Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:aeneas_jaissle:archive
kolab-z-push
kolab.php-correct-namespaces
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File kolab.php-correct-namespaces of Package kolab-z-push
<?php /* Kolab Z-Push Backend Copyright (C) 2009-2010 Free Software Foundation Europe e.V. The main author of the Kolab Z-Push Backend is Alain Abbas, with contributions by ....... This program is Free Software; you can redistribute it and/or modify it under the terms of version two of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. The licensor of the Kolab Z-Push Backend is the Free Software Foundation Europe (FSFE), Fiduciary Program, Linienstr. 141, 10115 Berlin, Germany, email:ftf@fsfeurope.org. */ //define('KOLABBACKEND_VERSION', 'SVN developpment 20100307'); define('KOLABBACKEND_VERSION', '0.7.5.20110619'); include_once('diffbackend.php'); // The is an improved version of mimeDecode from PEAR that correctly // handles charsets and charset conversion include_once('mimeDecode.php'); include_once('z_RTF.php'); include_once('z_RFC822.php'); include_once('Horde/Kolab/Kolab_Zpush/lib/kolabActivesyncData.php'); require_once 'Horde/Kolab/Format.php'; require_once 'Horde/String.php'; require_once 'Horde/NLS.php'; class BackendKolab extends BackendDiff { private $_server = ""; private $_username =""; private $_domain = ""; private $_password = ""; private $_cache; private $_deviceType; private $_deviceAgent; private $hasDefaultEventFolder =false; private $hasDefaultContactFolder= false; private $hasDefaultTaskFolder = false; private $foMode = false; private $_mbox; private $_KolabHomeServer; private $_cn; private $_email; private $sentFolder=""; private $namespaces = Array( 'personal' => "INBOX", 'users' => "user", 'shared' => "shared" ); /* Called to logon a user. These are the three authentication strings that you must * specify in ActiveSync on the PDA. Normally you would do some kind of password * check here. Alternatively, you could ignore the password here and have Apache * do authentication via mod_auth_* */ function Logon($username, $domain, $password) { if (defined("KOLAB_IMAP_NAMESPACES")) { $this->namespaces = KOLAB_IMAP_NAMESPACES; } $this->_wasteID = false; $this->_sentID = false; $this->_username = $username; $this->_domain = $domain; $this->_password = $password; //test for some device who sernd the username as domain/use if (!$this->getLdapAccount()) { return false; } $this->_server = "{" . $this->_KolabHomeServer . ":" . KOLAB_IMAP_PORT . "/imap" . KOLAB_IMAP_OPTIONS . "}"; $this->Log("Connecting to ". $this->_server); if (!function_exists("imap_open")) { debugLog("ERROR BackendIMAP : PHP-IMAP module not installed!!!!!"); $this->Log("module PHP imap not installed ") ; } // open the IMAP-mailbox $this->_mbox = @imap_open($this->_server , $username, $password, OP_HALFOPEN); $this->_mboxFolder = ""; if ($this->_mbox) { debugLog("KolabBackend Version : " . KOLABBACKEND_VERSION); debugLog("KolabActiveSyndData Version : " .KOLABACTIVESYNCDATA_VERSION); $this->Log("KolabBackend Version : " . KOLABBACKEND_VERSION); $this->Log("KolabActiveSyndData Version : " .KOLABACTIVESYNCDATA_VERSION); $this->Log("IMAP connection opened sucessfully user : " . $username ); // set serverdelimiter $this->_serverdelimiter = $this->getServerDelimiter(); return true; } else { $this->Log("IMAP can't connect: " . imap_last_error() . " user : " . $this->_user . " Mobile ID:" . $this->_devid); return false; } } /* Called before shutting down the request to close the IMAP connection */ function Logoff() { if ($this->_mbox) { // list all errors $errors = imap_errors(); if (is_array($errors)) { foreach ($errors as $e) debugLog("IMAP-errors: $e"); } @imap_close($this->_mbox); debugLog("IMAP connection closed"); $this->Log("IMAP connection closed"); unset($this->_cache); } } /* Called directly after the logon. This specifies the client's protocol version * and device id. The device ID can be used for various things, including saving * per-device state information. * The $user parameter here is normally equal to the $username parameter from the * Logon() call. In theory though, you could log on a 'foo', and then sync the emails * of user 'bar'. The $user here is the username specified in the request URL, while the * $username in the Logon() call is the username which was sent as a part of the HTTP * authentication. */ function Setup($user, $devid, $protocolversion) { $this->_user = $user; $this->_devid = $devid; $this->_protocolversion = $protocolversion; if ($devid == "") { //occurs in the OPTION Command return true; } $this->_deviceType=$_REQUEST["DeviceType"]; $this->_deviceAgent=$_SERVER["HTTP_USER_AGENT"]; $this->Log("Setup : " . $user. " Mobile ID :" . $devid. " Proto Version : " . $protocolversion ." DeviceType : ". $this->_deviceType . " DeviceAgent : ". $this->_deviceAgent); $this->CheckProcess($devid); $this->_cache=new userCache(); $this->CacheCheckVersion(); //read globalparam . $gp=$this->kolabReadGlobalParam(); $mode=KOLAB_MODE; if ($gp != false ) { //search if serial already in it; if ( $gp->getDeviceType($devid)) { if ( $gp->getDeviceMode($devid) != -1) { $mode=$gp->getDeviceMode($devid); } //register the folders if ( defined('KOLAB_ALWAYS_AUTOREGISTER') && defined('KOLAB_AUTOREGISTER') ) { $folders=split(":",KOLAB_AUTOREGISTER); foreach( $folders as $f) { $this->log("Autoregister folder : ".$f . " for " . $devid); $this->kolabRegisterFolder($devid,$f); } } } else { //register the folders if (defined('KOLAB_AUTOREGISTER') ) { $folders=split(":",KOLAB_AUTOREGISTER); foreach( $folders as $f) { $this->log("Autoregister folder : ".$f . " for " . $devid); $this->kolabRegisterFolder($devid,$f); } } //no present we must write it; $gp->setDevice($devid,$this->_deviceType) ; if ( ! $this->kolabWriteGlobalParam($gp)) { $this->Log("ERR cant write Globalparam"); } } } switch($mode) { case 0:$this->foMode = false; $this->Log("NOTICE : Forced to flatmode") ; break; case 1:$this->foMode = true; $this->Log("NOTICE : Forced to foldermode") ; break; case 2:$this->foMode = $this->findMode(); break; } return true; } /* Sends a message which is passed as rfc822. You basically can do two things * 1) Send the message to an SMTP server as-is * 2) Parse the message yourself, and send it some other way * It is up to you whether you want to put the message in the sent items folder. If you * want it in 'sent items', then the next sync on the 'sent items' folder should return * the new message as any other new message in a folder. */ private function findMode() { $type=explode(":",KOLAB_MOBILES_FOLDERMODE); if (in_array(strtolower($this->_deviceType),$type)) { $this->Log("NOTICE : findMode Foldermode") ; return 1; } $this->Log("NOTICE : findMode Flatmode") ; return 0; } function SendMail($rfc822, $forward = false, $reply = false, $parent = false) { debugLog("IMAP-SendMail: " . $rfc822 . "for: $forward reply: $reply parent: $parent" ); // $mobj = new Mail_mimeDecode($rfc822); $message = $mobj->decode(array('decode_headers' => false, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $rfc822, 'crlf' => "\n", 'charset' => 'utf-8')); $toaddr = $ccaddr = $bccaddr = ""; if(isset($message->headers["to"])) $toaddr = $this->parseAddr(Mail_RFC822::parseAddressList($message->headers["to"])); if(isset($message->headers["cc"])) $ccaddr = $this->parseAddr(Mail_RFC822::parseAddressList($message->headers["cc"])); if(isset($message->headers["bcc"])) $bccaddr = $this->parseAddr(Mail_RFC822::parseAddressList($message->headers["bcc"])); // save some headers when forwarding mails (content type & transfer-encoding) $headers = ""; $forward_h_ct = ""; $forward_h_cte = ""; $use_orgbody = false; // clean up the transmitted headers // remove default headers because we are using imap_mail $changedfrom = false; $returnPathSet = false; $body_base64 = false; $org_charset = ""; foreach($message->headers as $k => $v) { if ($k == "subject" || $k == "to" || $k == "cc" || $k == "bcc") continue; if ($k == "content-type") { // save the original content-type header for the body part when forwarding if ($forward) { $forward_h_ct = $v; continue; } // set charset always to utf-8 $org_charset = $v; $v = preg_replace("/charset=([A-Za-z0-9-\"']+)/", "charset=\"utf-8\"", $v); } if ($k == "content-transfer-encoding") { // if the content was base64 encoded, encode the body again when sending if (trim($v) == "base64") $body_base64 = true; // save the original encoding header for the body part when forwarding if ($forward) { $forward_h_cte = $v; continue; } } // if the message is a multipart message, then we should use the sent body if (!$forward && $k == "content-type" && preg_match("/multipart/i", $v)) { $use_orgbody = true; } // check if "from"-header is set if ($k == "from" ) { $changedfrom = true; if (! trim($v) ) { $v = $this->_email; } } // check if "Return-Path"-header is set if ($k == "return-path") { $returnPathSet = true; if (! trim($v) ) { $v = $this->_email; } } // all other headers stay if ($headers) $headers .= "\n"; $headers .= ucfirst($k) . ": ". $v; } // set "From" header if not set on the device if( !$changedfrom){ $v = $this->_email; if ($headers) $headers .= "\n"; $headers .= 'From: '.$v; } // set "Return-Path" header if not set on the device if(!$returnPathSet){ $v = $this->_email; if ($headers) $headers .= "\n"; $headers .= 'Return-Path: '.$v; } // if this is a multipart message with a boundary, we must use the original body if ($use_orgbody) { list(,$body) = $mobj->_splitBodyHeader($rfc822); } else $body = $this->getBody($message); // reply if (isset($reply) && isset($parent) && $reply && $parent) { $this->imap_reopenFolder($parent); // receive entire mail (header + body) to decode body correctly $origmail = @imap_fetchheader($this->_mbox, $reply, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $reply, FT_PEEK | FT_UID); $mobj2 = new Mail_mimeDecode($origmail); // receive only body $body .= $this->getBody($mobj2->decode(array('decode_headers' => false, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $origmail, 'crlf' => "\n", 'charset' => 'utf-8'))); // unset mimedecoder & origmail - free memory unset($mobj2); unset($origmail); } // encode the body to base64 if it was sent originally in base64 by the pda // the encoded body is included in the forward if ($body_base64) $body = base64_encode($body); // forward if (isset($forward) && isset($parent) && $forward && $parent) { $this->imap_reopenFolder($parent); // receive entire mail (header + body) $origmail = @imap_fetchheader($this->_mbox, $forward, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $forward, FT_PEEK | FT_UID); // build a new mime message, forward entire old mail as file list($aheader, $body) = $this->mail_attach("forwarded_message.eml",strlen($origmail),$origmail, $body, $forward_h_ct, $forward_h_cte); // unset origmail - free memory unset($origmail); // add boundary headers $headers .= "\n" . $aheader; } $headers .="\n"; $send = @imap_mail ( $toaddr, $message->headers["subject"], $body, $headers, $ccaddr, $bccaddr); $errors = imap_errors(); if (is_array($errors)) { foreach ($errors as $e) debugLog("IMAP-errors: $e"); } // email sent? if (!$send) { debugLog("The email could not be sent. Last-IMAP-error: ". imap_last_error()); } // add message to the sent folder // build complete headers $cheaders = "To: " . $toaddr. "\n"; $cheaders .= $headers; $asf = false; //try to see if there are a folder with the annotation $sent=$this->readDefaultSentItemFolder(); $body=str_replace("\n","\r\n",$body); $cheaders=str_replace(": ",": ",$cheaders); $cheaders=str_replace("\n","\r\n",$cheaders); if ($sent) { $asf = $this->addSentMessage($sent, $cheaders, $body); } else if ($this->sentFolder) { $asf = $this->addSentMessage($this->sentFolder, $cheaders, $body); debugLog("IMAP-SendMail: Outgoing mail saved in configured 'Sent' folder '".$this->sentFolder."': ". (($asf)?"success":"failed")); } // No Sent folder set, try defaults else { debugLog("IMAP-SendMail: No Sent mailbox set"); if ($this->namespaces['personal'] == "") { $folder_prefix = ""; } else { $folder_prefix = "" . $this->namespaces['personal'] . $this->_serverdelimiter; } if($this->addSentMessage($folder_prefix . "Sent", $cheaders, $body)) { debugLog("IMAP-SendMail: Outgoing mail saved in '" . $folder_prefix . "Sent'"); $asf = true; } else if ($this->addSentMessage($folder_prefix . "Sent Items", $cheaders, $body)) { debugLog("IMAP-SendMail: Outgoing mail saved in '" . $folder_prefix . "Sent Items'"); $asf = true; } } $errors = imap_errors(); if (is_array($errors)) { foreach ($errors as $e) debugLog("IMAP-errors: $e"); } // unset mimedecoder - free memory unset($mobj); return ($send && $asf); } /* Should return a wastebasket folder if there is one. This is used when deleting * items; if this function returns a valid folder ID, then all deletes are handled * as moves and are sent to your backend as a move. If it returns FALSE, then deletes * are always handled as real deletes and will be sent to your importer as a DELETE */ function GetWasteBasket() { return $this->_wasteID; } private function GetMessagesListByType($foldertype,$cutoffdate) { $lastfolder=""; $messages=array(); $list = @imap_getmailboxes($this->_mbox, $this->_server, "*"); if (is_array($list)) { $list = array_reverse($list); foreach ($list as $val) { //$folder=imap_utf7_decode(substr($val->name, strlen($this->_server))); $folder=substr($val->name, strlen($this->_server)); //$this->saveFolderAnnotation($folder); $ft=$this->kolabFolderType($folder); if ($ft != $foldertype) { continue; } $isUser=false; $isShared=false; if (substr($folder,0,strlen($this->namespaces['users'])) == $this->namespaces['users']) { $isUser=true; } elseif (substr($folder,0,strlen($this->namespaces['shared'])) == $this->namespaces['shared']) { $isShared=true; } $fa=$this->kolabReadFolderParam($folder); // here we must push the object into the cache so we don't // have to read it again at each message (for the alarms) $this->CacheWriteFolderParam($folder,$fa); $fa->setFolder($folder); if ( !$fa->isForSync($this->_devid) ) { //not set to sync continue; } if ( $this->CacheGetDefaultFolder($foldertype) == false) { //no default if ( !(substr($folder,0,strlen($this->namespaces['users'])) == $this->namespaces['users']) && !(substr($folder,0,strlen($this->namespaces['shared'])) == $this->namespaces['shared']) && (substr($folder,0,strlen($this->namespaces['personal'])) == $this->namespaces['personal']) ) { if (!$this->namespaces['personal'] == "" ) { $n = array_pop(explode($this->_serverdelimiter,$folder)); } else { $n = $folder; } $result = false; switch($foldertype) { case 1: $result = $this->isDefaultFolder($n,KOLAB_DEFAULTFOLDER_CONTACT); break; case 2: $result = $this->isDefaultFolder($n,KOLAB_DEFAULTFOLDER_DIARY); break; case 3: $result = $this->isDefaultFolder($n,KOLAB_DEFAULTFOLDER_TASK); break; } if ( $result == true) { $this->forceDefaultFolder($foldertype,$folder); } else { $lastfolder = $folder; } } } $this->imap_reopenFolder($folder); /*trying optimizing the reads*/ if ($this->isFolderModified($folder) == false ) { //$this->Log("NOTICE : folder not modified $folder"); $message_folder=$this->CacheReadMessageList($folder); if (is_array($message_folder) && count($message_folder)> 0) { $messages=array_merge($messages,$message_folder); continue; } } $overviews = @imap_fetch_overview($this->_mbox, "1:*",FT_UID); if (!$overviews) { debugLog("IMAP-GetMessageList: $folder Failed to retrieve overview"); } else { $message_infolder=array(); foreach($overviews as $overview) { $date = ""; $vars = get_object_vars($overview); if (array_key_exists( "deleted", $vars) && $overview->deleted) continue; $message=$this->KolabStat($folder,$overview); if (! $message){continue;} //cutoffdate for appointment if ( $foldertype == 2) { //look for kolabuid //$this->Log("try cutoffdate for message id ".$message["id"]); $enddate= $this->CacheReadEndDate($folder,$message["id"]); if ($enddate != - 1 && $cutoffdate > $enddate) { //cuteoffdate //$this->Log("cuteoffDate :" . $message["id"] ); continue; } if ( substr($folder,0,strlen($this->namespaces['personal'])) != $this->namespaces['personal'] ) { if ($this->CacheReadSensitivity($message["id"])) { //check if private for namespace <> INBOX continue; } } } //check if key is duplicated if (isset($checkId[$message["id"]])) { //uid exist $this->Log("Key : " .$message["id"] ." duplicated folder :" . $folder ." Imap id : " . $checkId[$message["id"]]); debugLog("Key : " .$message["id"] ." duplicated folder :" . $folder ." Imap id : " . $checkId[$message["id"]]); //rewrite the index to have the good imapid $id=array_pop(explode($this->_serverdelimiter,$checkId[$message["id"]])); $this->CacheCreateIndex($folder,$message["id"],$id); continue; } else { $checkId[$message["id"]] = $message["mod"]; } //here check the cutdate for appointments debugLog("ListMessage : " . $message["id"] . "->" . $message["mod"] ) ; $messages[]=$message; $message_infolder[]=$message; } $this->CacheStoreMessageList($folder,$message_infolder); } } //check if we found a default folder for this type if ( $this->CacheGetDefaultFolder($foldertype) == false) { //no we pur the last folder found as default; $this->forceDefaultFolder($foldertype,$lastfolder); } unset($checkId); unset($overviews); return $messages; } } private function statImapFolder($folder) { $info=imap_status($this->_mbox, $this->_server .$folder, SA_ALL) ; return serialize($info); } /* Should return a list (array) of messages, each entry being an associative array * with the same entries as StatMessage(). This function should return stable information; ie * if nothing has changed, the items in the array must be exactly the same. The order of * the items within the array is not important though. * * The cutoffdate is a date in the past, representing the date since which items should be shown. * This cutoffdate is determined by the user's setting of getting 'Last 3 days' of e-mail, etc. If * you ignore the cutoffdate, the user will not be able to select their own cutoffdate, but all * will work OK apart from that. */ function GetMessageList($folderid, $cutoffdate) { $messages = array(); $checkId = array(); //time measure $mtime = microtime(); $mtime = explode(" ",$mtime); $mtime = $mtime[1] + $mtime[0]; $starttime = $mtime; $id=$folderid; $folderid=$this->cacheReadId2Folder($id); if ($folderid =="user") { return array(); } else if ($folderid == "calendar") { //flat mode //search all folders of type calendar $messages=$this->GetMessagesListByType(2,$cutoffdate); } else if ($folderid == "contacts") { $messages=$this->GetMessagesListByType(1,$cutoffdate); } else if ($folderid == "tasks") { $messages=$this->GetMessagesListByType(3,$cutoffdate); } else { $this->imap_reopenFolder($folderid, true); //check if the folder as moved by imap stat if ($this->isFolderModified($folderid) == false ) { $messages=$this->CacheReadMessageList($folderid); if (count($messages) > 0) { debuglog("NOTICE : folder not modified $folderid"); $mtime = microtime(); $mtime = explode(" ",$mtime); $mtime = $mtime[1] + $mtime[0]; $endtime = $mtime; $totaltime = ($endtime - $starttime); debugLog("MEM GetmessageList End:" . memory_get_usage()) ; $this->Log("GetMessageList not modified (IN CACHE)". $folderid . "count : ". count($messages) . " exectime : ".$totaltime." seconds"); return $messages; } } /// type of folder $folderType=$this->kolabFolderType($folderid); //if mail folder search for the cutoffdate $sequence="1:*"; if ( $folderType == 0) { //mail folder //search if cutoffdate if ($cutoffdate > 0) { $search = @imap_search($this->_mbox, "SINCE ". date("d-M-Y", $cutoffdate),SE_UID); if ($search !== false) { $sequence = implode(",", $search); } } } $overviews = @imap_fetch_overview($this->_mbox,$sequence,FT_UID); if (!$overviews) { debugLog("IMAP-GetMessageList: $folderid Failed to retrieve overview"); } else { foreach($overviews as $overview) { $date = ""; $vars = get_object_vars($overview); // cut of deleted messages if (array_key_exists( "deleted", $vars) && $overview->deleted) continue; $folderType=$this->kolabFolderType($folderid); if ( $folderType> 0) { //kolab contacts and appointment special index //mode is the imap uid because kolab delete the message and recreate a newone in case //of modification $message=$this->KolabStat($folderid,$overview); if (! $message){continue;} //cutoffdate for appointment if ( $folderType == 2) { //look for kolabuid //$this->Log("try cutoffdate for message id ".$message["id"]); $enddate= $this->CacheReadEndDate($folderid,$message["id"]); if ($enddate != - 1 && $cutoffdate > $enddate) { //cuteoffdate //$this->Log("cuteoffDate too old"); continue; } if ( substr($folderid,0,strlen($this->namespaces['personal'])) != $this->namespaces['personal']) { if ($this->CacheReadSensitivity($message["id"])) { //check if private for namespace <> INBOX continue; } } } //check if key is duplicated if (isset($checkId[$message["id"]])) { $this->Log("Key : " .$message["id"] ." duplicated folder :" . $folder ." Imap id : " . $checkId[$message["id"]]); debugLog("Key : " .$message["id"] ." duplicated folder :" . $folder ." Imap id : " . $checkId[$message["id"]]); //rewrite the index to have the good imapid $id=array_pop(explode($this->_serverdelimiter,$checkId[$message["id"]])); $this->CacheCreateIndex($folder,$message["id"],$id); continue; } else { $checkId[$message["id"]] = $message["mod"]; } //here check the cutdate for appointments debugLog("ListMessage : " . $message["id"] . "->" . $message["mod"] ) ; $messages[]=$message; } else { if (array_key_exists( "date", $vars)) { // message is out of range for cutoffdate, ignore it $date = $overview->date; } if (array_key_exists( "uid", $vars)) { $message = array(); $message["mod"] = $date; $message["id"] = $overview->uid; // 'seen' aka 'read' is the only flag we want to know about $message["flags"] = 0; if(array_key_exists( "seen", $vars) && $overview->seen) $message["flags"] = 1; array_push($messages, $message); } } } } //clean the index before leave $this->CacheIndexClean($messages) ; //$this->Log("Get Message List : " . count($messages)) ; } $this->CacheStoreMessageList($folderid,$messages); //end time mesure $mtime = microtime(); $mtime = explode(" ",$mtime); $mtime = $mtime[1] + $mtime[0]; $endtime = $mtime; $totaltime = ($endtime - $starttime); debugLog("MEM GetmessageList End:" . memory_get_usage()) ; $this->Log("GetMessageList ". $folderid . "count : ". count($messages) . " exectime : ".$totaltime." seconds"); return $messages; } private function isFolderModified($folder) { $newstatus=@imap_status($this->_mbox,$this->_server. $folder,SA_ALL); $oldstatus=$this->CacheReadImapStatus($folder); if ($oldstatus == false) { $this->CacheStoreImapStatus($folder,$newstatus); return true; } //found the old status; //we compare if ( $oldstatus->uidnext == $newstatus->uidnext && $oldstatus->messages == $newstatus->messages && $oldstatus->unseen == $newstatus->unseen ) { //the folder has not been modified $this->Log("$folder not modified"); return False; } $this->CacheStoreImapStatus($folder,$newstatus); return true; } /* This function is analogous to GetMessageList. * */ function GetFolderList() { //Time measure $mtime = microtime(); $mtime = explode(" ",$mtime); $mtime = $mtime[1] + $mtime[0]; $starttime = $mtime; if ( $this->foMode == true) { $list= $this->GetFolderListFoMode(); } else { $list= $this->GetFolderListFlMode(); } //end time mesure $mtime = microtime(); $mtime = explode(" ",$mtime); $mtime = $mtime[1] + $mtime[0]; $endtime = $mtime; $totaltime = ($endtime - $starttime); $this->Log("GetFolderMode exectime : ".$totaltime." seconds"); return $list; } private function GetFolderListFlMode() { $folders = array(); $list = @imap_getmailboxes($this->_mbox, $this->_server, "*"); //add the virtual folders for contacts calendars and tasks $virtual=array("calendar","contacts","tasks","user","shared"); //$virtual=array("VIRTUAL/calendar","VIRTUAL/contacts"); //$box=array(); /* $cacheFid=$this->cacheReadFolderId("VIRTUAL"); $box["id"]=$cacheFid; $box["mod"] =$cacheFid; $box["flags"]=0; $box["parent"]="0" ; $folders[]=$box; */ foreach ($virtual as $v) { //$name=split($this->_serverdelimiter,$v); $name=$v; $box=array(); $box["id"]=$this->cacheReadFolderId($v); $box["mod"] =$name; $box["flags"]=0; $box["parent"]="0"; $folders[]=$box; } if (is_array($list)) { $list = array_reverse($list); foreach ($list as $val) { $box = array(); // cut off serverstring $box["flags"]=0; //$box["id"] = imap_utf7_decode(substr($val->name, strlen($this->_server))); $folderName=substr($val->name, strlen($this->_server)); $cacheFid=$this->cacheReadFolderId($folderName); $box["id"] =$cacheFid; //rerid the annotations $this->saveFolderAnnotation($folderName); $foldertype=$this->readFolderAnnotation($folderName); //if folder type > 0 escape if ( substr($foldertype,0,5) == "event") { continue; } if ( substr($foldertype,0,7) == "contact") { continue; } if ( substr($foldertype,0,4) == "task") { continue; } //other folders (mails) //$box["id"] = imap_utf7_encode( $box["id"]); $fhir = explode($this->_serverdelimiter, $folderName); if (count($fhir) > 1) { $box["mod"] = imap_utf7_encode(array_pop($fhir)); // mod is last part of path $box["parent"] = $this->cacheReadFolderId(implode($this->_serverdelimiter, $fhir)); // parent is all previous parts of path } else { $box["mod"] = imap_utf7_encode($box["id"]); $box["parent"] = "0"; } $folders[]=$box; } } else { debugLog("GetFolderList: imap_list failed: " . imap_last_error()); } return $folders; } private function GetFolderListFoMode() { // $folders = array(); $list = @imap_getmailboxes($this->_mbox, $this->_server, "*"); //here we can check if we must reparse or not $this->hasDefaultEventFolder=false; $this->hasDefaultContactFolder=false; $this->hasDefaultTaskFolder=false; if (is_array($list)) { //create the // reverse list to obtain folders in right order $list = array_reverse($list); foreach ($list as $val) { $box = array(); // cut off serverstring $box["flags"]=0; $folderName=substr($val->name, strlen($this->_server)); $cacheFid=$this->cacheReadFolderId($folderName); $box["id"]= $cacheFid; //determine the type en default folder $isUser=false; $isShared=false; $isInbox=false; //rerid the annotations $this->saveFolderAnnotation($folderName); $foldertype=$this->readFolderAnnotation($folderName); $defaultfolder = false; //defaultfolder ? if ( $foldertype == "event.default") { $this->hasDefaultEventFolder=true; $defaultfolder = true; } if ( $foldertype == "contact.default") { $this->hasDefaultContactFolder=true; $defaultfolder = true; } if ( $foldertype == "task.default") { $this->hasDefaultTaskFolder=true; $defaultfolder = true; } // namespace for the the folder; if (substr( $folderName,0,strlen($this->namespaces['shared'])) == $this->namespaces['shared']) { //this is a shared folder $isShared = true; } elseif (substr( $folderName,0,strlen($this->namespaces['users'])) == $this->namespaces['users']) { //this is a User shared folder $isUser = true; } else { // It must be a personal folder $isInbox = true; } //selection of the folder depending to the setup if (! $defaultfolder) { //test annotation $fa=$this->kolabReadFolderParam($folderName); //for later use (in getMessage) $this->CacheWriteFolderParam($folderName,$fa); $fa->setfolder($folderName); if ( ! $fa->isForSync($this->_devid)) { //not set to sync continue; } } //$this->Log("NOTICE SyncFolderList Add folder ".$box["id"]); //$box["id"] = imap_utf7_encode( $box["id"]); if ($isShared) { $fhir = explode(".",$folderName); $box["mod"] = imap_utf7_encode($fhir[1]); $box["parent"] = "0"; } elseif ($isUser) { $box["mod"] = imap_utf7_encode(array_pop($fhir)); $box["parent"] = "0"; } else { // explode hierarchies $fhir = explode($this->_serverdelimiter, $folderName); $t=count($fhir); if (count($fhir) > 1) { $box["mod"] = imap_utf7_encode(array_pop($fhir)); // mod is last part of path $box["parent"] = $this->cacheReadFolderId(implode($this->_serverdelimiter, $fhir)); // parent is all previous parts of path } else { $box["mod"] = imap_utf7_encode($folderName); $box["parent"] = "0"; } } $folders[]=$box; } } else { debugLog("GetFolderList: imap_list failed: " . imap_last_error()); } return $folders; } /* GetFolder should return an actual SyncFolder object with all the properties set. Folders * are pretty simple really, having only a type, a name, a parent and a server ID. */ function GetFolder($id) { $folder = new SyncFolder(); $folder->serverid = $id; //retrieve real name $folderName=$this->cacheReadId2Folder($id); // explode hierarchy $fhir = explode($this->_serverdelimiter, $folderName); if ( substr($folderName,0,7) == "shared.") { $parent="0"; } else { $ftmp= $fhir; array_pop($ftmp); debugLog("retreive Parent for ". $folderName . ' '. implode($this->_serverdelimiter, $ftmp) ); $parent=$this->cacheReadFolderId(implode($this->_serverdelimiter, $ftmp)); } debugLog("Parent id is " . $parent ." for ". $folderName); //get annotation type // compare on lowercase strings $lfolderName = strtolower($folderName); $fimap=$folderName; if ( $this->namespaces['personal'] == "" ) { $folder_prefix = ""; } else { $folder_prefix = $this->namespaces['personal'] . $this->_serverdelimiter; } if($lfolderName == "inbox") { $folder->parentid = "0"; // Root $folder->displayname = "Inbox"; $folder->type = SYNC_FOLDER_TYPE_INBOX; } else if($lfolderName == strtolower($this->namespaces['shared'])) { $folder->parentid = "0"; // Root $folder->displayname = "Shared"; $folder->type = SYNC_FOLDER_TYPE_OTHER; } else if($lfolderName == strtolower($this->namespaces['users'])) { $folder->parentid = "0"; // Root $folder->displayname = "User"; $folder->type = SYNC_FOLDER_TYPE_OTHER; } else if($lfolderName == $folder_prefix . "drafts") { $folder->parentid =$this->cacheReadFolderId($fhir[0]); $folder->displayname = "Drafts"; $folder->type = SYNC_FOLDER_TYPE_DRAFTS; } else if($lfolderName == $folder_prefix . "trash") { $folder->parentid = $this->cacheReadFolderId($fhir[0]); $folder->displayname = "Trash"; $folder->type = SYNC_FOLDER_TYPE_WASTEBASKET; $this->_wasteID = $id; } else if($lfolderName == $folder_prefix . "sent") { $folder->parentid = $this->cacheReadFolderId($fhir[0]); $folder->displayname = "Sent"; $this->sentFolder=$id; $folder->type = SYNC_FOLDER_TYPE_SENTMAIL; $this->_sentID = $id; } // define the rest as other-folders //check if flatmode else if ( $this->foMode == False && $folderName == "calendar") { $folder->parentid = "0"; $folder->displayname = "calendar"; $folder->type = SYNC_FOLDER_TYPE_APPOINTMENT; $this->_sentID = $id; } else if ( $this->foMode == False && $folderName == "contacts") { $folder->parentid = "0"; $folder->displayname = "contacts"; $folder->type = SYNC_FOLDER_TYPE_CONTACT; $this->_sentID = $id; } else if ( $this->foMode == False && $folderName == "tasks") { $folder->parentid = "0"; $folder->displayname = "tasks"; $folder->type = SYNC_FOLDER_TYPE_TASK; $this->_sentID = $id; } else if ( $this->kolabfolderType($folderName) == 1) { //contact kolab $folder->parentid = $parent; $folder->displayname = $this->folderDisplayName($folderName); $folder->type = $this->ActiveSyncFolderSyncType($folderName); $this->_sentID = $id; } else if ($this->kolabfolderType($folderName) == 2) { // shared folder in UPPER , $folder->parentid = $parent; $folder->displayname = $this->folderDisplayName($folderName); $folder->type = $this->ActiveSyncFolderSyncType($folderName); $this->_sentID = $id; } else if ($this->kolabfolderType($folderName) == 3) { $folder->parentid = $parent; $folder->displayname = $this->folderDisplayName($folderName); $folder->type = $this->ActiveSyncFolderSyncType($folderName); $this->_sentID = $id; } else { if (count($fhir) > 1) { $folder->displayname = windows1252_to_utf8(imap_utf7_decode(array_pop($fhir))); $folder->parentid = $this->cacheReadFolderId(implode($this->_serverdelimiter, $fhir)); } else { $folder->displayname = windows1252_to_utf8(imap_utf7_decode($folderName)); $folder->parentid = "0"; } $folder->type = SYNC_FOLDER_TYPE_OTHER; } //advanced debugging debugLog("IMAP-GetFolder(id: '$id') -> " . print_r($folder, 1)); return $folder; } /* Return folder stats. This means you must return an associative array with the * following properties: * "id" => The server ID that will be used to identify the folder. It must be unique, and not too long * How long exactly is not known, but try keeping it under 20 chars or so. It must be a string. * "parent" => The server ID of the parent of the folder. Same restrictions as 'id' apply. * "mod" => This is the modification signature. It is any arbitrary string which is constant as long as * the folder has not changed. In practice this means that 'mod' can be equal to the folder name * as this is the only thing that ever changes in folders. (the type is normally constant) */ private function folderDisplayName($folder) { if ( substr($folder,0,strlen($this->namespaces['shared'])) == $this->namespaces['shared'] ) { // shared folder in UPPER $s = explode($this->_serverdelimiter,$folder) ; return strtoupper(windows1252_to_utf8(imap_utf7_decode($s[1]))); } elseif ( substr($folder,0,strlen($this->namespaces['users'])) == $this->namespaces['users'] ) { $type=$this->readFolderAnnotation($folder); $t=explode(".",$type); //find the user $fname=array_pop($f); $r=windows1252_to_utf8(imap_utf7_decode($fname."(".$f[1].")")); return windows1252_to_utf8($r); } else { $type=$this->readFolderAnnotation($folder); if ($type =="contact.default" || $type =="event.default" || $type =="task.default") { //default folder all min lowaercase $r=windows1252_to_utf8(imap_utf7_decode($f[1])); return strtolower(windows1252_to_utf8(imap_utf7_decode(array_pop($f)))); } else { //others AA problem when we have sub sub folder //must keep the last one return ucfirst(windows1252_to_utf8(imap_utf7_decode(array_pop($f)))); } } } function StatFolder($id) { $folder = $this->GetFolder($id); $stat = array(); $stat["id"] = $id; $stat["parent"] = $folder->parentid; $stat["mod"] = $folder->displayname; return $stat; } /* Creates or modifies a folder * "folderid" => id of the parent folder * "oldid" => if empty -> new folder created, else folder is to be renamed * "displayname" => new folder name (to be created, or to be renamed to) * "type" => folder type, ignored in IMAP * */ function ChangeFolder($folderid, $oldid, $displayname, $type){ debugLog("ChangeFolder: (parent: '$folderid' oldid: '$oldid' displayname: '$displayname' type: '$type')"); // go to parent mailbox $this->imap_reopenFolder($folderid); // build name for new mailbox $newname = $this->_server . str_replace(".", $this->_serverdelimiter, $folderid) . $this->_serverdelimiter . $displayname; $csts = false; // if $id is set => rename mailbox, otherwise create if ($oldid) { // rename doesn't work properly with IMAP // the activesync client doesn't support a 'changing ID' //$csts = imap_renamemailbox($this->_mbox, $this->_server . imap_utf7_encode(str_replace(".", $this->_serverdelimiter, $oldid)), $newname); } else { $csts = @imap_createmailbox($this->_mbox, $newname); } if ($csts) { return $this->StatFolder($folderid . "." . $displayname); } else return false; } /* Should return attachment data for the specified attachment. The passed attachment identifier is * the exact string that is returned in the 'AttName' property of an SyncAttachment. So, you should * encode any information you need to find the attachment in that 'attname' property. */ function GetAttachmentData($attname) { debugLog("getAttachmentDate: (attname: '$attname')"); list($folderid, $id, $part) = explode(":", $attname); $this->imap_reopenFolder($folderid); $mail = @imap_fetchheader($this->_mbox, $id, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $id, FT_PEEK | FT_UID); $mobj = new Mail_mimeDecode($mail); $message = $mobj->decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $mail, 'crlf' => "\n", 'charset' => 'utf-8')); if (isset($message->parts[$part]->body)) print $message->parts[$part]->body; // unset mimedecoder & mail unset($mobj); unset($mail); return true; } /* StatMessage should return message stats, analogous to the folder stats (StatFolder). Entries are: * 'id' => Server unique identifier for the message. Again, try to keep this short (under 20 chars) * 'flags' => simply '0' for unread, '1' for read * 'mod' => modification signature. As soon as this signature changes, the item is assumed to be completely * changed, and will be sent to the PDA as a whole. Normally you can use something like the modification * time for this field, which will change as soon as the contents have changed. */ function StatMessage($folderid, $id) { $saveId=$folderid; $folderid=$this->cacheReadId2Folder($folderid); debugLog("IMAP-StatMessage: (fid: '$folderid' id: '$id' )"); //search the imap id if ( $this->kolabFolderType($folderid)) { //in case of synchor app or contacts we work with kolab_uid if ($folderid == "calendar" || $folderid == "contacts" || $folderid == "calendar" || $folderid == "tasks" ) { //must find the right folder $folderid=$this->CacheIndexUid2FolderUid($id); debugLog("StatMessage Flmode: $id - > $folderid"); //$this->Log("NOTICE StatMessage Flmode: $id - > $folderid"); } $imap_id=$this->CacheIndexUid2Id($folderid,$id); if ($imap_id) { $entry=array(); $entry["mod"]=$folderid .$this->_serverdelimiter.$imap_id; $entry["id"]=$id; $entry["flags"] = 0; return $entry; } else { //kolab_uid -> imap_id must be exist debugLog("StatMessage: Failed to retrieve imap_id from index: ". $id); return false; } } //normal case for imap mails synchro $this->imap_reopenFolder($folderid); $overview = @imap_fetch_overview( $this->_mbox , $id , FT_UID); if (!$overview) { debugLog("IMAP-StatMessage: Failed to retrieve overview: ". imap_last_error()); return false; } else { // check if variables for this overview object are available $vars = get_object_vars($overview[0]); // without uid it's not a valid message if (! array_key_exists( "uid", $vars)) return false; $entry = array(); $entry["mod"] = (array_key_exists( "date", $vars)) ? $overview[0]->date : ""; $entry["id"] = $overview[0]->uid; // 'seen' aka 'read' is the only flag we want to know about $entry["flags"] = 0; if(array_key_exists( "seen", $vars) && $overview[0]->seen) $entry["flags"] = 1; } //advanced debugging //debugLog("IMAP-StatMessage-parsed: ". print_r($entry,1)); return $entry; } /* GetMessage should return the actual SyncXXX object type. You may or may not use the '$folderid' parent folder * identifier here. * Note that mixing item types is illegal and will be blocked by the engine; ie returning an Email object in a * Tasks folder will not do anything. The SyncXXX objects should be filled with as much information as possible, * but at least the subject, body, to, from, etc. */ function GetMessage($folderid, $id, $truncsize,$mimesupport = 0) { debugLog("KOLAB-GetMessage: (fid: '$folderid' id: '$id' truncsize: $truncsize)"); // Get flags, etc $stat = $this->StatMessage($folderid, $id); $saveId=$folderid; $folderid=$this->cacheReadId2Folder($folderid); if ($stat) { if ( $this->kolabFolderType($folderid)) { //get the imap_id $imap_id=array_pop(explode($this->_serverdelimiter,$stat['mod'])); //$imap_id=$stat['mod']; if ($folderid == "contacts" || $folderid == "calendar" || $folderid == "tasks") { $folderid=$this->CacheIndexUid2FolderUid($id); debugLog("GetMessage Flmode: $id - > $folderid"); //$this->Log("NOTICE GetMessage Flmode: $id - > $folderid"); } } else { $imap_id=$id; } $this->imap_reopenFolder($folderid); $mail = @imap_fetchheader($this->_mbox, $imap_id, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $imap_id, FT_PEEK | FT_UID); $mobj = new Mail_mimeDecode($mail); $message = $mobj->decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $mail, 'crlf' => "\n", 'charset' => 'utf-8')); if ($this->kolabFolderType($folderid) == 1) { $output=$this->KolabReadContact($message,0); $this->Log("Changed on Server C: $folderid /" .$id. "imap id : " .$imap_id ); $this->Log(" : " . u2w($output->fileas)); $this->CacheCreateIndex($folderid,$id,$imap_id); return $output; } elseif ($this->kolabFolderType($folderid) == 2 ) { //bug #9 we must test if we want alarms or not // for the moment disable it if namespace <> INBOX $fa=$this->CacheReadFolderParam($folderid); $fa->setFolder($folderid) ; if ( $fa->showAlarm($this->_devid)) { $output=$this->KolabReadEvent($message,$id,false) ; //alarm must be shown } else { $output=$this->KolabReadEvent($message,$id,true) ; } $this->Log("Changed on Server A: $folderid/" .$id ); $this->Log(" : " . u2w($output->subject)); $this->CacheCreateIndex($folderid,$id,$imap_id) ; $this->CacheWriteSensitivity($id,$output->sensitivity); return $output; } elseif ($this->kolabFolderType($folderid) == 3 ) { $output=$this->KolabReadTask($message,$id) ; $this->Log("Changed on Server T: $folderid /" .$id ); $this->Log(" : " . u2w($output->subject)); $this->CacheCreateIndex($folderid,$id,$imap_id) ; //rewrite completion $this->CacheWriteTaskCompleted($id,$output->completed); $this->CacheWriteSensitivity($id,$output->sensitivity); return $output; } else { $output = new SyncMail(); // decode body to truncate it $body = utf8_to_windows1252($this->getBody($message)); //$truncsize=2048; if(strlen($body) > $truncsize) { $body = substr($body, 0, $truncsize); $output->bodytruncated = 1; } else { $body = $body; $output->bodytruncated = 0; } $body = str_replace("\n","\r\n", windows1252_to_utf8(str_replace("\r","",$body))); $output->bodysize = strlen($body); $output->body = $body; $output->datereceived = isset($message->headers["date"]) ? strtotime($message->headers["date"]) : null; $output->displayto = isset($message->headers["to"]) ? $message->headers["to"] : null; $output->importance = isset($message->headers["x-priority"]) ? preg_replace("/\D+/", "", $message->headers["x-priority"]) : null; $output->messageclass = "IPM.Note"; $output->subject = isset($message->headers["subject"]) ? $message->headers["subject"] : ""; $output->read = $stat["flags"]; $output->to = trim(isset($message->headers["to"]) ? $message->headers["to"] : null); $output->cc = trim(isset($message->headers["cc"]) ? $message->headers["cc"] : null); $output->from = trim(isset($message->headers["from"]) ? $message->headers["from"] : null); $output->reply_to = trim(isset($message->headers["reply-to"]) ? $message->headers["reply-to"] : null); // Attachments are only searched in the top-level part $n = 0; if(isset($message->parts)) { foreach($message->parts as $part) { if(isset($part->disposition) && ($part->disposition == "attachment" || $part->disposition == "inline")) { $attachment = new SyncAttachment(); if (isset($part->body)) $attachment->attsize = strlen($part->body); if(isset($part->d_parameters['filename'])) $attname = $part->d_parameters['filename']; else if(isset($part->ctype_parameters['name'])) $attname = $part->ctype_parameters['name']; else if(isset($part->headers['content-description'])) $attname = $part->headers['content-description']; else $attname = "unknown attachment"; $attachment->displayname = $attname; $attachment->attname = $folderid . ":" . $id . ":" . $n; $attachment->attmethod = 1; $attachment->attoid = isset($part->headers['content-id']) ? $part->headers['content-id'] : ""; array_push($output->attachments, $attachment); } $n++; } } // unset mimedecoder & mail unset($mobj); unset($mail); return $output; } } return false; } /* This function is called when the user has requested to delete (really delete) a message. Usually * this means just unlinking the file its in or somesuch. After this call has succeeded, a call to * GetMessageList() should no longer list the message. If it does, the message will be re-sent to the PDA * as it will be seen as a 'new' item. This means that if you don't implement this function, you will * be able to delete messages on the PDA, but as soon as you sync, you'll get the item back */ function DeleteMessage($folderid, $id) { debugLog("KOLAB-DeleteMessage: (fid: '$folderid' id: '$id' )"); $saveId=$folderid; $folderid=$this->cacheReadId2Folder($folderid); if ( $this->kolabFolderType($folderid) >0 ) { if ($folderid == "contacts" || $folderid == "calendar" || $folderid == "tasks") { $folderid=$this->CacheIndexUid2FolderUid($id); debugLog("DeleteMessage Flmode: $id - > $folderid"); $this->Log("NOTICE DeleteMessage Flmode: $id - > $folderid"); } //kolab_uid -> imap_id $imap_id=$this->CacheIndexUid2Id($folderid,$id); } else { $imap_id=$id; } $this->imap_reopenFolder($folderid); $s1 = @imap_delete ($this->_mbox, $imap_id, FT_UID); $s11 = @imap_setflag_full($this->_mbox, $imap_id, "\\Deleted", FT_UID); $s2 = @imap_expunge($this->_mbox); $this->CacheIndexDeletebyId($folderid,$id); debugLog("IMAP-DeleteMessage: s-delete: $s1 s-expunge: $s2 setflag: $s11"); return ($s1 && $s2 && $s11); } /* This should change the 'read' flag of a message on disk. The $flags r * parameter can only be '1' (read) or '0' (unread). After a call to * SetReadFlag(), GetMessageList() should return the message with the * new 'flags' but should not modify the 'mod' parameter. If you do * change 'mod', simply setting the message to 'read' on the PDA will trigger * a full resync of the item from the server */ function SetReadFlag($folderid, $id, $flags) { debugLog("IMAP-SetReadFlag: (fid: '$folderid' id: '$id' flags: '$flags' )"); $saveId=$folderid; $folderid=$this->cacheReadId2Folder($folderid); $this->imap_reopenFolder($folderid); if ($flags == 0) { // set as "Unseen" (unread) $status = @imap_clearflag_full ( $this->_mbox, $id, "\\Seen", ST_UID); } else { // set as "Seen" (read) $status = @imap_setflag_full($this->_mbox, $id, "\\Seen",ST_UID); } debugLog("IMAP-SetReadFlag -> set as " . (($flags) ? "read" : "unread") . "-->". $status); return $status; } /* This function is called when a message has been changed on the PDA. You should parse the new * message here and save the changes to disk. The return value must be whatever would be returned * from StatMessage() after the message has been saved. This means that both the 'flags' and the 'mod' * properties of the StatMessage() item may change via ChangeMessage(). * Note that this function will never be called on E-mail items as you can't change e-mail items, you * can only set them as 'read'. */ function ChangeMessage($folderid, $id, $message) { $modify=false; $this->Log("PDA Folder : " . $folderid . " object uid : " . $id); $saveId=$folderid; $folderid=$this->cacheReadId2Folder($folderid); if (substr($folderid,0,6) == "shared" && KOLAB_SHAREDFOLDERS_RO ==1 ) { //shared folders are protected $this->Log("PDA Folder : READ ONLY Cancel " . $folderid . " object uid : " . $id); return false; } if ( $id != FALSE ) { //finding the kolab_uid for this id if ( $this->kolabFolderType($folderid)> 0) { if ($folderid == "contacts" || $folderid == "calendar" || $folderid == "tasks") { $folderid=$this->CacheIndexUid2FolderUid($id); debugLog("ChangeMessage Flmode: $id - > $folderid"); $this->Log("NOTICE ChangeMessage Flmode: $id - > $folderid"); } //message exist on the server delete it $imap_id=$this->CacheIndexUid2Id($folderid,$id); $this->imap_reopenFolder($folderid); $s1 = @imap_delete ($this->_mbox, $imap_id, FT_UID); $s11 = @imap_setflag_full($this->_mbox, $imap_id, "\\Deleted", FT_UID); $s2 = @imap_expunge($this->_mbox); $this->Log("Change delete imap message : " . $folderid . " " . $imap_id) ; $kolab_uid=$id; $modify=true; } else { //delete du mail $this->DeleteMessage($folderid,$id); } } // mail is an Array [uid,date,RFC822Message] * if ($folderid == "calendar") { $folderid=$this->CacheGetDefaultFolder("event"); } if ($folderid == "contacts") { $folderid=$this->CacheGetDefaultFolder("contact"); } if ($folderid == "tasks") { $folderid=$this->CacheGetDefaultFolder("task"); } if ( $this->kolabFolderType($folderid) == 1) { $mail=$this->KolabWriteContact($message,$kolab_uid); } elseif ($this->kolabFolderType($folderid) == 2) { $mail=$this->KolabWriteEvent($message,$kolab_uid); } elseif ($this->kolabFolderType($folderid) == 3) { $mail=$this->KolabWriteTask($message,$kolab_uid); } // now we can insert it again $this->imap_reopenFolder($folderid); $info=imap_status($this->_mbox, $this->_server . $folderid, SA_ALL) ; $r=@imap_append($this->_mbox,$this->_server . $folderid,$mail[2] ,"\\Seen"); $id=$info->uidnext; if ( $r == TRUE) { $this->Log("create message : " . $folderid . " " . $id) ; $this->CacheCreateIndex($folderid,$mail[0],$id); if ( $this->kolabFolderType($folderid) ==2) { //cache the end date $this->CacheWriteEndDate($folderid,$message) ; } if ($this->kolabFolderType($folderid) == 3) { $this->CacheWriteTaskCompleted($id,$message->completed); $this->CacheWriteSensitivity($id,$message->sensitivity); } $entry["mod"] = $folderid .$this->_serverdelimiter.$id; $entry["id"]=strtoupper($mail[0]); $entry["flags"]=0; return $entry; } $this->Log("IMAP can't add mail : " . imap_last_error()); return false; } /* This function is called when the user moves an item on the PDA. You should do whatever is needed * to move the message on disk. After this call, StatMessage() and GetMessageList() should show the items * to have a new parent. This means that it will disappear from GetMessageList() will not return the item * at all on the source folder, and the destination folder will show the new message * */ function MoveMessage($folderid, $id, $newfolderid) { debugLog("IMAP-MoveMessage: (sfid: '$folderid' id: '$id' dfid: '$newfolderid' )"); $saveId=$folderid; $folderid=$this->cacheReadId2Folder($folderid); $this->imap_reopenFolder($folderid); // read message flags $overview = @imap_fetch_overview ( $this->_mbox , $id, FT_UID); if (!$overview) { debugLog("IMAP-MoveMessage: Failed to retrieve overview"); return false; } else { // move message $s1 = imap_mail_move($this->_mbox, $id, $newfolderid, FT_UID); // delete message in from-folder $s2 = imap_expunge($this->_mbox); // open new folder $this->imap_reopenFolder($newfolderid); // remove all flags $s3 = @imap_clearflag_full ($this->_mbox, $id, "\\Seen \\Answered \\Flagged \\Deleted \\Draft", FT_UID); $newflags = ""; if ($overview[0]->seen) $newflags .= "\\Seen"; if ($overview[0]->flagged) $newflags .= " \\Flagged"; if ($overview[0]->answered) $newflags .= " \\Answered"; $s4 = @imap_setflag_full ($this->_mbox, $id, $newflags, FT_UID); debugLog("MoveMessage: (" . $folderid . "->" . $newfolderid . ") s-move: $s1 s-expunge: $s2 unset-Flags: $s3 set-Flags: $s4"); return ($s1 && $s2 && $s3 && $s4); } } // ---------------------------------------- // imap-specific internals function getSearchResults($searchquery) { //chech if KOLAB_LDAP_SERVER is a URI or an IP $reg= "/ldap:\/\/(.+):(.+)/"; //check bad characters in the search query if (! preg_match("/^[A-Z,a-z,0-9]+$/",$searchquery)) { return false; } if (preg_match($reg,KOLAB_SERVER,$tab)) { $addrip=$tab[1]; $port=$tab[2]; } else { $addrip=KOLAB_SERVER; $port=389; } $conn=ldap_connect($addrip,$port) ; if ($conn == 0) { $this->Log("ERR LDAP GetSearch connexion to server : " . KOLAB_SERVER . " failed"); return false; } if (defined("LDAP_BIND_DN") && !empty(LDAP_BIND_DN)) { if (!ldap_bind($conn, LDAP_BIND_DN, LDAP_BIND_PW)) { $this->Log("ERR LDAP GetSearch Invalid bind credentials"); return false; } } else { if (!ldap_bind ($conn,"","")) { $this->Log("ERR LDAP GetSearch Invalid credentials: Anonymous bind failed.") ; return false; } } //recherche du DN a autentifier if ( ! $sr=ldap_search($conn,KOLAB_LDAP_BASE,"(|(cn=".$searchquery."*)(mail=".$searchquery."*))",array("cn","sn","mail","mobile","o","telephonenumber","givenname","sn","homephone"))) { $this->Log("Query filter ". $searchquery ." not found") ; return False; } $searchresult=ldap_get_entries($conn,$sr); // range for the search results, default symbian range end is 50, wm 99, // so we'll use that of nokia $rangestart = 0; $rangeend = 50; $items = array(); $querycnt = $searchresult['count']; //do not return more results as requested in range $querylimit = (($rangeend + 1) < $querycnt) ? ($rangeend + 1) : $querycnt; $items['range'] = $rangestart.'-'.($querycnt-1); $items['searchtotal'] = $querycnt; $rc = 0; $test=SYNC_GAL_DISPLAYNAME; for ($i = $rangestart; $i < $querylimit; $i++) { if ($searchresult[$i]['sn'][0] != null) { $items[$rc][SYNC_GAL_DISPLAYNAME]=$searchresult[$i]['cn'][0]; $items[$rc][SYNC_GAL_PHONE]=$searchresult[$i]['telephonenumber'][0]; $items[$rc][SYNC_GAL_TITLE]=$searchresult[$i]['title'][0]; $items[$rc][SYNC_GAL_COMPANY]=$searchresult[$i]['o'][0]; $items[$rc][SYNC_GAL_ALIAS]=$searchresult[$i]['uid'][0]; $items[$rc][SYNC_GAL_FIRSTNAME]=$searchresult[$i]['givenname'][0]; $items[$rc][SYNC_GAL_LASTNAME]=$searchresult[$i]['sn'][0]; $items[$rc][SYNC_GAL_HOMEPHONE]=$searchresult[$i]['homephone'][0]; $items[$rc][SYNC_GAL_MOBILEPHONE]=$searchresult[$i]['mobile'][0]; $items[$rc][SYNC_GAL_EMAILADDRESS]=$searchresult[$i]['mail'][0]; $rc++; } } return $items; } /* Parse the message and return only the plaintext body */ function getBody($message) { $body = ""; $htmlbody = ""; $this->getBodyRecursive($message, "plain", $body); if(!isset($body) || $body === "") { $this->getBodyRecursive($message, "html", $body); // remove css-style tags $body = preg_replace("/<style.*?<\/style>/is", "", $body); // remove all other html $body = strip_tags($body); } return $body; } // Get all parts in the message with specified type and concatenate them together, unless the // Content-Disposition is 'attachment', in which case the text is apparently an attachment function getBodyRecursive($message, $subtype, &$body) { if(!isset($message->ctype_primary)) return; if(strcasecmp($message->ctype_primary,"text")==0 && strcasecmp($message->ctype_secondary,$subtype)==0 && isset($message->body)) $body .= $message->body; if(strcasecmp($message->ctype_primary,"multipart")==0 && isset($message->parts) && is_array($message->parts)) { foreach($message->parts as $part) { if(!isset($part->disposition) || strcasecmp($part->disposition,"attachment")) { $this->getBodyRecursive($part, $subtype, $body); } } } } // save the serverdelimiter for later folder (un)parsing function getServerDelimiter() { $list = @imap_getmailboxes($this->_mbox, $this->_server, "*"); if (is_array($list)) { $val = $list[0]; return $val->delimiter; } return "."; // default "." } // speed things up // remember what folder is currently open and only change if necessary function imap_reopenFolder($folderid, $force = false) { // to see changes, the folder has to be reopened! if ($this->_mboxFolder != $folderid || $force) { $s = @imap_reopen($this->_mbox, $this->_server . $folderid); if (!$s) debugLog("failed to change folder: ". implode(", ", imap_errors())); $this->_mboxFolder = $folderid; } } // build a multipart email, embedding body and one file (for attachments) function mail_attach($filenm,$filesize,$file_cont,$body, $body_ct, $body_cte,$file_ct,$picture=null) { $boundary = strtoupper(md5(uniqid(time()))); if ( $file_ct == "") { $file_ct="text/plain" ; } $mail_header = "Content-Type: multipart/mixed; boundary=$boundary\r\n"; // build main body with the sumitted type & encoding from the pda $mail_body = "This is a multi-part message in MIME format\r\n\r\n"; $mail_body .= "--$boundary\r\n"; $mail_body .= "Content-Type:$body_ct\r\n"; if ($body_cte != "") { $mail_body .= "Content-Transfer-Encoding:$body_cte\r\n\r\n"; } $mail_body .= "$body\r\n\r\n"; $mail_body .= "--$boundary\r\n"; $mail_body .= "Content-Type: ".$file_ct."; name=\"$filenm\"\r\n"; $mail_body .= "Content-Transfer-Encoding: base64\r\n"; $mail_body .= "Content-Disposition: attachment; filename=\"$filenm\"\r\n"; $mail_body .= "Content-Description: $filenm\r\n\r\n"; $mail_body .= base64_encode($file_cont) . "\r\n\r\n"; if ( $picture) { //add picture $mail_body .= "--$boundary\r\n"; $mail_body .= "Content-Type: image/jpeg; name=\"photo.jpeg\"\r\n"; $mail_body .= "Content-Transfer-Encoding: base64\r\n"; $mail_body .= "Content-Disposition: attachment; filename=\"photo.jpeg\"\r\n\r\n"; $mail_body .=$picture . "\r\n\r\n"; } $mail_body .= "--$boundary--\r\n\r\n"; return array($mail_header, $mail_body); } // adds a message as seen to a specified folder (used for saving sent mails) function addSentMessage($folderid, $header, $body) { return @imap_append($this->_mbox,$this->_server . $folderid, $header . "\r\n" . $body ,"\\Seen"); } // parses address objects back to a simple "," separated string function parseAddr($ad) { $addr_string = ""; if (isset($ad) && is_array($ad)) { foreach($ad as $addr) { if ($addr_string) $addr_string .= ","; $addr_string .= $addr->mailbox . "@" . $addr->host; } } return $addr_string; } private function KolabReadContact($message,$with_uid) { $contact=NULL; $kolabXml=NULL; $images=array(); $n=0; if(isset($message->parts)) { $parts=$message->parts; foreach($parts as $part) { if(isset($part->disposition) && ($part->disposition == "attachment" || $part->disposition == "inline")) { $type=$part->headers; //kolab contact attachment ? $ctype=explode(";",$type["content-type"] ) ; $ctype[0]=trim($ctype[0]); if ($ctype[0] == "application/x-vnd.kolab.contact") { $kolabXml=$part->body; } if ($ctype[0] == "image/jpeg") { $name=$part->ctype_parameters["name"]; $images[$name]=$part->body; } $n++; } } if (! $kolabXml) { //nothing in the mail return ""; } //processing String::setDefaultCharset('utf-8'); $format = Horde_Kolab_Format::factory('XML', 'contact'); $kcontact=$format->load($kolabXml); unset($format); unset($factory); if ($kcontact instanceof PEAR_Error) { //parsing error debugLog("ERROR ".$kcontact->message); debugLog("Xml kolab : $body") ; $this->Log("ERROR ".$kcontact->message); $this->Log("XML : $body") ; unset($kcontact); return ""; } //mappage $contact=new SyncContact(); if ( $with_uid != 0) { $contact->uid= strtoupper($kcontact['uid']); } $contact->fileas= $this->fenc($kcontact['last-name'].", " . $kcontact['given-name']); $contact->firstname= $this->fenc($kcontact['given-name']) ; $contact->lastname= $this->fenc($kcontact['last-name']); $contact->middlename=$this->fenc($kcontact['middle-names']); $contact->webpage=$kcontact['web-page'] ; $contact->jobtitle=$this->fenc($kcontact["job-title"]) ; $contact->title=$this->fenc($kcontact["prefix"]) ; $contact->suffix=$this->fenc($kcontact['suffix']); $contact->companyname =$this->fenc($kcontact['organization']) ; $contact->email1address=$kcontact['emails']; if ( isset($kcontact["picture"])) { $contact->picture=base64_encode($images[$kcontact["picture"]]); $this->CacheWritePicture($kcontact['uid'],$contact->picture); } if (isset($kcontact["phone-business1"])) { if ( $this->checkPhoneNumber($kcontact["phone-business1"])) { $contact->businessphonenumber=$kcontact["phone-business1"] ; } else { $this->Log("ERR: ".$contact->fileas ." ---> " . $kcontact["phone-business1"] ); } } if (isset($kcontact["phone-business2"])) { if ( $this->checkPhoneNumber($kcontact["phone-business2"])) { $contact->business2phonenumber=$kcontact["phone-business1"] ; } else { $this->Log("ERR: ".$contact->fileas ." ---> " . $kcontact["phone-business2"] ); } } if (isset($kcontact["phone-home1"])) { if ( $this->checkPhoneNumber($kcontact["phone-home1"])) { $contact->homephonenumber=$kcontact["phone-home1"] ; } else { $this->Log("ERR: ".$contact->fileas ." ---> " . $kcontact["phone-home1"] ); } } if (isset($kcontact["phone-mobile"])) { if ( $this->checkPhoneNumber($kcontact["phone-mobile"])) { $contact->mobilephonenumber=$kcontact["phone-mobile"] ; } else { $this->Log("ERR: ".$contact->fileas ." ---> " . $kcontact["phone-mobile"] ); } } if (isset($kcontact["phone-businessfax"])) { if ( $this->checkPhoneNumber($kcontact["phone-businessfax"])) { $contact->businessfaxnumber=$kcontact["phone-businessfax"] ; } else { $this->Log("ERR: ".$contact->fileas ." ---> " . $kcontact["phone-businessfax"] ); } } $contact->otherstreet=$this->fenc($kcontact["addr-other-street"]); $contact->othercity=$this->fenc($kcontact["addr-other-locality"]); $contact->otherpostalcode=$kcontact["addr-other-postal-code"]; $contact->otherstate=$kcontact["addr-other-region"] ; $contact->othercountry=$this->fenc($kcontact["addr-other-country"]); $contact->businessstreet=$this->fenc($kcontact["addr-business-street"]); $contact->businesscity=$this->fenc($kcontact["addr-business-locality"]); $contact->businesspostalcode=$kcontact["addr-business-postal-code"]; $contact->businessstate=$kcontact["addr-business-region"] ; $contact->businesscountry=$this->fenc($kcontact["addr-business-country"]); $contact->homestreet=$this->fenc($kcontact["addr-home-street"]); $contact->homecity=$this->fenc($kcontact["addr-home-locality"]); $contact->homepostalcode=$kcontact["addr-home-postal-code"]; $contact->homestate=$kcontact["addr-home-region"] ; $contact->homecountry=$this->fenc($kcontact["addr-home-country"]); $contact->body=$this->fenc($kcontact['body'] ); $contact->spouse=$this->fenc($kcontact['spouse-name']); $contact->nickname=$this->fenc($kcontact['nick-name']); $contact->pagernumber=$this->fenc($kcontact['phone-pager']); $contact->assistantname=$this->fenc($kcontact['assistant']); $contact->department=$this->fenc($kcontact['department']); $contact->officelocation=$this->fenc($kcontact{'office-location'}); if (isset($kcontact['anniversary'])) { $contact->anniversary=$this->KolabDate2Unix($kcontact['anniversary']); } if (isset($kcontact['birthday'])) { $contact->birthday=$this->KolabDate2Unix($kcontact['birthday']); } if ($kcontact["children"]) { $children=array(); $children[]= $kcontact["children"]; $contact->children=$children; } if ($contact->fileas == false) { $contact->fileas =$this->fenc($kcontact["organization"]); } if ($contact->fileas == false) { $contact->fileas =$kcontact["phone-mobile"]; } if ($contact->fileas == false) { $contact->fileas =$kcontact["phone-business1"]; } if ($contact->fileas == false) { $this->Log("ERR: fileAs empty" ); } return $contact; } return "" ; } private function checkPhoneNumber($phone) { if (preg_match( '/^[0-9,\+,\*,\#,\(,\),\s,\.\-]+$/', $phone)) { return $phone; } return ""; } private function KolabWriteContact($message,$uid) { if ( $uid == '') { $uid = strtoupper(md5(uniqid(time()))); } $object = array( 'uid' => $uid, 'full-name' => $message->fileas , 'given-name' =>$message->firstname, 'last-name' => $message->lastname, 'middle-names' => $message->middlename, 'prefix' => $message->title, 'suffix' => $message->suffix, 'job-title' => $message->jobtitle, 'web-page' => $message->webpage, 'emails' => $message->email1address, 'phone-mobile' => $message->mobilephonenumber, 'phone-business1' => $message->businessphonenumber, 'phone-business2' => $message->business2phonenumber, 'phone-home1' => $message->homephonenumber, 'phone-pager' => $message->pagernumber, 'phone-businessfax' => $message->businessfaxnumber, 'addr-business-street' => u2w($message->businessstreet), 'addr-business-locality' => u2w($message->businesscity), 'addr-business-postal-code' => $message->businesspostalcode, 'addr-business-region' => $message->businessstate, 'addr-business-country' => $message->businesscountry, 'addr-home-street'=> $message->homestreet, 'addr-home-locality' => $message->homecity , 'addr-home-postal-code' => $message->homepostalcode, 'addr-home-region' => $message->homestate, 'addr-home-country' => $message->homecountry, 'addr-other-street'=> $message->otherstreet, 'addr-other-locality' => $message->othercity , 'addr-other-postal-code' => $message->otherpostalcode, 'addr-other-region' => $message->othersstate, 'addr-other-country' => $message->othercountry, 'organization' => $message->companyname , 'department' => $message->department, 'spouse-name'=> $message->spouse, 'children' =>$message->children, 'nick-name'=> $message->nickname, 'assistant' => $message->assistantname, 'department' => $message->department , 'office-location' => $message->officelocation ); if ($message->body != "") { $object['body']=$message->body; } elseif ($message->rtf) { $object['body']=$this->rtf2text($message->rtf); //case of mobile windowz 6.5 who send this string for an empty body if ($object['body'] == "<sn></sn>") { $object['body']=""; } } //bithday if ( isset($message->anniversary)) { $object['anniversary'] =substr($this->KolabDateUnix2Kolab($message->anniversary),0,10); } if ( isset($message->birthday)) { $object['birthday'] = substr($this->KolabDateUnix2Kolab($message->birthday),0,10); } //children $children=$message->children; if ($children != NULL) { $object['children']=join(",",$children); } //picture if ( is_null($message->picture) ) { //no image or not modified //check if picture has been modified $message->picture=$this->CacheReadPicture($uid); if ($message->picture) { $object['picture'] ="photo.jpeg"; } } else { if ( $message->picture == "") { //erase the picture $this->CacheDeletePicture($uid); } else { $object['picture'] ="photo.jpeg"; $this->CacheWritePicture($uid,$message->picture); } } //check mail for android if (preg_match("/\<(.+)\>/",$object['emails'],$m)) { $object['emails']=$m[1]; } //fulname empty (happen sometimes with iphone) if ( $object['full-name'] == "") { $object['full-name']= $object['given-name']. ' ' . $object['last-name']; } NLS::setCharset('utf-8'); $format = Horde_Kolab_Format::factory('XML', 'contact'); $xml = $format->save($object); unset($format); // set the mail // attach the XML file $mail=$this->mail_attach("kolab.xml",0,$xml,"kolab message","text/plain", "plain","application/x-vnd.kolab.contact",$message->picture); //add the picture if needed //add header $h["from"]=$this->_email; $h["to"]=$this->_email; $h["X-Mailer"]="z-push-Kolab Backend"; $h["subject"]= $object["uid"]; $h["message-id"]= "<" . strtoupper(md5(uniqid(time()))) . ">"; $h["date"]=date(DATE_RFC2822); foreach(array_keys($h) as $i) { $header= $header . $i . ": " . $h[$i] ."\r\n"; } //return the mail formatted return array($uid,$h['date'],$header .$mail[0]."\r\n" .$mail[1]); } private function KolabReadEvent($message,$id,$disableAlarm=false) { $event=NULL; //searching the righ attachment Kolab XML $n=0; if(isset($message->parts)) { foreach($message->parts as $part) { if(isset($part->disposition) && ($part->disposition == "attachment" || $part->disposition == "inline")) { $type=$part->headers; //kolab contact attachment ? $ctype=explode(";",$type["content-type"] ) ; $ctype[0]=trim($ctype[0]); if ($ctype[0] == "application/x-vnd.kolab.event" ) { String::setDefaultCharset('utf-8'); $format = Horde_Kolab_Format::factory('XML', 'event'); $body=$part->body; $kevent=$format->load($body); unset($format); if ($kevent instanceof PEAR_Error) { //parsing error debugLog("ERROR ".$kevent->message); debugLog("Xml kolab : $body") ; $this->Log("ERROR ".$kevent->message); $this->Log("XML : $body") ; unset ($kevent); return ""; } //mappage $event=new SyncAppointment(); $event->uid = strtoupper($kevent['uid']); $event->dtstamp = time(); $event->subject=$this->fenc($kevent['summary']); $event->starttime=$kevent['start-date']; $event->endtime=$kevent['end-date']; switch(strtolower($kevent['sensitivity'])) { case "private": $event->sensitivity="2"; break; case "confidential": $event->sensitivity="3"; } //bug #9 Alarm mus not be shown for all folders if ($disableAlarm == false) { if ($kevent['alarm'] > 0) { $event->reminder=$kevent['alarm']; } } else { $event->reminder=NULL; } $event->location=$this->fenc($kevent['location']); $event->busystatus="2"; if ($kevent['show-time-as'] == 'busy' ) { $event->busystatus="2"; } elseif ($kevent['show-time-as'] == 'free') { $event->busystatus="0"; } elseif ($kevent['show-time-as'] == 'tentative') { $event->busystatus="1"; } elseif ($kevent['show-time-as'] == 'outofoffice') { $event->busystatus="3"; } $event->body=$this->fenc($kevent['body']); //sensitivity $event->meetingstatus="0"; $event->alldayevent="0"; //timezone must be fixed $event->timezone="xP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAIAAAAAAAAAxP///w==" ; $event->bodytruncated = 0; if (isset($kevent["organizer"]["smtp-address"])) { $event->organizername=$this->fenc($kevent["organizer"]["display-name"]); $event->organizeremail=$this->fenc($kevent["organizer"]["smtp-address"]); } else { $event->organizername=$this->fenc($this->_cn); $event->organizeremail=$this->fenc($this->_email); } //reccurence process if (isset($kevent["recurrence"])) { $event->recurrence=$this->kolabReadRecurrence($kevent); //handle exceptions if ( isset($kevent["recurrence"]["exclusion"])) { foreach($kevent["recurrence"]["exclusion"] as $ex) { $poom_ex=new SyncAppointment(); $poom_ex->deleted=1; $poom_ex->exceptionstarttime=$this->KolabDate2Unix($ex); $event->exceptions[]=$poom_ex; } } } return $event; } $n++; } } } return "" ; } private function kolabReadRecurrence($kevent,$type=0) { $numMonth=array( "january" => 1, "february" => 2, "march" => 3, "april" => 4, "may" => 5, "june" => 6, "july" => 7, "august" => 8, "september" => 9, "october" => 10, "november" => 11, "december" => 12 ); if (isset($kevent["recurrence"])) { if ($type == 0) { $recurrence = new SyncRecurrence; } else { $recurrence= new SyncTaskRecurrence; } $rec=$kevent["recurrence"]; //cycle if ($rec["cycle"] == "daily") { $recurrence->type = 0 ; } elseif($rec["cycle"] == "weekly") { $recurrence->type = 1 ; //dayofweek //tableau jour 1=sunday 128 =saturday $nday=0; $recurrence->dayofweek=$this->KolabDofW2pda($rec["day"]); } elseif($rec["cycle"] == "monthly") { // sous type by day if ($rec["type"] == "daynumber") { $recurrence->type = 2 ; $recurrence->dayofmonth = $rec["daynumber"] ; } elseif ($rec["type"] == "weekday") { $recurrence->type = 3 ; $recurrence->weekofmonth = $rec["daynumber"]; //day of week $recurrence->dayofweek=$this->KolabDofW2pda($rec["day"]); } } // year elseif($rec["cycle"] == "yearly") { if ($rec["type"] == "monthday") { $recurrence->type =5 ; $recurrence->dayofmonth = $rec["daynumber"] ; $recurrence->monthofyear= $numMonth[$rec["month"]]; } elseif ($rec["type"] == "weekday") { $recurrence->type =6 ; $recurrence->weekofmonth = $rec["daynumber"]; $recurrence->monthofyear= $numMonth[$rec["month"]]; $recurrence->dayofweek=$this->KolabDofW2pda($rec["day"]); } } //interval $recurrence->interval = $rec["interval"] ; //range if ($rec["range-type"] == "number") { $recurrence->occurrences =$rec["range"]; } elseif ($rec["range-type"] == "date") { /* if ( strtolower($_GET["DeviceType"]) == "iphone") { $recurrence->until =$rec["range"] + 93599; } else { $recurrence->until =$rec["range"]; } */ $recurrence->until =$rec["range"]; } return $recurrence; } else { return NULL; } } private function KolabWriteEvent($message,$uid) { $attendee = array( 'display-name' => $this->_cn, 'smtp-address' => $this->_email, 'uid' => "" ); $test=mb_detect_encoding($message->subject, 'auto'); $object = array( 'uid' => strtoupper($message->uid), 'start-date' => $message->starttime, 'end-date' => $message->endtime, 'summary' => $message->subject, 'reminder' => $message->reminder, 'location' => $message->location, 'alarm' => $message->reminder, 'color-label' => "none" , 'show-time-as' => "busy", 'organizer' => $attendee, 'location' => $message->location ); if ($message->body != "") { $object['body']=$message->body; } elseif ($message->rtf) { $object['body']=$this->rtf2text($message->rtf); } if ($message->alldayevent == 1) { $object['_is_all_day']=True; } switch($message->busystatus ) { case 0: $object['show-time-as'] = "free"; break; case 1: $object['show-time-as'] = "tentative"; break; case 2: $object['show-time-as'] = "busy"; break; case 3: $object['show-time-as'] = "outofoffice"; break; } switch($message->sensitivity) { case 1: case 2: $object["sensitivity"] = "private"; break; case 3: $object["sensitivity"] = "confidential"; } //recurence if(isset($message->recurrence)) { $object["recurrence"]=$this->kolabWriteReccurence($message); } NLS::setCharset('utf-8'); $format = Horde_Kolab_Format::factory('XML', 'event'); $xml = $format->save($object); unset($format); // set the mail // attach the XML file $mail=$this->mail_attach("kolab.xml",0,$xml,"kolab message","text/plain", "plain","application/x-vnd.kolab.event"); //add header $h["from"]=$this->_email; $h["to"]=$this->_email; $h["X-Mailer"]="z-push-Kolab Backend"; $h["subject"]= $object["uid"]; $h["message-id"]= "<" . strtoupper(md5(uniqid(time()))) . ">"; $h["date"]=date(DATE_RFC2822); foreach(array_keys($h) as $i) { $header= $header . $i . ": " . $h[$i] ."\r\n"; } //return the mail formatted return array($object['uid'],$h['date'],$header .$mail[0]."\r\n" .$mail[1]); } private function kolabWriteReccurence($message) { $month=array("dummy","january","february","march","april","may","june","july","august","september","october","november","december"); $rec=array(); $recurrence=$message->recurrence; switch($recurrence->type) { case 0: //repeat daily $rec["cycle"] = "daily"; break; case 1: //repeat weekly $rec["cycle"] = "weekly"; $rec["day"] = $this->KolabPda2DofW($recurrence->dayofweek ); break; case 2: //montly daynumber $rec["cycle"] = "monthly"; $rec["type"] ="daynumber"; $rec["daynumber"] =$recurrence->dayofmonth ; break; case 3: //monthly day of week $rec["cycle"] = "monthly"; $rec["type"] ="weekday"; $rec["daynumber"] =$recurrence->weekofmonth ; $rec["day"] = $this->KolabPda2DofW($recurrence->dayofweek ); break; case 5: //yearly $rec["cycle"] = "yearly"; $rec["type"] ="monthday"; $rec["daynumber"] =$recurrence->dayofmonth ; $rec["month"]=$month[$recurrence->monthofyear]; break; // case 6: //yearly $rec["cycle"] = "yearly"; $rec["type"] ="weekday"; $rec["daynumber"] =$recurrence->weekofmonth ; $rec["month"]=$month[$recurrence->monthofyear]; $rec["day"] = $this->KolabPda2DofW($recurrence->dayofweek ); break; } //interval if (isset($recurrence->interval)) { $rec["interval"] = $recurrence->interval; } else { $rec["interval"] = 1; } if (isset($recurrence->occurrences)) { //by ocurence $rec["range-type"] = "number"; $rec["range"] =$recurrence->occurrences; } elseif (isset($recurrence->until)) { //by end date $rec["range-type"] = "date"; /* Was for the iphone prior to release 4 if ( strtolower($_GET["DeviceType"]) == "iphone" || strtolower($_GET["DeviceType"]) == "ipod") { $rec["range"] =$recurrence->until - 93599 ; } else { $rec["range"] =$recurrence->until; } */ $rec["range"] =$recurrence->until; } else { $rec["range-type"] ="none"; } if (isset($message->exceptions)) { $ex=array(); foreach($message->exceptions as $poom_ex) { if ($poom_ex->deleted == 1) { $ex[]=$this->KolabUnixDay2kolab($poom_ex->exceptionstarttime); } } if (count($ex) > 0) { $rec["exclusion"]=$ex; } } return $rec; } private function KolabReadTask($message,$id,$disableAlarm=false,$with_uid=false) { $task=NULL; $n=0; if(isset($message->parts)) { foreach($message->parts as $part) { if(isset($part->disposition) && ($part->disposition == "attachment" || $part->disposition == "inline")) { $type=$part->headers; //kolab contact attachment ? $ctype=explode(";",$type["content-type"] ) ; $ctype[0]=trim($ctype[0]); if ($ctype[0] == "application/x-vnd.kolab.task") { String::setDefaultCharset('utf-8'); $format = Horde_Kolab_Format::factory('XML', 'task'); $body=$part->body; $ktask=$format->load($body); unset($format); if ($ktask instanceof PEAR_Error) { //parsing error debugLog("ERROR ".$ktask->message); debugLog("Xml kolab : $body") ; $this->Log("ERROR ".$ktask->message); $this->Log("XML : $body") ; unset ($ktask); return ""; } //mappage $task=new SyncTask(); if ( $with_uid != 0) { $task->uid= strtoupper($ktask['uid']); } $task->subject=$this->fenc($ktask['name']); if ($ktask['start']) { $offset=date('Z',$ktask['start']); $task->utcstartdate=$kstart['start']; $task->startdate=$ktask['start'] + $offset; } if($ktask['due']) { $offset=date('Z',$ktask['due']); $task->utcduedate=$ktask['due']; $task->duedate=$ktask['due'] + $offset; } $task->complete=$ktask['completed']; if (isset($ktask['completed_date'])) { $task->datecompleted=$ktask['completed_date']; } //categories if (isset($ktask['categories'])) { $cat=split(',',$this->fenc($ktask['categories'])); $task->categories=$cat; } switch($ktask['priority']) { case 1: $task->importance= 2; break; case 2: case 3: case 4: $task->importance=1; break; case 5: $task->importance=0; } switch(strtolower($ktask['sensitivity'])) { case "public": $task->sensitivity=0; break; case "private": $task->sensitivity=2; break; case "confidential": $task->sensitivity=3; } //bug #9 Alarm mus not be shown for all folders if ($disableAlarm == false) { if ($ktask['alarm'] > 0) { $task->remindertime=$ktask["start"] +($ktask['alarm'] * 60); $task->reminderset=1; } } else { $task->reminderset=NULL; $task->remindertime=NULL; } $task->body=$this->fenc($ktask['body']); //timezone must be fixed $task->bodytruncated = 0; //reccurence process if (isset($ktask["recurrence"])) { $task->recurrence=$this->kolabReadRecurrence($ktask,1); } return $task; } $n++; } } } return "" ; } private function KolabWriteTask($message,$id) { if ( ! $id ) { $uid=strtoupper(md5(uniqid(time()))); } else { $uid=$id; } $object = array( 'uid' => $uid, 'start' => $message->utcstartdate, 'due' => $message->utcduedate, 'name' => $message->subject, ); if (isset($message->rtf)) { $object['body']=$this->rtf2text($message->rtf); } if ($message->reminderset == 1) { $object['alarm']=($message->remindertime - $message->utcstartdate) / 60; } //categories if (isset($message->categories)) { $object['categories']=join(',',$message->categories); } switch($message->importance) { case 0: $object["priority"] = 5; break; case 1: $object["priority"] = 3; break; case 2: $object["priority"] = 1; break; } if ( $message->complete == 1) { $object['completed'] = 100; $object['completed_date'] = $message->datecompleted; } else { $object['completed'] = 0; } switch($message->sensitivity) { case 1: case 2: $object["sensitivity"] = "private"; break; case 3: $object["sensitivity"] = "confidential"; } //recurence if(isset($message->recurrence)) { $object["recurrence"]=$this->kolabWriteReccurence($message->recurrence); } NLS::setCharset('utf-8'); $format = Horde_Kolab_Format::factory('XML', 'task'); $xml = $format->save($object); unset($format); // set the mail // attach the XML file $mail=$this->mail_attach("kolab.xml",0,$xml,"kolab message","text/plain", "plain","application/x-vnd.kolab.task"); //add header $h["from"]=$this->_email; $h["to"]=$this->_email; $h["X-Mailer"]="z-push-Kolab Backend"; $h["subject"]= $object["uid"]; $h["message-id"]= "<" . strtoupper(md5(uniqid(time()))) . ">"; $h["date"]=date(DATE_RFC2822); foreach(array_keys($h) as $i) { $header= $header . $i . ": " . $h[$i] ."\r\n"; } //return the mail formatted return array($object['uid'],$h['date'],$header .$mail[0]."\r\n" .$mail[1]); } private function KolabUnixDay2kolab($timestamp) { $d=substr($this->KolabDateUnix2Kolab($timestamp),0,10); return $d; } //return the date for Kolab private function KolabDateUnix2Kolab($timestamp) { $d=date(DATE_W3C ,$timestamp); $d=substr($d,0,19) . "Z" ; return $d; } private function KolabDate2Unix($kdate) { if (! $kdate) { return NULL; } else { $tm= gmmktime(0, 0, 0, substr($kdate,5,2), substr($kdate,8,2), substr($kdate,0,4)); return $tm; } } private function fenc($input) { //if encoding is cp1252 - encode it to utf8 using utils.php if(strcasecmp(mb_detect_encoding($input, 'auto'), 'cp1252') == 0) { $output=w2u($input); }else { //input is in UTF8 - send it to the phone $output=$input; } return $output; } /*CacheCreateIndex : create an index to retrieve easly the uid-> id and the id->uid */ private function CacheCreateIndex($folderid,$kolab_uid,$imap_uid) { $kolab_uid=strtoupper($kolab_uid); $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $this->_cache->write("IMAP:".$folderid.$this->_serverdelimiter.$imap_uid,$kolab_uid); $this->_cache->write("KOLAB:".$folderid.$this->_serverdelimiter.$kolab_uid,$imap_uid); //must another index to find the folder of the uid $this->_cache->write("FLMODE:".$kolab_uid, $folderid); $this->_cache->close(); } private function CacheIndexUid2FolderUid($uid) { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $result= $this->_cache->find("FLMODE:".$uid); $this->_cache->close(); return $result; } private function CacheStoreMessageList($folder,$mlist) { $stat=serialize($mlist); $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $this->_cache->write("MLIST:".$folder,$stat); $this->_cache->close(); } private function CacheReadMessageList($folder) { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $result= $this->_cache->find("MLIST:".$folder); $this->_cache->close(); return unserialize($result); } private function CacheStoreImapStatus($folder,$stat) { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $this->_cache->write("FIMAPSTAT:".$folder,serialize($stat)); $this->_cache->close(); } private function CacheReadImapStatus($folder) { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $result= $this->_cache->find("FIMAPSTAT:".$folder); $this->_cache->close(); return unserialize($result); } private function CacheIndexId2Uid($folderid,$id) { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $result= $this->_cache->find("IMAP:".$folderid.$this->_serverdelimiter.$id); $this->_cache->close(); return $result; } private function CacheIndexUid2Id($folderid,$uid) { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $result= $this->_cache->find("KOLAB:".$folderid.$this->_serverdelimiter.$uid); $this->_cache->close(); return $result; } private function CacheIndexDeletebyId($folderid,$id) { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $uid= $this->_cache->find("IMAP:".$folderid.$this->_serverdelimiter.$id); $this->_cache->delete("IMAP:".$folderid.$this->_serverdelimiter.$id); $this->_cache->delete("KOLAB:".$folderid.$this->_serverdelimiter.$uid); $this->_cache->delete("ENDDATE:".$folderid.$this->_serverdelimiter.$uid); $this->_cache->delete("FLMODE:".$uid); $this->_cache->close(); return $result; } private function CacheCheckVersion() { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $version= $this->_cache->find("CACHEVERSION"); if ( $version != KOLABBACKEND_VERSION) { //reinit cache $this->_cache->close(); $this->_cache->purge(); $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $this->_cache->write("CACHEVERSION",KOLABBACKEND_VERSION); } $this->_cache->close(); } private function CacheIndexClean($messagelist) { return; } private function CacheWriteFolderParam($folder,$fa) { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $this->_cache->write("FOLDERPARAM:".$folder,$fa->serialize()); $this->_cache->close(); } private function CacheReadFolderParam($folder) { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $result= $this->_cache->find("FOLDERPARAM:".$folder); $this->_cache->close(); $fa=new folderParam(); $fa->unserialize($result); return $fa; } private function KolabgetMail($username) { return $username . "@localhost.localdomain"; } private function KolabDofW2pda($recday) { foreach ($recday as $day) { if($day == "sunday") { $nday=$nday +1; } elseif ($day == "monday") { $nday=$nday +2; } elseif ($day == "tuesday") { $nday=$nday + 4; } elseif ($day == "wednesday") { $nday=$nday + 8; } elseif ($day == "thursday") { $nday=$nday + 16; } elseif ($day == "friday") { $nday=$nday + 32; } elseif ($day == "saturday") { $nday=$nday + 64; } } return $nday; } private function KolabPda2DofW($value) { $days=array(); $test = $value & 8; $value=$value *1; //conversion in long ... if ( ($value & 1) >0){$days[]="sunday";} if ( ($value & 2) >0){$days[]="monday";} if ( ($value & 4) >0){$days[]="tuesday";} if ( ($value & 8) >0) { $days[]="wednesday"; } if ( ($value & 16) >0){$days[]="thursday";} if ( ($value & 32) >0){$days[]="friday";} if ( ($value & 64) >0){$days[]="saturday";} return $days ; } private function Log($message) { if (KOLAB_LOGFILE != "" ) { @$fp = fopen(KOLAB_LOGFILE ,"a+"); @$date = strftime("%x %X"); @fwrite($fp, "$date [". getmypid() ."] : " . $this->_username . " : $message\n"); @fclose($fp); } } private function KolabStat($fid,$o) { if ( !$o) { return false; } $kolab_uid=""; $m= array(); $m["mod"] = $fid .$this->_serverdelimiter.$o->uid; //search the kolab uid in index if nofound read the mail to find it $kolab_uid=$this->CacheIndexId2Uid($fid,$o->uid); if (! $kolab_uid) { //no found read the message $mail = @imap_fetchheader($this->_mbox, $o->uid, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $o->uid, FT_PEEK | FT_UID); $mobj = new Mail_mimeDecode($mail); $message = $mobj->decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $mail, 'crlf' => "\n", 'charset' => 'utf-8')); if ($this->kolabFolderType($fid) == 2) { $ev=$this->KolabReadEvent($message,false) ; if (! $ev) { return false ; } $kolab_uid=strtoupper($ev->uid); //index if ($kolab_uid){ $this->CacheCreateIndex($fid,$kolab_uid,$o->uid); //index of the endDate too $this->CacheWriteEndDate($fid,$ev); if ( $ev->sensitivity != 0) { //add in cache the sensitivity $this->CacheWriteSensitivity($kolab_uid,$ev->sensitivity); } } else { return False; } } if ($this->kolabFolderType($fid) == 1) { $ev=$this->KolabReadContact($message,1) ; $kolab_uid=strtoupper($ev->uid); //index if ($kolab_uid){ $this->CacheCreateIndex($fid,$kolab_uid,$o->uid); } else { return False; } } if ($this->kolabFolderType($fid) == 3) { $ev=$this->KolabReadTask($message,false,false,1) ; $kolab_uid=strtoupper($ev->uid); //index if ($kolab_uid){ $this->CacheCreateIndex($fid,$kolab_uid,$o->uid); if ( $ev->sensitivity != 0) { //add in cache the sensitivity $this->CacheWriteSensitivity($kolab_uid,$ev->sensitivity); } if ( $ev->complete) { $this->CacheWriteTaskCompleted($kolab_uid,$ev->complete); } } else { return False; } } } $m["id"] = $kolab_uid; //$m["mod"]= $o->uid; // 'seen' aka 'read' is the only flag we want to know about $m["flags"] = 0; return $m; } private function getImapFolderType($folder) { if (function_exists("imap_getannotation")) { $result = imap_getannotation($this->_mbox, $folder, "/vendor/kolab/folder-type", "value.shared"); if (isset($result["value.shared"])) { $anno=$result["value.shared"]; } else { $anno=""; } } else { $rec=""; $anno=""; $fp = fsockopen($this->_KolabHomeServer,KOLAB_IMAP_PORT, $errno, $errstr, 30); if (!$fp) { return false; } else { //vidage greeting $rec=$rec . stream_get_line($fp,1024,"\r\n"); $rec=""; //envoi login ; $out = "01 LOGIN " . $this->_username." ". $this->_password ."\r\n"; fwrite($fp, $out); $rec=$rec . stream_get_line($fp,1024,"\r\n"); if (ereg("01 OK",$rec)) { $r=array(); //envoi de la commande myrights $out='ok getannotation "'.$folder.'" "/vendor/kolab/folder-type" "value"' ."\r\n"; fwrite($fp, $out); $rec=fread($fp,1024); $r=split("\r\n",$rec); $rec=$r[0]; if (ereg("ANNOTATION",$rec)) { //bonne reponse //* ANNOTATION "INBOX/Calendrier" "/vendor/kolab/folder-type" ("value.shared" "event.default") $tab=array(); $reg= "/value.shared\" \"(.+)\"/"; if (preg_match($reg,$rec,$tab)) { $anno=$tab[1]; } } $out="03 LOGOUT\r\n"; fwrite($fp, $out); fclose($fp); } } } // Allow only non-default annotations to be set on folders not in // the personal namespace. $tab = explode(".",$anno); $root = explode($this->_serverdelimiter,$folder); if ( $root[0] != $this->namespaces['personal']) { if (count($tab) == 2) { $anno = $tab[0]; } } return $anno; } private function kolabFolderType($name) { if ( $name == "calendar") { return 2; } if ( $name == "contacts") { return 1; } if ( $name == "tasks") { return 3; } $type= $this->readFolderAnnotation($name) ; if ( $type == false) { //not in the cache $this->saveFolderAnnotation($name); $type= $this->readFolderAnnotation($name) ; } if ($type == "task" || $type == "task.default") { return 3; } if ($type == "event" || $type == "event.default") { return 2; } if ($type == "contact" || $type == "contact.default") { return 1; } return 0; } private function ActiveSyncFolderSyncType($name) { $type= $this->readFolderAnnotation($name) ; if ( $type == "task.default") { return SYNC_FOLDER_TYPE_TASK; } if ( $type == "event.default") { return SYNC_FOLDER_TYPE_APPOINTMENT; } if ( $type == "contact.default") { return SYNC_FOLDER_TYPE_CONTACT; } if ( $type == "task") { //check if no default folder exist; if ( $this->hasDefaultTaskFolder == false ) { if ($this->isDefaultFolder($name,KOLAB_DEFAULTFOLDER_TASK)) { $this->hasDefaultTaskFolder= true; $this->forceDefaultFolder("task",$name); return SYNC_FOLDER_TYPE_TASK; } } return SYNC_FOLDER_TYPE_USER_TASK; } if ( $type == "event") { if ( $this->hasDefaultEventFolder == false ) { if ($this->isDefaultFolder($name,KOLAB_DEFAULTFOLDER_DIARY)) { $this->Log("NOTICE no event default folder set as default: $name"); $this->forceDefaultFolder("event",$name); $this->hasDefaultEventFolder= true; return SYNC_FOLDER_TYPE_APPOINTMENT; } } return SYNC_FOLDER_TYPE_USER_APPOINTMENT; } if ( $type == "contact") { if ( $this->hasDefaultContactFolder == false ) { if ($this->isDefaultFolder($name,KOLAB_DEFAULTFOLDER_CONTACT)) { $this->forceDefaultFolder("contact",$name); $this->hasDefaultContactFolder= true; return SYNC_FOLDER_TYPE_CONTACT; } } return SYNC_FOLDER_TYPE_USER_CONTACT; } } private function isDefaultFolder($folder,$defaultchain) { $folder=strtolower($folder); $f=split(":",strtolower($defaultchain)); foreach($f as $value) { if ($value == $folder) { return true; } } return false; } private function forceDefaultFolder($type,$folder) { switch ($type){ case 1: $type="contact"; break; case 2: $type="event"; break; case 3: $type="task"; break; } $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $this->_cache->write("DEFAULT:".$type.".default",$folder); $this->_cache->close(); } private function saveFolderAnnotation($foldera) { $anno=$this->getImapFolderType($foldera); if (!$anno) { $anno="0"; } $default=explode(".",$anno); //remove the default if this is not in INBOX folder //we must detech just INBOX default folder $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); if ( isset($default[1]) && $default[1] == "default" ) { if (substr($foldera,0,strlen($this->namespaces['personal'])) == $this->namespaces['personal']) { $this->_cache->write("DEFAULT:".$anno,$foldera); } else { $anno = $default[0]; } } if ( $anno =="mail.sentitems") { $this->_cache->write("SENTFOLDER:",$foldera); } if ( ! $this->_cache->write("FA:".$foldera,$anno)) { $this->Log("ERROR: ".KOLAB_INDEX."/".$this->_username); } $this->_cache->close(); //$this->Log("Annotation $foldera : $anno") ; } private function readDefaultSentItemFolder() { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $sentf=$this->_cache->find("SENTFOLDER:"); $this->_cache->close(); return $sentf; } private function readFolderAnnotation($folder) { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $anno=$this->_cache->find("FA:".$folder); $this->_cache->close(); return $anno; } private function CacheGetDefaultFolder($type) { switch ($type){ case 1: $type="contact"; break; case 2: $type="event"; break; case 3: $type="task"; break; } $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $deffolder=$this->_cache->find("DEFAULT:".$type.".default"); $this->_cache->close(); return $deffolder; } private function CacheReadEndDate($folder,$uid) { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $deffolder=$this->_cache->find("ENDDATE:".$folder.$this->_serverdelimiter.$uid); $this->_cache->close(); if ($deffolder == False) { $deffolder = "-1"; } return $deffolder; } private function CacheWriteEndDate($folder,$event) { $uid=strtoupper($event->uid); $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $edate=-1; if ($event->recurrence) { //end date in the recurence ? if (isset($event->recurrence->until)) { if ( strtolower($_GET["DeviceType"]) == "iphone" || strtolower($_GET["DeviceType"]) == "ipod") { $edate =$event->recurrence->until - 93599 ; } else { $edate = $event->recurrence->until; } } elseif(isset($event->recurrence->occurrences)) { if ( isset($event->recurrence->interval)) { $interval=$event->recurrence->interval; } else { $interval=1; } switch($event->recurrence->type) { case 0: //repeat daily // enddate = startDate + (repeat +(86400 * interval)) $edate= $event->starttime + ($event->recurrence->occurrences *(86400* $interval)) ; break; case 2: //approche monts =31 to be sure to not cute it with a complex thing $edate= $event->starttime + ($event->recurrence->occurrences *(2678400* $interval)) ; case 5: //yearly $edate= $event->starttime + ($event->recurrence->occurrences *(31536000* $interval )) ; break; } } //others stuffs } else { $edate=$event->endtime; } $this->_cache->write("ENDDATE:" . $folder.$this->_serverdelimiter.$uid,$edate); $this->_cache->close(); } private function CacheWriteSensitivity($uid,$sensitivity) { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $this->_cache->write("SENSITIVITY:" .$uid,$sensitivity); $this->_cache->close(); } private function CacheReadSensitivity($uid) { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $s=$this->_cache->find("SENSITIVITY:" .$uid); $this->_cache->close(); return $s; } private function CacheWriteTaskCompleted($uid,$completed) { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $this->_cache->write("TCOMPLETED:" .$uid,$completed); $this->_cache->close(); } private function CacheReadTaskCompleted($uid) { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $s=$this->_cache->find("TCOMPLETED:" .$uid); $this->_cache->close(); return $s; } private function CacheWritePicture($uid,$picture) { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $this->_cache->write("CPICTURE:" .$uid,$picture); $this->_cache->close(); } private function CacheReadPicture($uid) { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $s=$this->_cache->find("CPICTURE:" .$uid); $this->_cache->close(); return $s; } private function CacheDeletePicture($uid) { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $this->_cache->delete("CPICTURE:".$uid); $this->_cache->close(); } private function cacheReadFolderId($folder) { $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $s=$this->_cache->find("ACTIVESYNCFID:".$folder); if ($s == false) { //we must regenerate the cache $this->_cache->close(); $this->cacheRegenerateFolderId(); $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $s=$this->_cache->find("ACTIVESYNCFID:".$folder); } $this->_cache->close(); return $s; } private function cacheRegenerateFolderId() { $list = @imap_getmailboxes($this->_mbox, $this->_server, "*"); //add VIRTUAL at First $this->cacheWriteFolderId("calendar"); $this->cacheWriteFolderId("contacts"); $this->cacheWriteFolderId("tasks"); $this->cacheWriteFolderId("user"); $this->cacheWriteFolderId("shared"); foreach( $list as $l) { $folderName=substr($l->name, strlen($this->_server)); $this->cacheWriteFolderId($folderName); } } private Function cacheReadId2Folder($id) { if ($id == "0") { return "0"; } $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $s=$this->_cache->find("ACTIVESYNCFIDF:".$id); if ($s == false) { //id not found regeneratee the cache $this->_cache->close(); $this->cacheRegenerateFolderId(); $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); $s=$this->_cache->find("ACTIVESYNCFIDF:".$id); } $this->_cache->close(); return $s; } private function cacheWriteFolderId($folder) { if ($folder == "0") { return "0"; } $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); /*$s=$this->_cache->find("FIDNEXT:"); if ($s === false) { $s="1"; //0 reserved for the IBOX root }*/ $s=sha1($folder); $test=$this->_cache->write("ACTIVESYNCFID:".$folder,"$s"); $test=$this->_cache->write("ACTIVESYNCFIDF:$s",$folder); $this->_cache->close(); return $s; } private function kolabReadGlobalParam() { if (function_exists("imap_getannotation")) { $gp=new GlobalParam(); $result = imap_getannotation($this->_mbox, "INBOX", "/vendor/kolab/activesync", "value.priv"); if (isset($result["value.priv"])) { if ( ! $gp->unserialize($result["value.priv"])) { return $gp; } } return $gp; } } private function kolabReadFolderParam($folder) { if (function_exists("imap_getannotation")) { $gp=new FolderParam(); $result = imap_getannotation($this->_mbox, $folder, "/vendor/kolab/activesync", "value.priv"); if (isset($result["value.priv"])) { if ( ! $gp->unserialize($result["value.priv"])) { return $gp; } } return $gp; } } private function kolabWriteGlobalParam($gp) { if ( ! $gp) { return false ; } $anno=$gp->serialize(); if (function_exists("imap_setannotation")) { //write annotation on the INBOX folder $result = @imap_setannotation($this->_mbox, "INBOX", "/vendor/kolab/activesync", "value.priv",$anno); if ( ! $result) { $this->Log("write globalparam :".@imap_last_error()); return false; } } return true ; } //** Register a folder for Sync private function kolabRegisterFolder($serial,$folder) { if ( ! function_exists("imap_setannotation")) { return false; } $fp=new FolderParam(); $fp->setForSync($serial); $anno=$fp->serialize(); $result = @imap_setannotation($this->_mbox, $folder, "/vendor/kolab/activesync", "value.priv",$anno); if ( ! $result) { $this->Log("write kolab autoregister failed :".@imap_last_error()); return false; } return true; } private function getLdapAccount() { //chech if KOLAB_LDAP_SERVER is a URI or an IP $reg= "/ldap:\/\/(.+):(.+)/"; if (preg_match($reg,KOLAB_SERVER,$tab)) { $addrip=$tab[1]; $port=$tab[2]; } else { $addrip=KOLAB_SERVER; $port=389; } $conn=ldap_connect($addrip,$port) ; if ($conn == 0) { $this->Log("ERR LDAP connexion to server : " . KOLAB_SERVER . " failed"); return 0; } $bind=""; $bindpasswd=""; if ( defined('KOLAB_BIND_DN')) { $bind=KOLAB_BIND_DN; } if ( defined('KOLAB_BIND_PW')) { $bindpasswd=KOLAB_BIND_PW; } debugLog("Attempting to bind with $bind and $bindpasswd"); if (!ldap_bind ($conn,$bind,$bindpasswd)) { $this->Log("ERR LDAP Invalid credential") ; return 0; } //recherche du DN a autentifier if ( ! $sr=ldap_search($conn,KOLAB_LDAP_BASE,"(uid=".$this->_username.")")) { $this->Log("ERR LDAP ". $this->_username ." not found") ; return 0; } $entries=ldap_get_entries($conn,$sr); if ($entries['count'] == 1) { $this->_email=$entries[0]["mail"][0]; $this->_cn=$entries[0]["cn"][0]; if (defined("KOLAB_IMAP_SERVER")) { $this->_KolabHomeServer = KOLAB_IMAP_SERVER; } else { $this->_KolabHomeServer = $entries[0]["kolabhomeserver"][0]; } $dn=$entries[0]["dn"]; //check ACL if KOLAN_LDAP_ACL if (defined("KOLAB_LDAP_ACL")) { $grp=KOLAB_LDAP_ACL; } else { $grp =""; } if ($grp != "") { //check if the dn is in the group as member $r = ldap_compare($conn, $grp, "member", $dn) ; if ( ! $r) { $this->Log("ACL member not present in $grp Access Denied"); return 0; } if ( $r == -1) { $this->Log("ACL group $gr not found (acces authorized)"); } } return 1; } } private function rtf2text($data) { $rtf_body = new rtf (); $rtf_body->loadrtf(base64_decode($data)); $rtf_body->output("ascii"); $rtf_body->parse(); $r=$rtf_body->out; unset($rtf_body); return $r; } private function CheckProcess($devid) { //DebugBreak("1@192.168.254.1:7869;d=1,p=0"); $file=STATE_DIR."/".$devid.".pid"; if (file_exists($file)) { //another process is running for this devid? $pid=unserialize(file_get_contents($file)); //Verifying for N900 if it is the same process //it seems that it send many requests in the same //socket. if ($pid == getmypid()) { return; } //see if the pid is running if ($this->processName($pid) == "apache") { debugLog("Killing process $pid "); exec("kill -9 $pid"); //posix_kill($pid,SIGQUIT); } } file_put_contents($file,serialize(getmypid())); //create again the pid file //fopen($file,"r"); //unlink($file); } private function processName($pid) { // $name=exec("ps -p $pid -o comm=",$name); return $name; } }; class userCache { private $_filename; private $_id; public $_lastError; function open($filename) { $this->_id = dba_open ($filename.".cache", "cl"); if (!$this->_id) { $this->_lastError = "failed to open $filename"; return false; } $this->_filename=$filename; return true; } function close() { dba_close($this->_id); } function write($key,$value) { $oldvalue=dba_fetch($key, $this->_id); if ( $oldvalue == $value) { //the key already exist and the value is the same we do nothing return 1; } if ($oldvalue) { //the key exist but the value change dba_delete($key,$this->_id); } return dba_insert($key,$value, $this->_id); } function delete($key) { if (dba_exists ($key, $this->_id)) { return dba_delete ($key, $this->_id); } return 1; } function purge() { unlink($this->_filename."cache"); } function find($key) { return dba_fetch($key,$this->_id); } } ?>
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor