Back to index

d-push  2.0
kolab.php
Go to the documentation of this file.
00001 <?php
00002     /*
00003     Kolab Z-Push Backend
00004 
00005     Copyright (C) 2009-2010 Free Software Foundation Europe e.V.
00006 
00007     The main author of the Kolab Z-Push Backend is Alain Abbas, with
00008     contributions by .......
00009 
00010     This program is Free Software; you can redistribute it and/or
00011     modify it under the terms of version two of the GNU General Public
00012     License as published by the Free Software Foundation.
00013 
00014     This program is distributed in the hope that it will be useful, but
00015     WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00017     General Public License for more details.
00018 
00019     You should have received a copy of the GNU General Public License
00020     along with this program; if not, write to the Free Software
00021     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00022     02110-1301, USA.
00023 
00024     The licensor of the Kolab Z-Push Backend is the 
00025     Free Software Foundation Europe (FSFE), Fiduciary Program, 
00026     Linienstr. 141, 10115 Berlin, Germany, email:ftf@fsfeurope.org.
00027     */                                                                    
00028     //define('KOLABBACKEND_VERSION', 'SVN developpment 20100307');
00029     define('KOLABBACKEND_VERSION', '0.6');   
00030     include_once('diffbackend.php');
00031 
00032     // The is an improved version of mimeDecode from PEAR that correctly
00033     // handles charsets and charset conversion
00034     include_once('mimeDecode.php');
00035     include_once('z_RTF.php');
00036     include_once('z_RFC822.php');
00037     include_once('Horde/Kolab/Kolab_Zpush/lib/kolabActivesyncData.php');
00038     require_once 'Horde/Kolab/Format.php';
00039 
00040     class BackendKolab extends BackendDiff {
00041         private $_server = "";
00042         private $_username ="";
00043         private $_domain = "";
00044         private $_password = "";
00045         private $_cache;
00046         private $_deviceType;
00047         private $_deviceAgent;
00048         private $hasDefaultEventFolder =false;
00049         private $hasDefaultContactFolder= false;  
00050         private $hasDefaultTaskFolder = false;
00051         private $foMode = false;
00052         private $_mbox;
00053         private $_KolabHomeServer;
00054         private $_cn;
00055         private $_email;
00056         private $sentFolder="";
00057         /* Called to logon a user. These are the three authentication strings that you must
00058         * specify in ActiveSync on the PDA. Normally you would do some kind of password
00059         * check here. Alternatively, you could ignore the password here and have Apache
00060         * do authentication via mod_auth_*
00061         */ 
00062         function Logon($username, $domain, $password) {
00063             $this->_wasteID = false;
00064             $this->_sentID = false;
00065             $this->_username = $username;
00066             $this->_domain = $domain;
00067             $this->_password = $password; 
00068             if (!$this->getLdapAccount())
00069             {
00070                 return false;
00071             }
00072             $this->_server = "{" . $this->_KolabHomeServer . ":" . KOLAB_IMAP_PORT . "/imap" . KOLAB_IMAP_OPTIONS . "}"; 
00073             $this->Log("Connecting to ". $this->_server);
00074             if (!function_exists("imap_open")) 
00075             {
00076                 debugLog("ERROR BackendIMAP : PHP-IMAP module not installed!!!!!");
00077                 $this->Log("module PHP imap not installed ")  ;
00078             }
00079 
00080             // open the IMAP-mailbox 
00081             $this->_mbox = @imap_open($this->_server , $username, $password, OP_HALFOPEN);
00082             $this->_mboxFolder = "";
00083 
00084             if ($this->_mbox) {
00085                 debugLog("KolabBackend Version : " . KOLABBACKEND_VERSION);
00086                 debugLog("KolabActiveSyndData Version : " .KOLABACTIVESYNCDATA_VERSION);
00087                 $this->Log("KolabBackend Version : " . KOLABBACKEND_VERSION);
00088                 $this->Log("KolabActiveSyndData Version : " .KOLABACTIVESYNCDATA_VERSION);
00089                 $this->Log("IMAP connection opened sucessfully user : " . $username );
00090                 // set serverdelimiter
00091                 $this->_serverdelimiter = $this->getServerDelimiter();
00092 
00093                 return true;
00094             }
00095             else {
00096                 $this->Log("IMAP can't connect: " . imap_last_error() . "  user : " . $this->_user . " Mobile ID:" . $this->_devid);
00097                 return false;
00098             }
00099         }
00100 
00101         /* Called before shutting down the request to close the IMAP connection
00102         */
00103         function Logoff() {
00104             if ($this->_mbox) {
00105                 // list all errors             
00106                 $errors = imap_errors();
00107                 if (is_array($errors)) {
00108                     foreach ($errors as $e)    debugLog("IMAP-errors: $e");            
00109                 }             
00110                 @imap_close($this->_mbox);
00111                 debugLog("IMAP connection closed");
00112                 $this->Log("IMAP connection closed");
00113                 unset($this->_cache);
00114             }
00115         }
00116 
00117         /* Called directly after the logon. This specifies the client's protocol version
00118         * and device id. The device ID can be used for various things, including saving
00119         * per-device state information.
00120         * The $user parameter here is normally equal to the $username parameter from the
00121         * Logon() call. In theory though, you could log on a 'foo', and then sync the emails
00122         * of user 'bar'. The $user here is the username specified in the request URL, while the
00123         * $username in the Logon() call is the username which was sent as a part of the HTTP 
00124         * authentication.
00125         */    
00126         function Setup($user, $devid, $protocolversion) {
00127             $this->_user = $user;
00128             $this->_devid = $devid;
00129             $this->_protocolversion = $protocolversion;
00130             if ($devid == "")
00131             {
00132                 //occurs in the OPTION Command
00133                 return true;
00134             }
00135             $this->_deviceType=$_REQUEST["DeviceType"];
00136             $this->_deviceAgent=$_SERVER["HTTP_USER_AGENT"];
00137             $this->Log("Setup : " . $user. " Mobile ID :" . $devid. " Proto Version : " . $protocolversion ." DeviceType : ". $this->_deviceType . " DeviceAgent : ". $this->_deviceAgent);
00138             $this->_cache=new userCache();
00139             $this->CacheCheckVersion();
00140             //read globalparam . 
00141             $gp=$this->kolabReadGlobalParam();
00142 
00143             $mode=KOLAB_MODE;
00144             if ($gp != false )
00145             {
00146                 //search if serial already in it;
00147                 if ( $gp->getDeviceType($devid))
00148                 {
00149                     if ( $gp->getDeviceMode($devid) != -1)
00150                     {
00151                         $mode=$gp->getDeviceMode($devid);
00152                     }
00153                 }
00154                 else
00155                 {
00156                     //no present we must write it;
00157                     $gp->setDevice($devid,$this->_deviceType) ;
00158                     if ( ! $this->kolabWriteGlobalParam($gp))
00159                     {
00160                         $this->Log("ERR cant write Globalparam");
00161                     }
00162                 }
00163             }
00164             switch($mode)
00165             {
00166                 case 0:$this->foMode = false;
00167                 $this->Log("NOTICE : Forced to flatmode") ;
00168                 break;
00169                 case 1:$this->foMode = true;
00170                 $this->Log("NOTICE : Forced to foldermode") ;
00171                 break;  
00172                 case 2:$this->foMode = $this->findMode();
00173                 break;
00174             }
00175             return true;
00176         }
00177 
00178         /* Sends a message which is passed as rfc822. You basically can do two things
00179         * 1) Send the message to an SMTP server as-is
00180         * 2) Parse the message yourself, and send it some other way
00181         * It is up to you whether you want to put the message in the sent items folder. If you
00182         * want it in 'sent items', then the next sync on the 'sent items' folder should return
00183         * the new message as any other new message in a folder.
00184         */
00185         private function findMode()
00186         {   
00187             $type=explode(":",KOLAB_MOBILES_FOLDERMODE);
00188             if (in_array(strtolower($this->_deviceType),$type))
00189             {
00190                 $this->Log("NOTICE : findMode Foldermode") ; 
00191                 return 1;
00192             }
00193             $this->Log("NOTICE : findMode Flatmode") ;  
00194             return 0;
00195         }
00196         function SendMail($rfc822, $forward = false, $reply = false, $parent = false) {
00197             debugLog("IMAP-SendMail: " . $rfc822 . "for: $forward   reply: $reply   parent: $parent" );
00198             //
00199             $mobj = new Mail_mimeDecode($rfc822);
00200             $message = $mobj->decode(array('decode_headers' => false, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $rfc822, 'crlf' => "\n", 'charset' => 'utf-8'));
00201 
00202             $toaddr = $ccaddr = $bccaddr = "";
00203             if(isset($message->headers["to"]))
00204             $toaddr = $this->parseAddr(Mail_RFC822::parseAddressList($message->headers["to"]));
00205             if(isset($message->headers["cc"]))
00206             $ccaddr = $this->parseAddr(Mail_RFC822::parseAddressList($message->headers["cc"]));
00207             if(isset($message->headers["bcc"]))
00208             $bccaddr = $this->parseAddr(Mail_RFC822::parseAddressList($message->headers["bcc"]));
00209 
00210             // save some headers when forwarding mails (content type & transfer-encoding)
00211             $headers = "";
00212             $forward_h_ct = "";
00213             $forward_h_cte = "";
00214 
00215             $use_orgbody = false;
00216 
00217             // clean up the transmitted headers
00218             // remove default headers because we are using imap_mail
00219             $changedfrom = false;
00220             $returnPathSet = false;
00221             $body_base64 = false;
00222             $org_charset = "";
00223             foreach($message->headers as $k => $v) {
00224                 if ($k == "subject" || $k == "to" || $k == "cc" || $k == "bcc") 
00225                 continue;
00226 
00227                 if ($k == "content-type") {
00228                     // save the original content-type header for the body part when forwarding 
00229                     if ($forward) {
00230                         $forward_h_ct = $v;
00231                         continue;
00232                     }
00233 
00234                     // set charset always to utf-8
00235                     $org_charset = $v;
00236                     $v = preg_replace("/charset=([A-Za-z0-9-\"']+)/", "charset=\"utf-8\"", $v);
00237                 }
00238 
00239                 if ($k == "content-transfer-encoding") {
00240                     // if the content was base64 encoded, encode the body again when sending                
00241                     if (trim($v) == "base64") $body_base64 = true;
00242 
00243                     // save the original encoding header for the body part when forwarding 
00244                     if ($forward) {
00245                         $forward_h_cte = $v;
00246                         continue;
00247                     }
00248                 }
00249 
00250                 // if the message is a multipart message, then we should use the sent body 
00251                 if (!$forward && $k == "content-type" && preg_match("/multipart/i", $v)) {
00252                     $use_orgbody = true;
00253                 }
00254 
00255                 // check if "from"-header is set
00256                 if ($k == "from"  ) {
00257                     $changedfrom = true;
00258                     if (! trim($v) )
00259                     {
00260                         $v = $this->_email;
00261                     }
00262                 }
00263 
00264                 // check if "Return-Path"-header is set
00265                 if ($k == "return-path") {
00266                     $returnPathSet = true;
00267                     if (! trim($v) ) {
00268                         $v = $this->_email;
00269 
00270                     }
00271                 }
00272 
00273                 // all other headers stay                             
00274                 if ($headers) $headers .= "\n";
00275                 $headers .= ucfirst($k) . ": ". $v;
00276             }
00277             
00278             // set "From" header if not set on the device
00279             if( !$changedfrom){
00280                 $v = $this->_email;    
00281                 if ($headers) $headers .= "\n";
00282                 $headers .= 'From: '.$v;
00283             }
00284 
00285             // set "Return-Path" header if not set on the device
00286             if(!$returnPathSet){
00287                 $v = $this->_email;    
00288                 if ($headers) $headers .= "\n";
00289                 $headers .= 'Return-Path: '.$v;
00290             }
00291              
00292             // if this is a multipart message with a boundary, we must use the original body
00293             if ($use_orgbody) {
00294                 list(,$body) = $mobj->_splitBodyHeader($rfc822);
00295             }    
00296             else
00297             $body = $this->getBody($message);
00298 
00299             // reply                
00300             if (isset($reply) && isset($parent) &&  $reply && $parent) {
00301                 $this->imap_reopenFolder($parent);
00302                 // receive entire mail (header + body) to decode body correctly
00303                 $origmail = @imap_fetchheader($this->_mbox, $reply, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $reply, FT_PEEK | FT_UID);
00304                 $mobj2 = new Mail_mimeDecode($origmail);
00305                 // receive only body
00306                 $body .= $this->getBody($mobj2->decode(array('decode_headers' => false, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $origmail, 'crlf' => "\n", 'charset' => 'utf-8')));
00307                 // unset mimedecoder & origmail - free memory            
00308                 unset($mobj2);
00309                 unset($origmail);
00310             }
00311 
00312             // encode the body to base64 if it was sent originally in base64 by the pda 
00313             // the encoded body is included in the forward         
00314             if ($body_base64) $body = base64_encode($body);
00315 
00316 
00317             // forward                
00318             if (isset($forward) && isset($parent) && $forward && $parent) {
00319                 $this->imap_reopenFolder($parent);
00320                 // receive entire mail (header + body)
00321                 $origmail = @imap_fetchheader($this->_mbox, $forward, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $forward, FT_PEEK | FT_UID);
00322 
00323                 // build a new mime message, forward entire old mail as file
00324                 list($aheader, $body) = $this->mail_attach("forwarded_message.eml",strlen($origmail),$origmail, $body, $forward_h_ct, $forward_h_cte);
00325 
00326                 // unset origmail - free memory            
00327                 unset($origmail);
00328 
00329                 // add boundary headers
00330                 $headers .= "\n" . $aheader;
00331             }
00332             $headers .="\n";
00333             $send =  @imap_mail ( $toaddr, $message->headers["subject"], $body, $headers, $ccaddr, $bccaddr);
00334             $errors = imap_errors();
00335                 if (is_array($errors)) {
00336                     foreach ($errors as $e)    debugLog("IMAP-errors: $e");            
00337                 }             
00338             // email sent?
00339             if (!$send) {
00340                 debugLog("The email could not be sent. Last-IMAP-error: ". imap_last_error());
00341             }
00342             // add message to the sent folder
00343             // build complete headers
00344             $cheaders  = "To: " . $toaddr. "\n";
00345             $cheaders .= $headers;
00346             $asf = false;  
00347             //try to see if there are a folder with the annotation 
00348             $sent=$this->readDefaultSentItemFolder();    
00349             $body=str_replace("\n","\r\n",$body); 
00350             $cheaders=str_replace(":  ",": ",$cheaders); 
00351             $cheaders=str_replace("\n","\r\n",$cheaders); 
00352             if ($sent) {
00353                 $asf = $this->addSentMessage($sent, $cheaders, $body);
00354             }
00355             else if ($this->sentFolder) {
00356                 $asf = $this->addSentMessage($this->sentFolder, $cheaders, $body);
00357                 debugLog("IMAP-SendMail: Outgoing mail saved in configured 'Sent' folder '".$this->sentFolder."': ". (($asf)?"success":"failed"));
00358             }
00359             // No Sent folder set, try defaults
00360             else {
00361                 debugLog("IMAP-SendMail: No Sent mailbox set");
00362                 if($this->addSentMessage("INBOX/Sent", $cheaders, $body)) {
00363                     debugLog("IMAP-SendMail: Outgoing mail saved in 'INBOX/Sent'");
00364                     $asf = true;
00365                 }
00366                 else if ($this->addSentMessage("Sent", $cheaders, $body)) {
00367                     debugLog("IMAP-SendMail: Outgoing mail saved in 'Sent'");
00368                     $asf = true;
00369                 }
00370                 else if ($this->addSentMessage("Sent Items", $cheaders, $body)) {
00371                     debugLog("IMAP-SendMail: Outgoing mail saved in 'Sent Items'");
00372                     $asf = true;
00373                 }
00374             }
00375             $errors = imap_errors();
00376                 if (is_array($errors)) {
00377                     foreach ($errors as $e)    debugLog("IMAP-errors: $e");            
00378                 }             
00379             // unset mimedecoder - free memory
00380             unset($mobj);
00381             return ($send && $asf);
00382         }
00383 
00384         /* Should return a wastebasket folder if there is one. This is used when deleting
00385         * items; if this function returns a valid folder ID, then all deletes are handled
00386         * as moves and are sent to your backend as a move. If it returns FALSE, then deletes
00387         * are always handled as real deletes and will be sent to your importer as a DELETE
00388         */
00389         function GetWasteBasket() {
00390             return $this->_wasteID;
00391         }
00392         private function GetMessagesListByType($foldertype,$cutoffdate)
00393         {
00394             $lastfolder="";
00395             $messages=array();
00396             $list = @imap_getmailboxes($this->_mbox, $this->_server, "*");
00397             if (is_array($list)) {  
00398                 $list = array_reverse($list);
00399                 foreach ($list as $val) {
00400                     //$folder=imap_utf7_decode(substr($val->name, strlen($this->_server)));
00401                     $folder=substr($val->name, strlen($this->_server));
00402                     //$this->saveFolderAnnotation($folder);
00403                     $ft=$this->kolabFolderType($folder);
00404                     if ($ft !=  $foldertype)
00405                     {
00406                         continue;
00407                     }
00408                     $isUser=false;
00409                     $isShared=false;
00410                     if (substr($folder,0,4) =="user"){$isUser=true;}
00411                     if (substr($folder,0,6) =="shared"){$isShared=true;} 
00412                     $fa=$this->kolabReadFolderParam($folder);
00413                     //here we must push theo object in the cache to 
00414                     //dont have to read it again at each message ( for the alarms)
00415                     $this->CacheWriteFolderParam($folder,$fa);
00416                     $fa->setFolder($folder);
00417                     if ( ! $fa->isForSync($this->_devid))
00418                     {
00419                         //not set to sync
00420                         continue;
00421                     }
00422                     //want user namespace ?
00423                     /*
00424                     if ( !KOLAB_USERFOLDER_DIARY && $foldertype == 2 && $isUser)
00425                     {
00426                     continue;
00427                     }
00428                     if ( !KOLAB_USERFOLDER_CONTACT && $foldertype == 1 && $isUser)
00429                     {
00430                     continue;
00431                     }
00432                     //want shared namespace ?
00433                     if ( !KOLAB_SHAREDFOLDER_DIARY && $foldertype == 2 && $isShared)
00434                     {
00435                     continue;
00436                     }
00437                     if ( !KOLAB_SHAREDFOLDER_CONTACT && $foldertype == 1 && $isShared)
00438                     {
00439                     continue;
00440                     }
00441                     */
00442                     if ( $this->CacheGetDefaultFolder($foldertype) == false)
00443                     {
00444                         //no default 
00445                         if (substr($folder,0,5) == "INBOX")
00446                         {
00447                             $n=array_pop(explode("/",$folder));
00448                             $result=false;
00449                             switch($foldertype)
00450                             {
00451                                 case 1: $result=$this->isDefaultFolder($n,KOLAB_DEFAULTFOLDER_CONTACT);
00452                                 break;
00453                                 case 2: $result=$this->isDefaultFolder($n,KOLAB_DEFAULTFOLDER_DIARY);
00454                                 break;
00455                                 case 3: $result=$this->isDefaultFolder($n,KOLAB_DEFAULTFOLDER_TASK);
00456                                 break;         
00457                             }
00458                             if ( $result == true)
00459                             {
00460                                 $this->forceDefaultFolder($foldertype,$folder);
00461                             }
00462                             else 
00463                             {
00464                                 $lastfolder=$folder;
00465                             }  
00466                         }
00467                     }
00468 
00469                     $this->imap_reopenFolder($folder);
00470                     
00471                     /*trying optimizing the reads*/
00472                     /*if ($this->isFolderModified($folder) == false )
00473                     {
00474                     $this->Log("NOTICE : folder not modified $folder");
00475                     $message_folder=$this->CacheReadMessageList($folder);
00476                     if (count($message)> 0)
00477                     {
00478                     $messages=array_merge($messages,$message_folder);
00479                     continue;
00480                     }     
00481                     }   */
00482                     $overviews = @imap_fetch_overview($this->_mbox, "1:*",FT_UID);
00483                     if (!$overviews) {
00484                         debugLog("IMAP-GetMessageList: $folder Failed to retrieve overview");
00485                     } else {
00486                         $message_infolder=array(); 
00487                         foreach($overviews as $overview) {
00488                             $date = "";                
00489                             $vars = get_object_vars($overview);
00490 
00491                             if (array_key_exists( "deleted", $vars) && $overview->deleted)                
00492                             continue;
00493 
00494                             $message=$this->KolabStat($folder,$overview);
00495                             if (! $message){continue;} 
00496                             //cutoffdate for appointment 
00497                             if ( $foldertype == 2)
00498                             {
00499                                 //look for kolabuid 
00500                                 $this->Log("try cutoffdate for message id ".$message["id"]);
00501                                 $enddate= $this->CacheReadEndDate($folder,$message["id"]);
00502                                 if ($enddate != - 1 && $cutoffdate > $enddate)
00503                                 {
00504                                     //cuteoffdate
00505                                     $this->Log("cuteoffDate :" . $message["id"] ); 
00506                                     continue;
00507                                 }
00508                                 if ( substr($folder,0,5) != "INBOX")
00509                                 {
00510                                     if ($this->CacheReadSensitivity($message["id"]))
00511                                     {
00512                                         //check if private for namespace <> INBOX 
00513                                         continue;
00514                                     }
00515                                 }
00516                             }
00517                             //check if key is duplicated 
00518                             if (isset($checkId[$message["id"]]))
00519                             {
00520                                 //uid exist
00521                                 $this->Log("Key : " .$message["id"] ." duplicated folder :" . $folder ." Imap id : " . $checkId[$message["id"]]);
00522                                 debugLog("Key : " .$message["id"] ." duplicated folder :" . $folder ." Imap id : " . $checkId[$message["id"]]);
00523                                 //rewrite the index to have the good imapid 
00524                                 $id=array_pop(explode("/",$checkId[$message["id"]]));
00525                                 $this->CacheCreateIndex($folder,$message["id"],$id);  
00526                                 continue;
00527                             }
00528                             else
00529                             {
00530                                 $checkId[$message["id"]] = $message["mod"];
00531                             }
00532                             //here check the cutdate for appointments 
00533                             debugLog("ListMessage : " . $message["id"] . "->" . $message["mod"] ) ;
00534                             $messages[]=$message;
00535                             $message_infolder[]=$message;
00536                         }
00537                         $this->CacheStoreMessageList($folder,$message_infolder);
00538                     }
00539                 } 
00540                 //check if we found a default folder for this type
00541                 if ( $this->CacheGetDefaultFolder($foldertype) == false)
00542                 {
00543                     //no we pur the last folder found as default;
00544                     $this->forceDefaultFolder($foldertype,$lastfolder); 
00545                 }
00546  
00547                 unset($checkId);
00548                 unset($overviews);
00549                 return $messages;
00550             }
00551         }
00552         private function statImapFolder($folder)
00553         {
00554             $info=imap_status($this->_mbox, $this->_server .$folder, SA_ALL)  ; 
00555             return serialize($info);
00556         }
00557         /* Should return a list (array) of messages, each entry being an associative array
00558         * with the same entries as StatMessage(). This function should return stable information; ie
00559         * if nothing has changed, the items in the array must be exactly the same. The order of
00560         * the items within the array is not important though.
00561         *
00562         * The cutoffdate is a date in the past, representing the date since which items should be shown.
00563         * This cutoffdate is determined by the user's setting of getting 'Last 3 days' of e-mail, etc. If
00564         * you ignore the cutoffdate, the user will not be able to select their own cutoffdate, but all
00565         * will work OK apart from that.
00566         */
00567         function GetMessageList($folderid, $cutoffdate) 
00568         {
00569             $messages = array();
00570             $checkId = array();
00571             if ($folderid == "VIRTUAL/calendar")
00572             {
00573                 //flat mode
00574                 //search all folders of type calendar
00575                 $messages=$this->GetMessagesListByType(2,$cutoffdate);
00576 
00577             }
00578             else if ($folderid == "VIRTUAL/contacts")  
00579             {
00580                 $messages=$this->GetMessagesListByType(1,$cutoffdate);
00581             }
00582             else if ($folderid == "VIRTUAL/tasks")  
00583             {
00584                 $messages=$this->GetMessagesListByType(3,$cutoffdate);
00585             }
00586             else
00587             {
00588                 $this->imap_reopenFolder($folderid, true);
00589                 //check if the folder as moved by imap stat
00590                 /*
00591                 if ($this->isFolderModified($folderid) == false )
00592                 {
00593                 $this->Log("NOTICE : folder not modified $folderid");
00594                 $messages=$this->CacheReadMessageList($folderid);
00595                 return $messages;      
00596                 } */
00597                 $overviews = @imap_fetch_overview($this->_mbox, "1:*",FT_UID);
00598                 if (!$overviews) {
00599                     debugLog("IMAP-GetMessageList: $folderid Failed to retrieve overview");
00600                 } else {
00601                     foreach($overviews as $overview) {
00602                         $date = "";                
00603                         $vars = get_object_vars($overview);
00604                         // cut of deleted messages
00605                         if (array_key_exists( "deleted", $vars) && $overview->deleted)                
00606                         continue;
00607                         $folderType=$this->kolabFolderType($folderid);
00608                         if ( $folderType> 0)
00609                         {
00610                             //kolab contacts and appointment special index
00611                             //mode is the imap uid because kolab delete the message and recreate a newone in case
00612                             //of modification
00613                             $message=$this->KolabStat($folderid,$overview);
00614                             if (! $message){continue;} 
00615                             //cutoffdate for appointment 
00616                             if ( $folderType == 2)
00617                             {
00618                                 //look for kolabuid 
00619                                 $this->Log("try cutoffdate for message id ".$message["id"]);
00620                                 $enddate= $this->CacheReadEndDate($folderid,$message["id"]);
00621                                 if ($enddate != - 1 &&  $cutoffdate > $enddate)
00622                                 {
00623                                     //cuteoffdate
00624                                     $this->Log("cuteoffDate too old"); 
00625                                     continue;
00626                                 }
00627                                 if ( substr($folderid,0,5) != "INBOX")
00628                                 {
00629                                     if ($this->CacheReadSensitivity($message["id"]))
00630                                     {
00631                                         //check if private for namespace <> INBOX 
00632                                         continue;
00633                                     }
00634                                 }
00635                             }
00636                             //check if key is duplicated 
00637                             if (isset($checkId[$message["id"]]))
00638                             {
00639                                 $this->Log("Key : " .$message["id"] ." duplicated folder :" . $folder ." Imap id : " . $checkId[$message["id"]]);
00640                                 debugLog("Key : " .$message["id"] ." duplicated folder :" . $folder ." Imap id : " . $checkId[$message["id"]]);
00641                                 //rewrite the index to have the good imapid 
00642                                 $id=array_pop(explode("/",$checkId[$message["id"]]));
00643                                 $this->CacheCreateIndex($folder,$message["id"],$id); 
00644                                 continue; 
00645                             }
00646                             else
00647                             {
00648                                 $checkId[$message["id"]] = $message["mod"];
00649                             }
00650                             //here check the cutdate for appointments 
00651                             debugLog("ListMessage : " . $message["id"] . "->" . $message["mod"] ) ;
00652                             $messages[]=$message;
00653                         }
00654                         else
00655                         {
00656 
00657                             if (array_key_exists( "date", $vars)) {               
00658                                 // message is out of range for cutoffdate, ignore it
00659 
00660                                 if(strtotime($overview->date) < $cutoffdate) continue;
00661                                 $date = $overview->date;
00662                             }
00663                             if (array_key_exists( "uid", $vars)) 
00664                             {               
00665                                 $message = array();
00666                                 $message["mod"] = $date;
00667                                 $message["id"] = $overview->uid;
00668                                 // 'seen' aka 'read' is the only flag we want to know about
00669                                 $message["flags"] = 0;
00670                                 if(array_key_exists( "seen", $vars) && $overview->seen)
00671                                 $message["flags"] = 1; 
00672                                 array_push($messages, $message);
00673                             }
00674                         }
00675                     }
00676                 }
00677                 //clean the index before leave
00678                 $this->CacheIndexClean($messages) ;
00679                 //$this->Log("Get Message List : " . count($messages)) ;
00680                 }
00681 
00682             debugLog("MEM GetmessageList End:" . memory_get_usage())  ; 
00683             $this->CacheStoreMessageList($folderid,$messages);
00684             return $messages;
00685 
00686 
00687         }
00688         private function isFolderModified($folder)
00689         {
00690             $newstatus=@imap_status($this->_mbox,$this->_server. $folder,SA_ALL);
00691             $oldstatus=$this->CacheReadImapStatus($folder);
00692             //found the old status;
00693             //we compare
00694             if ( $oldstatus->uidnext == $newstatus->uidnext && $oldstatus->messages == $newstatus->messages)
00695             {
00696                 //the folder has not been modified 
00697                 return False;
00698             }
00699             $this->CacheStoreImapStatus($folder,$newstatus);
00700             return true;
00701         }    
00702         /* This function is analogous to GetMessageList. 
00703         *
00704         */
00705         function GetFolderList()
00706         { 
00707  
00708             if ( $this->foMode == true)
00709             {
00710                 return $this->GetFolderListFoMode();
00711             }
00712             else
00713             {
00714                 return $this->GetFolderListFlMode(); 
00715             }
00716         }
00717         private function GetFolderListFlMode()
00718         {
00719             $folders = array();      
00720             $list = @imap_getmailboxes($this->_mbox, $this->_server, "*");
00721             //add the virtual folders for contacts calendars and tasks
00722             $virtual=array("VIRTUAL/calendar","VIRTUAL/contacts","VIRTUAL/tasks");   
00723             //$virtual=array("VIRTUAL/calendar","VIRTUAL/contacts");
00724             foreach ($virtual as $v)
00725             {
00726                 $box=array();
00727                 $box["id"]=$v;
00728                 $box["mod"] =$v;
00729                 $box["flags"]=0;
00730                 $folders[]=$box;
00731             }           
00732             if (is_array($list)) {  
00733                 $list = array_reverse($list);
00734                 foreach ($list as $val) {
00735                     $box = array();
00736                     // cut off serverstring 
00737                     $box["flags"]=0;
00738                     //$box["id"] = imap_utf7_decode(substr($val->name, strlen($this->_server)));
00739                     $box["id"] =substr($val->name, strlen($this->_server));
00740                     //rerid the annotations
00741                     $this->saveFolderAnnotation($box["id"]); 
00742                     $foldertype=$this->readFolderAnnotation($box["id"]);
00743                     //if folder type > 0 escape
00744                     if ( substr($foldertype,0,5) == "event")
00745                     {
00746                         continue;
00747                     }
00748                     if ( substr($foldertype,0,7) == "contact")
00749                     {
00750                         continue;
00751                     }
00752                     if ( substr($foldertype,0,4) == "task")
00753                     {
00754                         continue;
00755                     }
00756                     //other folders (mails)
00757                     //$box["id"] = imap_utf7_encode( $box["id"]);  
00758                     $fhir = explode("/", $box["id"]);
00759                     if (count($fhir) > 1) {
00760                         $box["mod"] = imap_utf7_encode(array_pop($fhir)); // mod is last part of path
00761                         $box["parent"] = imap_utf7_encode(implode("/", $fhir)); // parent is all previous parts of path
00762                         }
00763                     else {
00764                         $box["mod"] = imap_utf7_encode($box["id"]);
00765                         $box["parent"] = "0";
00766                     }
00767 
00768                     $folders[]=$box;  
00769                 }
00770             }
00771             else {
00772                 debugLog("GetFolderList: imap_list failed: " . imap_last_error());
00773             }
00774             return $folders;   
00775         }
00776         private function GetFolderListFoMode() {
00777             $folders = array();      
00778             $list = @imap_getmailboxes($this->_mbox, $this->_server, "*");
00779             $this->hasDefaultEventFolder=false;
00780             $this->hasDefaultContactFolder=false;  
00781             $this->hasDefaultTaskFolder=false;  
00782             if (is_array($list)) {
00783 
00784                 //create the 
00785                 // reverse list to obtain folders in right order
00786                 $list = array_reverse($list);
00787                 foreach ($list as $val) {
00788                     $box = array();
00789                     // cut off serverstring 
00790                     $box["flags"]=0;
00791                     //$box["id"] = imap_utf7_decode(substr($val->name, strlen($this->_server)));
00792                     $box["id"]= substr($val->name, strlen($this->_server));
00793                     //determine the type en default folder
00794                     $isUser=false;
00795                     $isShared=false;
00796                     $isInbox=false;
00797                     //rerid the annotations
00798                     $this->saveFolderAnnotation($box["id"]); 
00799                     $foldertype=$this->readFolderAnnotation($box["id"]);
00800                     $defaultfolder = false;
00801                     //defaultfolder ? 
00802                     if ( $foldertype == "event.default")
00803                     {
00804                         $this->hasDefaultEventFolder=true;
00805                         $defaultfolder = true;
00806                     }
00807                     if ( $foldertype == "contact.default")
00808                     {
00809                         $this->hasDefaultContactFolder=true;
00810                         $defaultfolder = true;
00811                     }
00812                     if ( $foldertype == "task.default")
00813                     {
00814                         $this->hasDefaultTaskFolder=true;
00815                         $defaultfolder = true;
00816                     }
00817                     // workspace of the folder;
00818                     if (substr( $box["id"],0,6) == "shared")
00819                     {
00820                         //this is a shared folder  
00821                         $isShared=true;
00822                     }
00823 
00824                     if (substr( $box["id"],0,4) == "user")
00825                     {
00826                         //this is a User shared folder  
00827                         $isUser=true;
00828                     }
00829                     if (substr( $box["id"],0,5) == "INBOX")
00830                     {
00831                         $isInbox=true;
00832                     }
00833                     //selection of the folder depending to the setup
00834                     if (! $defaultfolder)
00835                     {
00836                                        
00837                         //test annotation
00838                         $fa=$this->kolabReadFolderParam($box["id"]);
00839                         //for later use (in getMessage)
00840 
00841                         $this->CacheWriteFolderParam($box["id"],$fa); 
00842                         $fa->setfolder($box["id"]);   
00843                         if ( ! $fa->isForSync($this->_devid))
00844                         {
00845                             //not set to sync
00846                             continue;
00847                         }
00848                     }
00849                     $this->Log("NOTICE SyncFolderList Add folder ".$box["id"]);
00850                     //$box["id"] = imap_utf7_encode( $box["id"]);
00851                     if ($isShared)
00852                     {
00853                         $fhir = explode(".", $box["id"]);
00854                         $box["mod"] = imap_utf7_encode($fhir[1]);
00855                         $box["parent"] = "shared"; 
00856                     }
00857                     elseif ($isUser)
00858                     {
00859                         $box["mod"] = imap_utf7_encode(array_pop($fhir));
00860                         $box["parent"] = "user";  
00861                     }
00862                     else
00863                     {
00864 
00865                         // explode hierarchies
00866                         $fhir = explode("/", $box["id"]);
00867                         $t=count($fhir);
00868                         if (count($fhir) > 1) {
00869                             $box["mod"] = imap_utf7_encode(array_pop($fhir)); // mod is last part of path
00870                             $box["parent"] = imap_utf7_encode(implode("/", $fhir)); // parent is all previous parts of path
00871                             }
00872                         else {
00873                             $box["mod"] = imap_utf7_encode($box["id"]);
00874                             $box["parent"] = "0";
00875                         }
00876                     }                    
00877                     $folders[]=$box;
00878                 }
00879             } 
00880             else {
00881                 debugLog("GetFolderList: imap_list failed: " . imap_last_error());
00882             }
00883             return $folders;
00884         }
00885 
00886         /* GetFolder should return an actual SyncFolder object with all the properties set. Folders
00887         * are pretty simple really, having only a type, a name, a parent and a server ID. 
00888         */
00889 
00890         function GetFolder($id) {
00891             $folder = new SyncFolder(); 
00892             $folder->serverid = $id;
00893             // explode hierarchy
00894             $fhir = explode("/", $id);
00895             if ( substr($id,0,6) == "shared")
00896             {
00897                 $parent="shared";
00898             }
00899             else
00900             {
00901                 $ftmp=$fhir;
00902                 array_pop($ftmp);
00903                 $parent=implode("/", $ftmp);
00904             }
00905             //get annotation type
00906             // compare on lowercase strings
00907             $lid = strtolower($id);
00908             $fimap=$id;
00909             if($lid == "inbox") {
00910                 $folder->parentid = "0"; // Root
00911                 $folder->displayname = "Inbox";
00912                 $folder->type = SYNC_FOLDER_TYPE_INBOX;
00913             } 
00914             // courier-imap outputs
00915             else if($lid == "inbox/drafts") {
00916                 $folder->parentid = $fhir[0];
00917                 $folder->displayname = "Drafts";
00918                 $folder->type = SYNC_FOLDER_TYPE_DRAFTS;
00919             }
00920             else if($lid == "inbox/trash") {
00921                 $folder->parentid = $fhir[0];
00922                 $folder->displayname = "Trash";
00923                 $folder->type = SYNC_FOLDER_TYPE_WASTEBASKET;
00924                 $this->_wasteID = $id;
00925             }
00926             else if($lid == "inbox/sent") {
00927                 $folder->parentid = $fhir[0];
00928                 $folder->displayname = "Sent";
00929                 $this->sentFolder=$id;
00930                 $folder->type = SYNC_FOLDER_TYPE_SENTMAIL;
00931                 $this->_sentID = $id;
00932             }
00933             // define the rest as other-folders
00934             //check if flatmode 
00935 
00936             else if ( $this->foMode == False && $id == "VIRTUAL/calendar")
00937             {
00938                 $folder->parentid ="VIRTUAL";
00939                 $folder->displayname = $id;
00940                 $folder->type = SYNC_FOLDER_TYPE_APPOINTMENT;
00941                 $this->_sentID = $id;
00942             }
00943             else if ( $this->foMode == False && $id == "VIRTUAL/contacts")
00944             {
00945                 $folder->parentid = "VIRTUAL";
00946                 $folder->displayname = "Contacts";
00947                 $folder->type = SYNC_FOLDER_TYPE_CONTACT;
00948                 $this->_sentID = $id;
00949             }
00950             else if ( $this->foMode == False && $id == "VIRTUAL/tasks")
00951             {
00952                 $folder->parentid = "VIRTUAL";
00953                 $folder->displayname = $id;
00954                 $folder->type = SYNC_FOLDER_TYPE_TASK;
00955                 $this->_sentID = $id;
00956             }
00957             else if ( $this->kolabfolderType($id) == 1)
00958             {
00959                 //contact kolab 
00960                 $folder->parentid = $parent;
00961                 $folder->displayname = $this->folderDisplayName($id);
00962                 $folder->type = $this->ActiveSyncFolderSyncType($id);  
00963                 $this->_sentID = $id;
00964 
00965             }
00966             else if ($this->kolabfolderType($id) == 2)
00967             {
00968 
00969                 // shared folder in UPPER , 
00970                 $folder->parentid = $parent;
00971                 $folder->displayname =  $this->folderDisplayName($id);  
00972                 $folder->type = $this->ActiveSyncFolderSyncType($id);
00973                 $this->_sentID = $id;
00974             }
00975             else if ($this->kolabfolderType($id) == 3)
00976             {
00977                 $folder->parentid = $parent;
00978                 $folder->displayname =  $this->folderDisplayName($id);    
00979                 $folder->type = $this->ActiveSyncFolderSyncType($id);
00980                 $this->_sentID = $id;
00981             }
00982             else {
00983                 if (count($fhir) > 1) {
00984 
00985                     $folder->displayname = windows1252_to_utf8(imap_utf7_decode(array_pop($fhir)));
00986                     $folder->parentid = implode("/", $fhir);
00987                 }
00988                 else {
00989                     $folder->displayname = windows1252_to_utf8(imap_utf7_decode($id));
00990                     $folder->parentid = "0";
00991                 }
00992                 $folder->type = SYNC_FOLDER_TYPE_OTHER;
00993             } 
00994 
00995             //advanced debugging
00996             //debugLog("IMAP-GetFolder(id: '$id') -> " . print_r($folder, 1));
00997             return $folder;
00998         }
00999 
01000         /* Return folder stats. This means you must return an associative array with the
01001         * following properties:
01002         * "id" => The server ID that will be used to identify the folder. It must be unique, and not too long
01003         *         How long exactly is not known, but try keeping it under 20 chars or so. It must be a string.
01004         * "parent" => The server ID of the parent of the folder. Same restrictions as 'id' apply.
01005         * "mod" => This is the modification signature. It is any arbitrary string which is constant as long as
01006         *          the folder has not changed. In practice this means that 'mod' can be equal to the folder name
01007         *          as this is the only thing that ever changes in folders. (the type is normally constant)
01008         */
01009         private function folderDisplayName($folder)
01010         {
01011 
01012             $f = explode("/", $folder);
01013             if (substr($f[0],0,6) == "shared" )
01014             {
01015                 // shared folder in UPPER 
01016                 $s=explode(".",$folder) ;
01017                 return strtoupper(windows1252_to_utf8(imap_utf7_decode($s[1])));
01018 
01019             }
01020             if ($f[0] == "INBOX")
01021             {
01022                 $type=$this->readFolderAnnotation($folder);
01023                 if ($type =="contact.default" || $type =="event.default" || $type =="task.default")
01024                 { 
01025                     //default folder all min lowaercase
01026 
01027                     $r=windows1252_to_utf8(imap_utf7_decode($f[1]));
01028                     return strtolower(windows1252_to_utf8(imap_utf7_decode(array_pop($f))));
01029                 }
01030                 else
01031                 {
01032                     //others    AA problem when we have sub sub folder 
01033                     //must keep the last one 
01034                     return ucfirst(windows1252_to_utf8(imap_utf7_decode(array_pop($f))));
01035                 }
01036             } 
01037             if ($f[0] == "user")
01038             {
01039                 $type=$this->readFolderAnnotation($folder);
01040                 $t=explode(".",$type);
01041 
01042                 //find the user
01043                 $fname=array_pop($f);
01044                 $r=windows1252_to_utf8(imap_utf7_decode($fname."(".$f[1].")"));
01045                 return windows1252_to_utf8($r);
01046             } 
01047         }
01048         function StatFolder($id) {
01049 
01050             $folder = $this->GetFolder($id);
01051 
01052             $stat = array();
01053             $stat["id"] = $id;
01054             $stat["parent"] = $folder->parentid;
01055             $stat["mod"] = $folder->displayname;
01056 
01057             return $stat;
01058         }
01059 
01060         /* Creates or modifies a folder
01061         * "folderid" => id of the parent folder
01062         * "oldid" => if empty -> new folder created, else folder is to be renamed
01063         * "displayname" => new folder name (to be created, or to be renamed to)
01064         * "type" => folder type, ignored in IMAP
01065         *
01066         */
01067         function ChangeFolder($folderid, $oldid, $displayname, $type){
01068             debugLog("ChangeFolder: (parent: '$folderid'  oldid: '$oldid'  displayname: '$displayname'  type: '$type')"); 
01069 
01070             // go to parent mailbox
01071             $this->imap_reopenFolder($folderid);
01072 
01073             // build name for new mailbox
01074             $newname = $this->_server . str_replace(".", $this->_serverdelimiter, $folderid) . $this->_serverdelimiter . $displayname;
01075 
01076             $csts = false;
01077             // if $id is set => rename mailbox, otherwise create
01078             if ($oldid) {
01079                 // rename doesn't work properly with IMAP
01080                 // the activesync client doesn't support a 'changing ID'
01081                 //$csts = imap_renamemailbox($this->_mbox, $this->_server . imap_utf7_encode(str_replace(".", $this->_serverdelimiter, $oldid)), $newname);
01082                 }
01083             else {
01084                 $csts = @imap_createmailbox($this->_mbox, $newname);
01085             }
01086             if ($csts) {
01087                 return $this->StatFolder($folderid . "." . $displayname);
01088             }
01089             else 
01090             return false;
01091         }
01092 
01093         /* Should return attachment data for the specified attachment. The passed attachment identifier is
01094         * the exact string that is returned in the 'AttName' property of an SyncAttachment. So, you should
01095         * encode any information you need to find the attachment in that 'attname' property.
01096         */    
01097         function GetAttachmentData($attname) {
01098             debugLog("getAttachmentDate: (attname: '$attname')");    
01099 
01100             list($folderid, $id, $part) = explode(":", $attname);
01101 
01102             $this->imap_reopenFolder($folderid);
01103             $mail = @imap_fetchheader($this->_mbox, $id, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $id, FT_PEEK | FT_UID);
01104 
01105             $mobj = new Mail_mimeDecode($mail);
01106             $message = $mobj->decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $mail, 'crlf' => "\n", 'charset' => 'utf-8'));
01107 
01108             if (isset($message->parts[$part]->body))
01109             print $message->parts[$part]->body;
01110 
01111             // unset mimedecoder & mail
01112             unset($mobj);            
01113             unset($mail);    
01114             return true;
01115         }
01116 
01117         /* StatMessage should return message stats, analogous to the folder stats (StatFolder). Entries are:
01118         * 'id'     => Server unique identifier for the message. Again, try to keep this short (under 20 chars)
01119         * 'flags'     => simply '0' for unread, '1' for read
01120         * 'mod'    => modification signature. As soon as this signature changes, the item is assumed to be completely
01121         *             changed, and will be sent to the PDA as a whole. Normally you can use something like the modification
01122         *             time for this field, which will change as soon as the contents have changed.
01123         */
01124 
01125         function StatMessage($folderid, $id) {
01126             debugLog("IMAP-StatMessage: (fid: '$folderid'  id: '$id' )");    
01127             //search the imap id 
01128             if ( $this->kolabFolderType($folderid))
01129             {
01130                 //in case of synchor app or contacts we work with kolab_uid
01131                 
01132                 if (substr($folderid,0,7) == "VIRTUAL")
01133                 {
01134                     //must find the right folder
01135                     $folderid=$this->CacheIndexUid2FolderUid($id);
01136                     debugLog("StatMessage Flmode: $id - > $folderid");
01137                     $this->Log("NOTICE StatMessage Flmode: $id - > $folderid");
01138                 }
01139                 $imap_id=$this->CacheIndexUid2Id($folderid,$id);
01140                 if ($imap_id)
01141                 {
01142                     $entry=array();
01143                     $entry["mod"]=$folderid ."/".$imap_id;
01144                     $entry["id"]=$id;
01145                     $entry["flags"] = 0;
01146                     return $entry;
01147                 }
01148                 else
01149                 {
01150                     //kolab_uid -> imap_id must be exist 
01151                     debugLog("StatMessage: Failed to retrieve imap_id from index: ". $id);      
01152                     return false;
01153                 }
01154             }
01155             //normal case for imap mails synchro 
01156 
01157             $this->imap_reopenFolder($folderid);  
01158             $overview = @imap_fetch_overview( $this->_mbox , $id , FT_UID);
01159 
01160             if (!$overview) {
01161                 debugLog("IMAP-StatMessage: Failed to retrieve overview: ". imap_last_error());
01162                 return false;
01163             } 
01164             else {
01165                 // check if variables for this overview object are available            
01166                 $vars = get_object_vars($overview[0]);
01167 
01168                 // without uid it's not a valid message
01169                 if (! array_key_exists( "uid", $vars)) return false;
01170 
01171                 $entry = array();
01172                 $entry["mod"] = (array_key_exists( "date", $vars)) ? $overview[0]->date : "";
01173                 $entry["id"] = $overview[0]->uid;
01174                 // 'seen' aka 'read' is the only flag we want to know about
01175                 $entry["flags"] = 0;
01176 
01177                 if(array_key_exists( "seen", $vars) && $overview[0]->seen)
01178                 $entry["flags"] = 1;
01179             }
01180             //advanced debugging
01181             //debugLog("IMAP-StatMessage-parsed: ". print_r($entry,1));
01182 
01183             return $entry;
01184 
01185         }
01186 
01187         /* GetMessage should return the actual SyncXXX object type. You may or may not use the '$folderid' parent folder
01188         * identifier here.
01189         * Note that mixing item types is illegal and will be blocked by the engine; ie returning an Email object in a 
01190         * Tasks folder will not do anything. The SyncXXX objects should be filled with as much information as possible, 
01191         * but at least the subject, body, to, from, etc.
01192         */
01193         function GetMessage($folderid, $id, $truncsize) {
01194             debugLog("KOLAB-GetMessage: (fid: '$folderid'  id: '$id'  truncsize: $truncsize)");
01195             // Get flags, etc  
01196   
01197             $stat = $this->StatMessage($folderid, $id);
01198             if ($stat) {  
01199                 if ( $this->kolabFolderType($folderid))
01200                 {
01201                     //get the imap_id  
01202                     $imap_id=array_pop(explode("/",$stat['mod']));
01203                     //$imap_id=$stat['mod'];
01204 
01205                     if ( substr($folderid,0,7) == "VIRTUAL")
01206                     {
01207 
01208                         $folderid=$this->CacheIndexUid2FolderUid($id);
01209                         debugLog("GetMessage Flmode: $id - > $folderid");
01210                         $this->Log("NOTICE GetMessage Flmode: $id - > $folderid");
01211                     }
01212                 }    
01213                 else
01214                 {
01215                     $imap_id=$id;
01216                 }
01217                 $this->imap_reopenFolder($folderid);
01218                 $mail = @imap_fetchheader($this->_mbox, $imap_id, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $imap_id, FT_PEEK | FT_UID);
01219 
01220                 $mobj = new Mail_mimeDecode($mail);
01221                 $message = $mobj->decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $mail, 'crlf' => "\n", 'charset' => 'utf-8'));
01222 
01223                 if ($this->kolabFolderType($folderid) == 1)
01224                 {
01225                     $output=$this->KolabReadContact($message,0);
01226                     $this->Log("Changed on Server C: $folderid /" .$id. "imap id : " .$imap_id );
01227                     $this->Log("                  : " . u2w($output->fileas));
01228                     $this->CacheCreateIndex($folderid,$id,$imap_id);
01229                     return $output;
01230                 }
01231                 elseif ($this->kolabFolderType($folderid) == 2 )
01232                 {
01233                     //bug #9 we must test if we want alarms or not
01234                     // for the moment disable it if namespace <> INBOX 
01235                     $fa=$this->CacheReadFolderParam($folderid);
01236                     $fa->setFolder($folderid)  ;
01237                     if ( $fa->showAlarm($this->_devid)) 
01238                     {   
01239                         $output=$this->KolabReadEvent($message,$id,false)   ;    //alarm must be shown
01240                         }
01241                     else
01242                     {
01243                         $output=$this->KolabReadEvent($message,$id,true)   ;  
01244                     }
01245                     $this->Log("Changed on Server A: $folderid/" .$id );
01246                     $this->Log("                  : " . u2w($output->subject));
01247                     $this->CacheCreateIndex($folderid,$id,$imap_id)   ;
01248                     $this->CacheWriteSensitivity($id,$output->sensitivity);
01249                     return $output;
01250                 }
01251                 elseif ($this->kolabFolderType($folderid) == 3 )
01252                 {   
01253                     
01254                     $output=$this->KolabReadTask($message,$id)   ;
01255                     $this->Log("Changed on Server T: $folderid /" .$id );
01256                     $this->Log("                  : " . u2w($output->subject));
01257                     $this->CacheCreateIndex($folderid,$id,$imap_id)   ;
01258                     //rewrite completion
01259                     $this->CacheWriteTaskCompleted($id,$output->completed);
01260                     $this->CacheWriteSensitivity($id,$output->sensitivity);
01261                     return $output;
01262                 }
01263                 else
01264                 {
01265                     $output = new SyncMail();
01266 
01267                     // decode body to truncate it
01268                     $body = utf8_to_windows1252($this->getBody($message));
01269                     $truncsize=2048;
01270                     if(strlen($body) > $truncsize) {
01271                         $body = substr($body, 0, $truncsize);
01272                         $output->bodytruncated = 1;
01273                     } else {
01274                         $body = $body;
01275                         $output->bodytruncated = 0;
01276                     }
01277                     $body = str_replace("\n","\r\n", windows1252_to_utf8(str_replace("\r","",$body)));
01278 
01279                     $output->bodysize = strlen($body);
01280                     $output->body = $body;
01281                     $output->datereceived = isset($message->headers["date"]) ? strtotime($message->headers["date"]) : null;
01282                     $output->displayto = isset($message->headers["to"]) ? $message->headers["to"] : null;
01283                     $output->importance = isset($message->headers["x-priority"]) ? preg_replace("/\D+/", "", $message->headers["x-priority"]) : null;
01284                     $output->messageclass = "IPM.Note";
01285                     $output->subject = isset($message->headers["subject"]) ? $message->headers["subject"] : "";
01286                     $output->read = $stat["flags"];
01287                     $output->to = isset($message->headers["to"]) ? $message->headers["to"] : null;
01288                     $output->cc = isset($message->headers["cc"]) ? $message->headers["cc"] : null;
01289                     $output->from = isset($message->headers["from"]) ? $message->headers["from"] : null;
01290                     $output->reply_to = isset($message->headers["reply-to"]) ? $message->headers["reply-to"] : null;
01291 
01292                     // Attachments are only searched in the top-level part
01293                     $n = 0;
01294                     if(isset($message->parts)) {
01295                         foreach($message->parts as $part) {
01296                             if(isset($part->disposition) && ($part->disposition == "attachment" || $part->disposition == "inline")) {
01297                                 $attachment = new SyncAttachment();
01298 
01299                                 if (isset($part->body))
01300                                 $attachment->attsize = strlen($part->body);
01301 
01302                                 if(isset($part->d_parameters['filename']))
01303                                 $attname = $part->d_parameters['filename'];
01304                                 else if(isset($part->ctype_parameters['name']))
01305                                 $attname = $part->ctype_parameters['name'];
01306                                 else if(isset($part->headers['content-description']))
01307                                 $attname = $part->headers['content-description'];
01308                                 else $attname = "unknown attachment";
01309 
01310                                 $attachment->displayname = $attname;
01311                                 $attachment->attname = $folderid . ":" . $id . ":" . $n;
01312                                 $attachment->attmethod = 1;
01313                                 $attachment->attoid = isset($part->headers['content-id']) ? $part->headers['content-id'] : "";
01314                                 array_push($output->attachments, $attachment);
01315                             }
01316                             $n++;
01317                         }
01318                     }
01319                     // unset mimedecoder & mail
01320                     unset($mobj);
01321                     unset($mail);
01322                     return $output;
01323                 }
01324             }
01325             return false;
01326         }
01327 
01328         /* This function is called when the user has requested to delete (really delete) a message. Usually
01329         * this means just unlinking the file its in or somesuch. After this call has succeeded, a call to
01330         * GetMessageList() should no longer list the message. If it does, the message will be re-sent to the PDA
01331         * as it will be seen as a 'new' item. This means that if you don't implement this function, you will
01332         * be able to delete messages on the PDA, but as soon as you sync, you'll get the item back
01333         */
01334         function DeleteMessage($folderid, $id) {
01335             debugLog("KOLAB-DeleteMessage: (fid: '$folderid'  id: '$id' )");
01336             if ( $this->kolabFolderType($folderid) >0 ) 
01337             {
01338                 if (substr($folderid,0,7) == "VIRTUAL")
01339                 {
01340                     $folderid=$this->CacheIndexUid2FolderUid($id);
01341                     debugLog("DeleteMessage Flmode: $id - > $folderid");
01342                     $this->Log("NOTICE DeleteMessage Flmode: $id - > $folderid");
01343                 }
01344 
01345                 //kolab_uid -> imap_id
01346                 $imap_id=$this->CacheIndexUid2Id($folderid,$id);
01347             }   
01348             else
01349             {
01350                 $imap_id=$id;
01351             }
01352             $this->imap_reopenFolder($folderid);
01353             $s1 = @imap_delete ($this->_mbox, $imap_id, FT_UID);
01354             $s11 = @imap_setflag_full($this->_mbox, $imap_id, "\\Deleted", FT_UID);
01355             $s2 = @imap_expunge($this->_mbox);
01356             $this->CacheIndexDeletebyId($folderid,$id);
01357             debugLog("IMAP-DeleteMessage: s-delete: $s1   s-expunge: $s2    setflag: $s11");
01358 
01359             return ($s1 && $s2 && $s11);
01360         }
01361 
01362         /* This should change the 'read' flag of a message on disk. The $flags                                                  r
01363         * parameter can only be '1' (read) or '0' (unread). After a call to
01364         * SetReadFlag(), GetMessageList() should return the message with the
01365         * new 'flags' but should not modify the 'mod' parameter. If you do
01366         * change 'mod', simply setting the message to 'read' on the PDA will trigger
01367         * a full resync of the item from the server
01368         */
01369         function SetReadFlag($folderid, $id, $flags) {
01370             debugLog("IMAP-SetReadFlag: (fid: '$folderid'  id: '$id'  flags: '$flags' )");
01371 
01372             $this->imap_reopenFolder($folderid);
01373 
01374             if ($flags == 0) {
01375                 // set as "Unseen" (unread)
01376                 $status = @imap_clearflag_full ( $this->_mbox, $id, "\\Seen", ST_UID);
01377             } else {
01378                 // set as "Seen" (read)
01379                 $status = @imap_setflag_full($this->_mbox, $id, "\\Seen",ST_UID);
01380             }
01381 
01382             debugLog("IMAP-SetReadFlag -> set as " . (($flags) ? "read" : "unread") . "-->". $status);
01383 
01384             return $status;
01385         }
01386 
01387         /* This function is called when a message has been changed on the PDA. You should parse the new
01388         * message here and save the changes to disk. The return value must be whatever would be returned
01389         * from StatMessage() after the message has been saved. This means that both the 'flags' and the 'mod'
01390         * properties of the StatMessage() item may change via ChangeMessage().
01391         * Note that this function will never be called on E-mail items as you can't change e-mail items, you
01392         * can only set them as 'read'.
01393         */
01394         function ChangeMessage($folderid, $id, $message) {
01395    
01396             $modify=false; 
01397             $this->Log("PDA Folder : " . $folderid .  "  object uid : " . $id);
01398             if (substr($folderid,0,6) == "shared" && KOLAB_SHAREDFOLDERS_RO  ==1 )
01399             {
01400                 //shared folders are protected 
01401                 $this->Log("PDA Folder : READ ONLY Cancel " . $folderid .  "  object uid : " . $id);
01402                 return false;
01403             }
01404             if ( $id != FALSE )
01405             {                                                                              
01406                 //finding the kolab_uid for this id
01407                 if ( $this->kolabFolderType($folderid)> 0)
01408                 {
01409                     if (substr($folderid,0,7) == "VIRTUAL")
01410                     {
01411                         $folderid=$this->CacheIndexUid2FolderUid($id);
01412                         debugLog("ChangeMessage Flmode: $id - > $folderid");
01413                         $this->Log("NOTICE ChangeMessage Flmode: $id - > $folderid"); 
01414                     }
01415                     //message exist on the server delete it 
01416                     $imap_id=$this->CacheIndexUid2Id($folderid,$id); 
01417                     $this->imap_reopenFolder($folderid);
01418                     $s1 = @imap_delete ($this->_mbox, $imap_id, FT_UID);
01419                     $s11 = @imap_setflag_full($this->_mbox, $imap_id, "\\Deleted", FT_UID);
01420                     $s2 = @imap_expunge($this->_mbox);
01421                     $this->Log("Change delete imap message : " . $folderid . " " . $imap_id)  ;
01422                     $kolab_uid=$id;
01423                     $modify=true;
01424                 }
01425                 else
01426                 {
01427                     //delete du mail 
01428                     $this->DeleteMessage($folderid,$id);
01429                 }
01430             }                                                                                
01431             // mail is an Array [uid,date,RFC822Message]      *
01432             if ($folderid == "VIRTUAL/calendar")
01433             {
01434                 $folderid=$this->CacheGetDefaultFolder("event");
01435             }
01436             if ($folderid == "VIRTUAL/contacts")
01437             {
01438                 $folderid=$this->CacheGetDefaultFolder("contact");
01439             }
01440             if ($folderid == "VIRTUAL/tasks")
01441             {
01442                 $folderid=$this->CacheGetDefaultFolder("task");
01443             }
01444 
01445             if ( $this->kolabFolderType($folderid) == 1)
01446             {
01447                 $mail=$this->KolabWriteContact($message,$kolab_uid);
01448 
01449             }
01450             elseif ($this->kolabFolderType($folderid) == 2)
01451             {
01452 
01453                 $mail=$this->KolabWriteEvent($message,$kolab_uid);
01454             }
01455             elseif ($this->kolabFolderType($folderid) == 3)
01456             {
01457                 $mail=$this->KolabWriteTask($message,$kolab_uid);
01458             }
01459             // now we can insert it again 
01460             $this->imap_reopenFolder($folderid);
01461             $info=imap_status($this->_mbox, $this->_server . $folderid, SA_ALL)  ;    
01462             $r=@imap_append($this->_mbox,$this->_server . $folderid,$mail[2] ,"\\Seen");
01463             $id=$info->uidnext;     
01464             if ( $r == TRUE)   
01465             {
01466                 $this->Log("create message : " . $folderid . " " . $id)  ;    
01467                 $this->CacheCreateIndex($folderid,$mail[0],$id);
01468                 if ( $this->kolabFolderType($folderid) ==2)
01469                 {
01470                     //cache the end date
01471                     $this->CacheWriteEndDate($folderid,$message) ;   
01472 
01473                 }
01474                 if ($this->kolabFolderType($folderid) == 3)
01475                 {
01476                     $this->CacheWriteTaskCompleted($id,$message->completed);
01477                     $this->CacheWriteSensitivity($id,$message->sensitivity);
01478                 }
01479                 $entry["mod"] = $folderid ."/".$id;
01480                 $entry["id"]=strtoupper($mail[0]);
01481                 $entry["flags"]=0;
01482                 return $entry;
01483             } 
01484             $this->Log("IMAP can't add mail : " . imap_last_error());
01485             return false;
01486         }
01487 
01488         /* This function is called when the user moves an item on the PDA. You should do whatever is needed
01489         * to move the message on disk. After this call, StatMessage() and GetMessageList() should show the items
01490         * to have a new parent. This means that it will disappear from GetMessageList() will not return the item
01491         * at all on the source folder, and the destination folder will show the new message
01492         *
01493         */
01494         function MoveMessage($folderid, $id, $newfolderid) {
01495             debugLog("IMAP-MoveMessage: (sfid: '$folderid'  id: '$id'  dfid: '$newfolderid' )");
01496             $this->imap_reopenFolder($folderid);
01497 
01498             // read message flags
01499             $overview = @imap_fetch_overview ( $this->_mbox , $id, FT_UID);
01500 
01501             if (!$overview) {
01502                 debugLog("IMAP-MoveMessage: Failed to retrieve overview");
01503                 return false;
01504             } 
01505             else {
01506                 // move message                    
01507                 $s1 = imap_mail_move($this->_mbox, $id, $newfolderid, FT_UID);
01508 
01509                 // delete message in from-folder
01510                 $s2 = imap_expunge($this->_mbox);
01511 
01512                 // open new folder
01513                 $this->imap_reopenFolder($newfolderid);
01514 
01515                 // remove all flags
01516                 $s3 = @imap_clearflag_full ($this->_mbox, $id, "\\Seen \\Answered \\Flagged \\Deleted \\Draft", FT_UID);
01517                 $newflags = "";
01518                 if ($overview[0]->seen) $newflags .= "\\Seen";   
01519                 if ($overview[0]->flagged) $newflags .= " \\Flagged";
01520                 if ($overview[0]->answered) $newflags .= " \\Answered";
01521                 $s4 = @imap_setflag_full ($this->_mbox, $id, $newflags, FT_UID);
01522 
01523                 debugLog("MoveMessage: (" . $folderid . "->" . $newfolderid . ") s-move: $s1   s-expunge: $s2    unset-Flags: $s3    set-Flags: $s4");
01524 
01525                 return ($s1 && $s2 && $s3 && $s4);
01526             }
01527         }
01528 
01529         // ----------------------------------------
01530         // imap-specific internals
01531 
01532         /* Parse the message and return only the plaintext body
01533         */
01534         function getBody($message) {
01535             $body = "";
01536             $htmlbody = "";
01537 
01538             $this->getBodyRecursive($message, "plain", $body);
01539 
01540             if(!isset($body) || $body === "") {
01541                 $this->getBodyRecursive($message, "html", $body);
01542                 // remove css-style tags
01543                 $body = preg_replace("/<style.*?<\/style>/is", "", $body);
01544                 // remove all other html
01545                 $body = strip_tags($body);
01546             }
01547 
01548             return $body;
01549         }
01550 
01551         // Get all parts in the message with specified type and concatenate them together, unless the
01552         // Content-Disposition is 'attachment', in which case the text is apparently an attachment
01553         function getBodyRecursive($message, $subtype, &$body) {
01554             if(!isset($message->ctype_primary)) return;
01555             if(strcasecmp($message->ctype_primary,"text")==0 && strcasecmp($message->ctype_secondary,$subtype)==0 && isset($message->body))
01556             $body .= $message->body;
01557 
01558             if(strcasecmp($message->ctype_primary,"multipart")==0 && isset($message->parts) && is_array($message->parts)) {
01559                 foreach($message->parts as $part) {
01560                     if(!isset($part->disposition) || strcasecmp($part->disposition,"attachment"))  {
01561                         $this->getBodyRecursive($part, $subtype, $body);
01562                     }
01563                 }
01564             }
01565         }
01566 
01567         // save the serverdelimiter for later folder (un)parsing
01568         function getServerDelimiter() {
01569             $list = @imap_getmailboxes($this->_mbox, $this->_server, "*");
01570             if (is_array($list)) {
01571                 $val = $list[0];    
01572 
01573                 return $val->delimiter;
01574             }        
01575             return "."; // default "."
01576             }
01577 
01578         // speed things up
01579         // remember what folder is currently open and only change if necessary
01580         function imap_reopenFolder($folderid, $force = false) {
01581             // to see changes, the folder has to be reopened!
01582             if ($this->_mboxFolder != $folderid || $force) {
01583                 $s = @imap_reopen($this->_mbox, $this->_server . $folderid);
01584                 if (!$s) debugLog("failed to change folder: ". implode(", ", imap_errors()));
01585                 $this->_mboxFolder = $folderid;
01586             }
01587         }
01588 
01589 
01590         // build a multipart email, embedding body and one file (for attachments)
01591         function mail_attach($filenm,$filesize,$file_cont,$body, $body_ct, $body_cte,$file_ct,$picture=null) {
01592 
01593             $boundary = strtoupper(md5(uniqid(time())));
01594             if ( $file_ct == "")
01595             {
01596                 $file_ct="text/plain"  ;
01597             }    
01598             $mail_header = "Content-Type: multipart/mixed; boundary=$boundary\r\n";
01599 
01600             // build main body with the sumitted type & encoding from the pda
01601             $mail_body  = "This is a multi-part message in MIME format\r\n\r\n";
01602             $mail_body .= "--$boundary\r\n";
01603             $mail_body .= "Content-Type:$body_ct\r\n";
01604             if ($body_cte != "")
01605             {
01606                 $mail_body .= "Content-Transfer-Encoding:$body_cte\r\n\r\n";
01607             }
01608             $mail_body .= "$body\r\n\r\n";
01609 
01610             $mail_body .= "--$boundary\r\n";
01611             $mail_body .= "Content-Type: ".$file_ct."; name=\"$filenm\"\r\n";
01612             $mail_body .= "Content-Transfer-Encoding: base64\r\n";
01613             $mail_body .= "Content-Disposition: attachment; filename=\"$filenm\"\r\n";
01614             $mail_body .= "Content-Description: $filenm\r\n\r\n";
01615             $mail_body .= base64_encode($file_cont) . "\r\n\r\n";
01616 
01617 
01618             if ( $picture)
01619             {
01620                 //add picture 
01621                 $mail_body .= "--$boundary\r\n";  
01622                 $mail_body .= "Content-Type: image/jpeg; name=\"photo.jpeg\"\r\n";
01623                 $mail_body .= "Content-Transfer-Encoding: base64\r\n";
01624                 $mail_body .= "Content-Disposition: attachment; filename=\"photo.jpeg\"\r\n\r\n";
01625                 $mail_body .=$picture . "\r\n\r\n";  
01626 
01627             }
01628             $mail_body .= "--$boundary--\r\n\r\n";  
01629             return array($mail_header, $mail_body);
01630         }
01631 
01632         // adds a message as seen to a specified folder (used for saving sent mails)
01633         function addSentMessage($folderid, $header, $body) {
01634             return @imap_append($this->_mbox,$this->_server . $folderid, $header . "\r\n" . $body ,"\\Seen");
01635         }
01636 
01637 
01638         // parses address objects back to a simple "," separated string
01639         function parseAddr($ad) {
01640             $addr_string = "";
01641             if (isset($ad) && is_array($ad)) {
01642                 foreach($ad as $addr) {
01643                     if ($addr_string) $addr_string .= ",";
01644                     $addr_string .= $addr->mailbox . "@" . $addr->host; 
01645                 }
01646             }
01647             return $addr_string;
01648         }
01649 
01650         private function KolabReadContact($message,$with_uid)
01651         {
01652                
01653             $contact=NULL;  
01654             $kolabXml=NULL;
01655             $images=array();
01656             if(isset($message->parts)) 
01657             {
01658                 $parts=$message->parts;
01659                 foreach($parts as $part) 
01660                 {
01661                     if(isset($part->disposition) && ($part->disposition == "attachment" || $part->disposition == "inline")) 
01662                     {
01663                         $type=$part->headers;
01664                         //kolab contact attachment ? 
01665                         $ctype=explode(";",$type["content-type"] )  ;
01666                         if ($ctype[0] == " application/x-vnd.kolab.contact")
01667                         { 
01668                             $kolabXml=$part->body;
01669                         }
01670                         if ($ctype[0] == " image/jpeg")
01671                         { 
01672                             $name=$part->ctype_parameters["name"];  
01673                             $images[$name]=$part->body;
01674                         }
01675                         $n++;
01676                     }
01677                 }
01678                 if (! $kolabXml)
01679                 {
01680                     //nothing in the mail
01681                     return "";
01682                 }
01683                 //processing
01684                 $factory=new Horde_Kolab_Format;
01685                 $format = $factory->factory('XML', 'contact');  
01686                 $kcontact=$format->load($kolabXml);
01687                 unset($format); 
01688                 unset($factory);
01689                 if ($kcontact instanceof PEAR_Error)
01690                 {
01691                     //parsing error 
01692                     debugLog("ERROR ".$kcontact->message);
01693                     debugLog("Xml kolab :     $body")  ;
01694                     $this->Log("ERROR ".$kcontact->message);
01695                     $this->Log("XML : $body")  ;   
01696                     unset($kcontact);
01697                     return ""; 
01698 
01699                 }  
01700                 //mappage
01701                 $contact=new SyncContact();   
01702                 if ( $with_uid != 0)
01703                 {
01704                     $contact->uid= hex2bin($kcontact['uid']);
01705                 }
01706                 $contact->fileas= w2u($kcontact['last-name'].", " . $kcontact['given-name']); 
01707                 $contact->firstname= w2u($kcontact['given-name'])   ;
01708                 $contact->lastname= w2u($kcontact['last-name']);
01709                 $contact->middlename=w2u($kcontact['middle-names']);
01710                 $contact->webpage=$kcontact['web-page'] ;
01711                 $contact->jobtitle=w2u($kcontact["job-title"]) ;
01712                 $contact->title=w2u($kcontact["prefix"]) ;
01713                 $contact->suffix=w2u($kcontact['suffix']);
01714                 $contact->companyname =w2u($kcontact['organization']) ;
01715                 $contact->email1address=$kcontact['emails']; 
01716                 if ( isset($kcontact["picture"]))
01717                 {
01718                     $contact->picture=base64_encode($images[$kcontact["picture"]]);
01719                     $this->CacheWritePicture($kcontact['uid'],$contact->picture);
01720                 }
01721                 if (isset($kcontact["phone-business1"]))
01722                 {
01723                     if ( $this->checkPhoneNumber($kcontact["phone-business1"]))
01724                     {
01725                         $contact->businessphonenumber=$kcontact["phone-business1"] ;
01726                     }
01727                     else
01728                     {
01729                         $this->Log("ERR: ".$contact->fileas ." ---> " . $kcontact["phone-business1"] );
01730                     }
01731                 }
01732                 if (isset($kcontact["phone-business2"]))
01733                 {
01734                     if ( $this->checkPhoneNumber($kcontact["phone-business2"]))
01735                     {
01736                         $contact->business2phonenumber=$kcontact["phone-business1"] ;
01737                     }
01738                     else
01739                     {
01740                         $this->Log("ERR: ".$contact->fileas ." ---> " . $kcontact["phone-business2"] );
01741                     }
01742                 }
01743                 if (isset($kcontact["phone-home1"]))
01744                 {
01745                     if ( $this->checkPhoneNumber($kcontact["phone-home1"]))
01746                     {
01747                         $contact->homephonenumber=$kcontact["phone-home1"] ;
01748                     }
01749                     else
01750                     {
01751                         $this->Log("ERR: ".$contact->fileas ." ---> " . $kcontact["phone-home1"] );
01752                     }
01753                 }
01754                 if (isset($kcontact["phone-mobile"]))
01755                 {
01756                     if ( $this->checkPhoneNumber($kcontact["phone-mobile"]))
01757                     {
01758                         $contact->mobilephonenumber=$kcontact["phone-mobile"] ;
01759                     }
01760                     else
01761                     {
01762                         $this->Log("ERR: ".$contact->fileas ." ---> " . $kcontact["phone-mobile"] );
01763                     }
01764                 }
01765                 if (isset($kcontact["phone-businessfax"]))
01766                 {
01767                     if ( $this->checkPhoneNumber($kcontact["phone-businessfax"]))
01768                     {
01769                         $contact->businessfaxnumber=$kcontact["phone-businessfax"] ;
01770                     }
01771                     else
01772                     {
01773                         $this->Log("ERR: ".$contact->fileas ." ---> " . $kcontact["phone-businessfax"] );
01774                     }
01775                 }
01776                 $contact->otherstreet=w2u($kcontact["addr-other-street"]);
01777                 $contact->othercity=w2u($kcontact["addr-other-locality"]);
01778                 $contact->otherpostalcode=$kcontact["addr-other-postal-code"];
01779                 $contact->otherstate=$kcontact["addr-other-region"]   ;   
01780                 $contact->othercountry=w2u($kcontact["addr-other-country"]);
01781                 $contact->businessstreet=w2u($kcontact["addr-business-street"]);
01782                 $contact->businesscity=w2u($kcontact["addr-business-locality"]);
01783                 $contact->businesspostalcode=$kcontact["addr-business-postal-code"];
01784                 $contact->businessstate=$kcontact["addr-business-region"]   ;   
01785                 $contact->businesscountry=w2u($kcontact["addr-business-country"]);
01786                 $contact->homestreet=w2u($kcontact["addr-home-street"]);
01787                 $contact->homecity=w2u($kcontact["addr-home-locality"]);
01788                 $contact->homepostalcode=$kcontact["addr-home-postal-code"];
01789                 $contact->homestate=$kcontact["addr-home-region"]   ;
01790                 $contact->homecountry=w2u($kcontact["addr-home-country"]);
01791                 $contact->body=w2u($kcontact['body'] );
01792                 $contact->spouse=w2u($kcontact['spouse-name']);
01793                 $contact->nickname=w2u($kcontact['nick-name']);
01794                 $contact->pagernumber=w2u($kcontact['phone-pager']);
01795                 $contact->assistantname=w2u($kcontact['assistant']);
01796                 $contact->department=w2u($kcontact['department']);
01797                 $contact->officelocation=w2u($kcontact{'office-location'});
01798                 if (isset($kcontact['anniversary']))
01799                 {
01800                     $contact->anniversary=$this->KolabDate2Unix($kcontact['anniversary']);
01801                 }
01802                 if (isset($kcontact['birthday']))
01803                 {     
01804                     $contact->birthday=$this->KolabDate2Unix($kcontact['birthday']);
01805                 }
01806                 if ($kcontact["children"])
01807                 {
01808                     $children=array();
01809                     $children[]= $kcontact["children"];
01810                     $contact->children=$children;
01811                 }
01812                 if ($contact->fileas == false)
01813                 {
01814                     $contact->fileas =w2u($kcontact["organization"]);
01815                 } 
01816                 if ($contact->fileas == false)
01817                 {
01818                     $contact->fileas =$kcontact["phone-mobile"];
01819                 } 
01820                 if ($contact->fileas == false)
01821                 {
01822                     $contact->fileas =$kcontact["phone-business1"];
01823                 } 
01824                 if ($contact->fileas == false)
01825                 {
01826                     $this->Log("ERR: fileAs empty" );
01827                 }
01828                 return $contact;
01829             }
01830             return ""     ;
01831         }
01832         private function checkPhoneNumber($phone)
01833         {
01834             if (preg_match( '/^[0-9,\+,\*,\#,\(,\),\s,\.\-]+$/', $phone))
01835             {
01836                 return $phone;
01837             }    
01838             return "";
01839         }
01840         private function KolabWriteContact($message,$uid)
01841         {
01842             if ( $uid == '')
01843             {
01844                 $uid =  strtoupper(md5(uniqid(time())));
01845             }
01846             $object = array(
01847             'uid' => $uid,
01848             'full-name' => u2w($message->asfile) ,
01849             'given-name' =>u2w($message->firstname),
01850             'last-name' => u2w($message->lastname),
01851             'middle-names' => u2w($message->middlename),
01852             'prefix' => u2w($message->title),
01853             'suffix' => u2w($message->suffix),
01854             'job-title' => u2w($message->jobtitle),
01855             'web-page' => $message->webpage,
01856             'emails' => $message->email1address,
01857             'phone-mobile' => $message->mobilephonenumber,
01858             'phone-business1' => $message->businessphonenumber,
01859             'phone-business2' => $message->business2phonenumber,
01860             'phone-home1' => $message->homephonenumber,
01861             'phone-pager' => $message->pagernumber,
01862             'phone-businessfax' => $message->businessfaxnumber,
01863             'addr-business-street' => u2w($message->businessstreet),
01864             'addr-business-locality' => u2w($message->businesscity),
01865             'addr-business-postal-code' => $message->businesspostalcode,
01866             'addr-business-region' => $message->businessstate,
01867             'addr-business-country' => $message->businesscountry,
01868             'addr-home-street'=> u2w($message->homestreet),
01869             'addr-home-locality'  => u2w($message->homecity)  ,
01870             'addr-home-postal-code' => $message->homepostalcode, 
01871             'addr-home-region' => $message->homesstate,  
01872             'addr-home-country' => $message->homecountry,  
01873             'addr-other-street'=> u2w($message->otherstreet),
01874             'addr-other-locality'  => u2w($message->othercity)  ,
01875             'addr-other-postal-code' => $message->otherpostalcode, 
01876             'addr-other-region' => $message->othersstate,  
01877             'addr-other-country' => $message->othercountry,              
01878             'organization' => u2w($message->companyname) ,
01879             'department' => u2w($message->department),  
01880             'spouse-name'=> u2w($message->spouse),
01881             'children' =>u2w($message->children),
01882             'nick-name'=> u2w($message->nickname),
01883             'assistant' => u2w($message->assistantname),
01884             'department' => u2w($message->department) ,
01885             'office-location' => u2w($message->officelocation)
01886             );
01887             if ($message->body != "")
01888             {
01889                 $object['body']=u2w($message->body);
01890             }
01891             elseif ($message->rtf)
01892             {
01893                 $object['body']=$this->rtf2text($message->rtf);
01894             }
01895             //bithday
01896             if (  isset($message->anniversary))
01897             {
01898                 $object['anniversary'] =substr($this->KolabDateUnix2Kolab($message->anniversary),0,10);
01899             }
01900             if (  isset($message->birthday))
01901             {
01902                 $object['birthday']  = substr($this->KolabDateUnix2Kolab($message->birthday),0,10);
01903             }
01904             //children
01905             $children=$message->children;
01906             if ($children != NULL)
01907             {
01908                 $object['children']=join(",",$children);
01909             }
01910             //picture 
01911             if ( is_null($message->picture) )
01912             {
01913                 //no image or not modified
01914                 //check if picture has been modified 
01915                 $message->picture=$this->CacheReadPicture($uid);
01916                 if ($message->picture)
01917                 {
01918                     $object['picture'] ="photo.jpeg";   
01919                 }
01920             }
01921             else
01922             {
01923                 if ( $message->picture == "")
01924                 {
01925                     //erase the picture
01926                     $this->CacheDeletePicture($uid);      
01927                 }
01928                 else
01929                 {
01930                     $object['picture'] ="photo.jpeg";   
01931                     $this->CacheWritePicture($uid,$message->picture);
01932                 }
01933             }
01934 
01935             //check mail for android
01936             if (preg_match("/<(.+)>/",$object['emails'],$m))
01937             {
01938                 $object['emails']=$m[1];
01939             }
01940             //fulname empty    (happen sometimes with iphone)
01941             if ( $object['full-name'] == "")
01942             {
01943                 $object['full-name']= $object['given-name']. ' ' . $object['last-name'];
01944             }
01945             $format = Horde_Kolab_Format::factory('XML', 'contact');  
01946             $xml = $format->save($object);
01947             unset($format);
01948             // set the mail 
01949             // attach the XML file 
01950             $mail=$this->mail_attach("kolab.xml",0,$xml,"kolab message","text/plain", "plain","application/x-vnd.kolab.contact",$message->picture); 
01951             //add the picture if needed
01952             //add header
01953             $h["from"]=$this->_email;
01954             $h["to"]=$this->_email; 
01955             $h["X-Mailer"]="z-push-Kolab Backend";
01956             $h["subject"]= $object["uid"];
01957             $h["message-id"]= "<" . strtoupper(md5(uniqid(time()))) . ">";
01958             $h["date"]=date(DATE_RFC2822);
01959             foreach(array_keys($h) as $i)
01960             {
01961                 $header= $header . $i . ": " . $h[$i] ."\r\n";
01962             }
01963             //return the mail formatted
01964             return array($uid,$h['date'],$header  .$mail[0]."\r\n" .$mail[1]);
01965 
01966         }
01967 
01968         private function KolabReadEvent($message,$id,$disableAlarm=false)
01969         {
01970             $event=NULL; 
01971             //searching the righ attachment Kolab XML 
01972             if(isset($message->parts)) 
01973             {
01974                 foreach($message->parts as $part) 
01975                 {
01976                     if(isset($part->disposition) && ($part->disposition == "attachment" || $part->disposition == "inline")) 
01977                     {
01978                         $type=$part->headers;
01979                         //kolab contact attachment ? 
01980                         $ctype=explode(";",$type["content-type"] )  ;
01981                         if ($ctype[0] == " application/x-vnd.kolab.event")
01982                         {
01983                             $format = Horde_Kolab_Format::factory('XML', 'event');  
01984                             $body=$part->body;  
01985                             $kevent=$format->load($body); 
01986                             unset($format);
01987                             if ($kevent instanceof PEAR_Error)
01988                             {
01989                                 //parsing error 
01990                                 debugLog("ERROR ".$kevent->message);
01991                                 debugLog("Xml kolab :     $body")  ;
01992                                 $this->Log("ERROR ".$kevent->message);
01993                                 $this->Log("XML : $body")  ;
01994                                 unset ($kevent);  
01995                                 return "";
01996                             }
01997 
01998                             //mappage
01999                             $event=new SyncAppointment();
02000                             $event->uid = hex2bin($kevent['uid']);
02001                             $event->dtstamp = time();
02002                             $event->subject=w2u($kevent['summary']);
02003                             $event->starttime=$kevent['start-date'];
02004                             $event->endtime=$kevent['end-date'];
02005 
02006                             switch(strtolower($kevent['sensitivity']))
02007                             {
02008                                 case "private":
02009                                 $event->sensitivity="2";
02010                                 break;
02011                                 case "confidential":
02012                                 $event->sensitivity="3"; 
02013                             }
02014                             //bug #9 Alarm mus not be shown for all folders
02015                             if ($disableAlarm == false)
02016                             {
02017                                 if ($kevent['alarm'] > 0)
02018                                 {
02019                                     $event->reminder=$kevent['alarm'];
02020                                 }
02021                             }
02022                             else
02023                             {
02024                                 $event->reminder=NULL;
02025                             }
02026                             $event->location=w2u($kevent['location']);
02027                             $event->busystatus="2";
02028                             if ($kevent['show-time-as'] == 'busy' )
02029                             {
02030                                 $event->busystatus="2";
02031                             }
02032                             elseif ($kevent['show-time-as'] == 'free')
02033                             {
02034                                 $event->busystatus="0"; 
02035                             }
02036                             elseif ($kevent['show-time-as'] == 'tentative')
02037                             {
02038                                 $event->busystatus="1"; 
02039                             }
02040                             elseif ($kevent['show-time-as'] == 'outofoffice')
02041                             {
02042                                 $event->busystatus="3"; 
02043                             } 
02044                             $event->body=w2u($kevent['body']);
02045                             //sensitivity 
02046                             $event->meetingstatus="0";
02047                             $event->alldayevent="0";
02048                             //timezone must be fixed
02049                             $event->timezone="xP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAIAAAAAAAAAxP///w==" ;
02050                             $event->bodytruncated = 0;  
02051                             if (isset($kevent["organizer"]["smtp-address"]))
02052                             { 
02053                                 $event->organizername=w2u($kevent["organizer"]["display-name"]);
02054                                 $event->organizeremail=w2u($kevent["organizer"]["smtp-address"]);
02055                             }
02056                             else
02057                             { 
02058                                 $event->organizername=w2u($this->_cn);
02059                                 $event->organizeremail=w2u($this->_email);
02060                             }
02061 
02062                             //reccurence process
02063                             if (isset($kevent["recurrence"]))
02064                             {
02065                                 $event->reccurence=$this->kolabReadRecurrence($kevent);
02066                             }
02067                             return $event;
02068                         }
02069                         $n++;
02070                     }
02071                 }
02072             }
02073             return ""     ;
02074 
02075         }
02076         private function kolabReadRecurrence($kevent,$type=0)
02077         {
02078             $numMonth=array(
02079             "january"   => 1,
02080             "february"  => 2,
02081             "march"     => 3,
02082             "april"     => 4,
02083             "may"       => 5,
02084             "june"      => 6,
02085             "july"      => 7,
02086             "august"    => 8,
02087             "september" => 9,
02088             "october"   => 10,
02089             "november"  => 11,
02090             "december"  => 12
02091             );
02092             if (isset($kevent["recurrence"]))
02093             {
02094                 if ($type == 0)
02095                 {
02096                     $recurrence = new SyncRecurrence;
02097                 }
02098                 else
02099                 {
02100                     $recurrence= new SyncTaskRecurrence;
02101                 } 
02102                 $rec=$kevent["recurrence"];
02103                 //cycle
02104                 if ($rec["cycle"] == "daily")
02105                 {
02106                     $recurrence->type =  0 ;
02107                 }
02108                 elseif($rec["cycle"] == "weekly")
02109                 {
02110                     $recurrence->type =  1 ;
02111                     //dayofweek
02112                     //tableau jour 1=sunday 128 =saturday 
02113                     $nday=0;
02114                     $recurrence->dayofweek=$this->KolabDofW2pda($rec["day"]);
02115                 }  
02116                 elseif($rec["cycle"] == "monthly")  
02117                 {
02118 
02119                     // sous type by day 
02120                     if ($rec["type"] == "daynumber")
02121                     {
02122                         $recurrence->type =  2 ;    
02123                         $recurrence->dayofmonth =   $rec["daynumber"] ;
02124                     } 
02125                     elseif ($rec["type"] == "weekday") 
02126                     {
02127                         $recurrence->type =  3 ;        
02128                         $recurrence->weekofmonth = $rec["daynumber"];
02129                         //day of week 
02130                         $recurrence->dayofweek=$this->KolabDofW2pda($rec["day"]); 
02131                     }       
02132                 }
02133                 // year
02134                 elseif($rec["cycle"] == "yearly")   
02135                 {
02136                     if ($rec["type"] == "monthday")
02137                     {
02138 
02139                         $recurrence->type =5   ;  
02140                         $recurrence->dayofmonth =   $rec["daynumber"] ;
02141                         $recurrence->monthofyear= $numMonth[$rec["month"]];
02142                     }
02143                     elseif ($rec["type"] == "weekday")
02144                     {
02145                         $recurrence->type =6   ;  
02146                         $recurrence->weekofmonth = $rec["daynumber"];
02147                         $recurrence->monthofyear= $numMonth[$rec["month"]];
02148                         $recurrence->dayofweek=$this->KolabDofW2pda($rec["day"]); 
02149                     }
02150                 }
02151                 //interval
02152                 $recurrence->interval = $rec["interval"] ;
02153                 //range
02154                 if ($rec["range-type"] == "number")
02155                 {
02156                     $recurrence->occurrences =$rec["range"];
02157                 }  
02158                 elseif ($rec["range-type"] == "date") 
02159                 {
02160                     if ( strtolower($_GET["DeviceType"]) == "iphone")     
02161                     {
02162                         $recurrence->until =$rec["range"] + 93599;
02163                     }
02164                     else
02165                     {
02166                         $recurrence->until =$rec["range"];
02167                     }
02168 
02169                 }    
02170 
02171                 return $recurrence;
02172             }
02173             else
02174             {
02175                 return NULL;
02176             }
02177         }
02178         private function KolabWriteEvent($message,$uid)
02179         {  
02180 
02181 
02182             $attendee = array(
02183             'display-name'  => $this->_cn,
02184             'smtp-address'  => $this->_email,
02185             'uid'           => ""  
02186             );
02187             $object = array(
02188             'uid' => bin2hex($message->uid),
02189             'start-date' => $message->starttime,
02190             'end-date'   => $message->endtime,
02191             'summary'   => u2w($message->subject),
02192             'reminder'  => $message->reminder,
02193             'location'  => $message->location,
02194             'alarm' => $message->reminder,
02195             'color-label' => "none"    ,
02196             'show-time-as' => "busy",
02197             'organizer' => $attendee,
02198             'location' => u2w($message->location)
02199             );
02200             if ($message->body != "")
02201             {
02202                 $object['body']=u2w($message->body);
02203             }
02204             elseif ($message->rtf)
02205             {
02206                 $object['body']=$this->rtf2text($message->rtf);
02207             }
02208             if ($message->alldayevent == 1)
02209             {
02210                 $object['_is_all_day']=True;
02211             }
02212             switch($message->busystatus )
02213             {
02214                 case 0:
02215                 $object['show-time-as'] = "free";
02216                 break;
02217                 case 1:
02218                 $object['show-time-as'] = "tentative";
02219                 break;
02220                 case 2:
02221                 $object['show-time-as'] = "busy";
02222                 break;
02223                 case 3:
02224                 $object['show-time-as'] = "outofoffice";
02225                 break;
02226 
02227             }
02228             switch($message->sensitivity)
02229             {
02230                 case 1:
02231                 case 2: 
02232                 $object["sensitivity"] = "private";
02233                 break;
02234                 case 3:
02235                 $object["sensitivity"] = "confidential";
02236             }
02237 
02238             //recurence
02239             if(isset($message->recurrence)) 
02240             {
02241                 $object["recurrence"]=$this->kolabWriteReccurence($message->reccurence);
02242             }
02243             $format = Horde_Kolab_Format::factory('XML', 'event');  
02244             $xml = $format->save($object);
02245             unset($format);
02246             // set the mail 
02247             // attach the XML file 
02248             $mail=$this->mail_attach("kolab.xml",0,$xml,"kolab message","text/plain", "plain","application/x-vnd.kolab.event"); 
02249             //add header
02250             $h["from"]=$this->_email;
02251             $h["to"]=$this->_email; 
02252             $h["X-Mailer"]="z-push-Kolab Backend";
02253             $h["subject"]= $object["uid"];
02254             $h["message-id"]= "<" . strtoupper(md5(uniqid(time()))) . ">";
02255             $h["date"]=date(DATE_RFC2822);
02256             foreach(array_keys($h) as $i)
02257             {
02258                 $header= $header . $i . ": " . $h[$i] ."\r\n";
02259             }
02260             //return the mail formatted
02261             return array($object['uid'],$h['date'],$header  .$mail[0]."\r\n" .$mail[1]);
02262 
02263         }
02264         private function kolabWriteReccurence($reccurence)
02265         {
02266             $month=array("dummy","january","february","march","april","may","june","july","august","september","october","november","december");
02267             $rec=array();
02268             switch($recurrence->type) 
02269             {
02270                 case 0:
02271                 //repeat daily 
02272                 $rec["cycle"] = "daily";
02273                 break;
02274                 case 1:
02275                 //repeat weekly 
02276                 $rec["cycle"] = "weekly";  
02277                 $rec["day"] = $this->KolabPda2DofW($recurrence->dayofweek );
02278                 break;
02279                 case 2:
02280                 //montly daynumber
02281                 $rec["cycle"] = "monthly";
02282                 $rec["type"] ="daynumber";
02283                 $rec["daynumber"] =$recurrence->dayofmonth  ;
02284                 break;
02285                 case 3:
02286                 //monthly day of week
02287                 $rec["cycle"] = "monthly";
02288                 $rec["type"] ="weekday";
02289                 $rec["daynumber"] =$recurrence->weekofmonth  ;
02290                 $rec["day"] = $this->KolabPda2DofW($recurrence->dayofweek ); 
02291                 break;  
02292                 case 5:
02293                 //yearly 
02294                 $rec["cycle"] = "yearly";
02295                 $rec["type"] ="monthday";
02296                 $rec["daynumber"] =$recurrence->dayofmonth  ;
02297                 $rec["month"]=$month[$recurrence->monthofyear];
02298                 break;  
02299                 //   
02300                 case 6:
02301                 //yearly 
02302                 $rec["cycle"] = "yearly";
02303                 $rec["type"] ="weekday";
02304                 $rec["daynumber"] =$recurrence->weekofmonth  ;
02305                 $rec["month"]=$month[$recurrence->monthofyear];
02306                 $rec["day"] = $this->KolabPda2DofW($recurrence->dayofweek ); 
02307                 break;  
02308             }
02309             //interval
02310             if (isset($recurrence->interval))
02311             {
02312                 $rec["interval"] = $recurrence->interval;
02313             }
02314             else
02315             {
02316                 $rec["interval"] = 1;
02317             }
02318             if (isset($recurrence->occurrences))
02319             {
02320                 //by ocurence
02321                 $rec["range-type"] = "number";
02322                 $rec["range"] =$recurrence->occurrences;
02323             }
02324             elseif (isset($recurrence->until))
02325             {
02326                 //by end date
02327                 $rec["range-type"] = "date";
02328                 if ( strtolower($_GET["DeviceType"]) == "iphone" || strtolower($_GET["DeviceType"]) == "ipod")
02329                 {
02330                     $rec["range"] =$recurrence->until  - 93599 ; 
02331                 }
02332                 else
02333                 {
02334                     $rec["range"] =$recurrence->until;
02335                 }
02336             } 
02337             else
02338             {
02339                 $rec["range-type"] ="none";
02340             }
02341             return $rec;   
02342         } 
02343         private function KolabReadTask($message,$id,$disableAlarm=false,$with_uid=false)
02344         {
02345             $task=NULL; 
02346             
02347             if(isset($message->parts)) 
02348             {
02349                 foreach($message->parts as $part) 
02350                 {
02351                     if(isset($part->disposition) && ($part->disposition == "attachment" || $part->disposition == "inline")) 
02352                     {
02353                         $type=$part->headers;
02354                         //kolab contact attachment ? 
02355                         $ctype=explode(";",$type["content-type"] )  ;
02356                         if ($ctype[0] == " application/x-vnd.kolab.task")
02357                         {
02358                             $format = Horde_Kolab_Format::factory('XML', 'task');  
02359                             $body=$part->body;  
02360                             $ktask=$format->load($body); 
02361                             unset($format);
02362                             if ($ktask instanceof PEAR_Error)
02363                             {
02364                                 //parsing error 
02365                                 debugLog("ERROR ".$ktask->message);
02366                                 debugLog("Xml kolab :     $body")  ;
02367                                 $this->Log("ERROR ".$ktask->message);
02368                                 $this->Log("XML : $body")  ;
02369                                 unset ($ktask);  
02370                                 return "";
02371                             }
02372 
02373                             //mappage
02374                             $task=new SyncTask();
02375                             if ( $with_uid != 0)
02376                             {
02377                                 $task->uid= hex2bin($ktask['uid']);
02378                             }
02379                             $task->subject=w2u($ktask['name']);
02380                             if ($ktask['start'])
02381                             {
02382                                 $offset=date('Z',$ktask['start']);
02383                                 $task->utcstartdate=$kstart['start'];
02384                                 $task->startdate=$ktask['start'] + $offset;
02385                             }
02386                             if($ktask['due'])
02387                             {
02388                                 $offset=date('Z',$ktask['due']);
02389                                 $task->utcduedate=$ktask['due'];
02390                                 $task->duedate=$ktask['due'] + $offset;
02391                             }    
02392                             $task->complete=$ktask['completed'];
02393                             if (isset($ktask['completed_date']))
02394                             {
02395                                 $task->datecompleted=$ktask['completed_date'];
02396                             }
02397                             //categories
02398                             if (isset($ktask['categories']))
02399                             {
02400                                 $cat=split(',',w2u($ktask['categories']));
02401                                 $task->categories=$cat;
02402                             }
02403                             switch($ktask['priority'])
02404                             {
02405                                 case 1: $task->importance= 2;
02406                                 break;
02407                                 case 2:
02408                                 case 3:
02409                                 case 4: $task->importance=1;
02410                                 break;
02411                                 case 5: $task->importance=0; 
02412                             }
02413                             switch(strtolower($ktask['sensitivity']))
02414                             {
02415                                 case "public":
02416                                 $task->sensitivity=0;
02417                                 break;
02418                                 case "private":
02419                                 $task->sensitivity=2;
02420                                 break;
02421                                 case "confidential":
02422                                 $task->sensitivity=3; 
02423                             }
02424                             //bug #9 Alarm mus not be shown for all folders
02425                             if ($disableAlarm == false)
02426                             {
02427                                 if ($ktask['alarm'] > 0)
02428                                 {
02429                                     $task->remindertime=$ktask["start"] +($ktask['alarm'] * 60);
02430                                     $task->reminderset=1;
02431                                 }
02432                             }
02433                             else
02434                             {
02435                                 $task->reminderset=NULL;
02436                                 $task->remindertime=NULL;
02437                             }
02438                             $task->body=w2u($ktask['body']);
02439                             //timezone must be fixed
02440                             $task->bodytruncated = 0;  
02441                             //reccurence process
02442                             if (isset($ktask["recurrence"]))
02443                             {
02444                                 $task->reccurence=$this->kolabReadRecurrence($ktask,1);
02445                             }
02446                             return $task;
02447                         }
02448                         $n++;
02449                     }
02450                 }
02451             }
02452             return ""     ;
02453 
02454         }
02455         private function KolabWriteTask($message,$id)
02456         {
02457             
02458             if ( ! $id )
02459             {
02460                 $uid=strtoupper(md5(uniqid(time())));
02461             }
02462             else 
02463             {
02464                 $uid=$id;
02465             }
02466             $object = array(
02467             'uid' => $uid,
02468             'start' => $message->utcstartdate,
02469             'due'   => $message->utcduedate,
02470             'name'   => u2w($message->subject),
02471             );
02472             if (isset($message->rtf))
02473             {
02474                 $object['body']=$this->rtf2text($message->rtf);                  
02475             }
02476             if ($message->reminderset == 1)
02477             {
02478                 $object['alarm']=($message->remindertime - $message->utcstartdate) / 60; 
02479             }
02480             //categories
02481             if (isset($message->categories))
02482             {
02483                 $object['categories']=u2w(join(',',$message->categories));
02484             }
02485             switch($message->importance)
02486             {
02487                 case 0: $object["priority"] = 5;
02488                 break;
02489                 case 1: $object["priority"] = 3;
02490                 break;      
02491                 case 2: $object["priority"] = 1;
02492                 break;                 
02493             }
02494             if ( $message->complete == 1)
02495             {
02496                 $object['completed'] = 100;
02497                 $object['completed_date'] = $message->datecompleted;
02498             }
02499             else
02500             {
02501                 $object['completed'] = 0;
02502             }
02503             switch($message->sensitivity)
02504             {
02505                 case 1:
02506                 case 2: 
02507                 $object["sensitivity"] = "private";
02508                 break;
02509                 case 3:
02510                 $object["sensitivity"] = "confidential";
02511             }
02512 
02513             //recurence
02514             if(isset($message->recurrence)) 
02515             {
02516                 $object["recurrence"]=$this->kolabWriteReccurence($message->reccurence);
02517             }
02518             $format = Horde_Kolab_Format::factory('XML', 'task');  
02519             $xml = $format->save($object);
02520             unset($format);
02521             // set the mail 
02522             // attach the XML file 
02523             $mail=$this->mail_attach("kolab.xml",0,$xml,"kolab message","text/plain", "plain","application/x-vnd.kolab.task"); 
02524             //add header
02525             $h["from"]=$this->_email;
02526             $h["to"]=$this->_email; 
02527             $h["X-Mailer"]="z-push-Kolab Backend";
02528             $h["subject"]= $object["uid"];
02529             $h["message-id"]= "<" . strtoupper(md5(uniqid(time()))) . ">";
02530             $h["date"]=date(DATE_RFC2822);
02531             foreach(array_keys($h) as $i)
02532             {
02533                 $header= $header . $i . ": " . $h[$i] ."\r\n";
02534             }
02535             //return the mail formatted
02536             return array($object['uid'],$h['date'],$header  .$mail[0]."\r\n" .$mail[1]);
02537 
02538         }
02539         //return the date for Kolab
02540         private function KolabDateUnix2Kolab($timestamp)
02541         {
02542             $d=date(DATE_W3C ,$timestamp);
02543             $d=substr($d,0,19) . "Z"  ;
02544             return $d;
02545         }
02546         private function KolabDate2Unix($kdate)
02547         {
02548             if (! $kdate)
02549             {
02550                 return NULL;
02551             }
02552             else
02553             {
02554                 $tm= gmmktime(0, 0, 0, substr($kdate,5,2), substr($kdate,8,2), substr($kdate,0,4)); 
02555                 return $tm;
02556             }
02557         }
02558         /*CacheCreateIndex : create an index to retrieve easly the uid-> id and the id->uid 
02559         */
02560         private function CacheCreateIndex($folderid,$kolab_uid,$imap_uid)
02561         {
02562 
02563             $kolab_uid=strtoupper($kolab_uid);
02564             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);
02565             $this->_cache->write("IMAP:".$folderid."/".$imap_uid,$kolab_uid);
02566             $this->_cache->write("KOLAB:".$folderid."/".$kolab_uid,$imap_uid);
02567             //must another index to find the folder of the uid
02568             $this->_cache->write("FLMODE:".$kolab_uid, $folderid); 
02569             $this->_cache->close();
02570         }
02571         private function CacheIndexUid2FolderUid($uid)
02572         {
02573             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); 
02574             $result= $this->_cache->find("FLMODE:".$uid);
02575             $this->_cache->close();
02576             return $result; 
02577         }
02578         private function CacheStoreMessageList($folder,$mlist)
02579         {
02580             $stat=serialize($mlist);
02581             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);
02582             $this->_cache->write("MLIST:".$folder,$stat);
02583             $this->_cache->close(); 
02584         }
02585         private function CacheReadMessageList($folder)
02586         {
02587             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); 
02588             $result= $this->_cache->find("MLIST:".$folder);
02589             $this->_cache->close();
02590             return unserialize($result); 
02591         }
02592         private function CacheStoreImapStatus($folder,$stat)
02593         {
02594 
02595             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);
02596             $this->_cache->write("FIMAPSTAT:".$folder,serialize($stat));
02597             $this->_cache->close();
02598         }
02599         private function CacheReadImapStatus($folder)
02600         {
02601             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); 
02602             $result= $this->_cache->find("FIMAPSTAT:".$folder);
02603             $this->_cache->close();
02604             return unserialize($result); 
02605         }
02606         private function CacheIndexId2Uid($folderid,$id)
02607         {
02608             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); 
02609             $result= $this->_cache->find("IMAP:".$folderid."/".$id);
02610             $this->_cache->close();
02611             return $result;
02612         }
02613         private function CacheIndexUid2Id($folderid,$uid)
02614         {
02615             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);  
02616             $result= $this->_cache->find("KOLAB:".$folderid."/".$uid);
02617             $this->_cache->close();
02618             return $result;
02619         }
02620         private function CacheIndexDeletebyId($folderid,$id)
02621         {
02622 
02623             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);  
02624             $uid= $this->_cache->find("IMAP:".$folderid."/".$id);
02625             $this->_cache->delete("IMAP:".$folderid."/".$id);
02626             $this->_cache->delete("KOLAB:".$folderid."/".$uid);
02627             $this->_cache->delete("ENDDATE:".$folderid."/".$uid);   
02628             $this->_cache->delete("FLMODE:".$uid); 
02629             $this->_cache->close();
02630             return $result;
02631         }
02632         private function CacheCheckVersion()
02633         {
02634 
02635             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); 
02636             $version= $this->_cache->find("CACHEVERSION"); 
02637             if ( $version != KOLABBACKEND_VERSION)
02638             {
02639                 //reinit cache
02640                 $this->_cache->close();
02641                 $this->_cache->purge();
02642                 $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);   
02643                 $this->_cache->write("CACHEVERSION",KOLABBACKEND_VERSION);
02644             } 
02645             $this->_cache->close();     
02646         }
02647         private function CacheIndexClean($messagelist)
02648         {
02649             return;
02650         }
02651         private function CacheWriteFolderParam($folder,$fa)
02652         {
02653             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);
02654             $this->_cache->write("FOLDERPARAM:".$folder,$fa->serialize());
02655             $this->_cache->close();
02656         }
02657         private function CacheReadFolderParam($folder)
02658         {
02659             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); 
02660             $result= $this->_cache->find("FOLDERPARAM:".$folder);
02661             $this->_cache->close();
02662             $fa=new folderParam();
02663             $fa->unserialize($result);
02664             return $fa; 
02665         }
02666         private function KolabgetMail($username)
02667         {
02668             return  $username . "@localhost.localdomain";
02669         }
02670         private function KolabDofW2pda($recday)
02671         {
02672             foreach ($recday as $day)
02673             {
02674                 if($day == "sunday")
02675                 {
02676                     $nday=$nday +1;
02677                 }
02678                 elseif ($day == "monday")
02679                 {
02680                     $nday=$nday +2; 
02681                 }
02682                 elseif ($day == "tuesday")
02683                 {
02684                     $nday=$nday + 4; 
02685                 }
02686                 elseif ($day == "wednesday")
02687                 {
02688                     $nday=$nday + 8; 
02689                 }
02690                 elseif ($day == "thursday")
02691                 {
02692                     $nday=$nday + 16; 
02693                 }
02694                 elseif ($day == "friday")
02695                 {
02696                     $nday=$nday + 32; 
02697                 }
02698                 elseif ($day == "saturday")
02699                 {
02700                     $nday=$nday + 64; 
02701                 }                           
02702             }
02703             return $nday;
02704 
02705         }
02706         private function KolabPda2DofW($value)
02707         {
02708             $days=array();
02709             $test = $value & 8;
02710             $value=$value *1; //conversion in long ...
02711             if ( ($value & 1) >0){$days[]="sunday";}   
02712             if ( ($value & 2) >0){$days[]="monday";}
02713             if ( ($value & 4) >0){$days[]="tuesday";}     
02714             if ( ($value & 8) >0)
02715             {
02716                 $days[]="wednesday";
02717             }     
02718             if ( ($value & 16) >0){$days[]="thursday";}     
02719             if ( ($value & 32) >0){$days[]="friday";}     
02720             if ( ($value & 64) >0){$days[]="saturday";}     
02721             return $days ;     
02722         }  
02723         private function Log($message) {
02724             if (KOLAB_LOGFILE != ""  )
02725             {
02726                 @$fp = fopen(KOLAB_LOGFILE ,"a+");
02727                 @$date = strftime("%x %X");
02728                 @fwrite($fp, "$date [". getmypid() ."] : " . $this->_username . " : $message\n");
02729                 @fclose($fp);
02730             }
02731         }
02732         private function KolabStat($fid,$o)
02733         {
02734 
02735             if ( !$o)
02736             {
02737                 return false;
02738             }
02739             $kolab_uid="";
02740             $m= array();
02741             $m["mod"] = $fid .'/'.$o->uid;
02742             //search the kolab uid in index if nofound read the mail to find it 
02743             $kolab_uid=$this->CacheIndexId2Uid($fid,$o->uid);
02744             if (! $kolab_uid)
02745             {
02746                 //no found read the message 
02747                 $mail = @imap_fetchheader($this->_mbox, $o->uid, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $o->uid, FT_PEEK | FT_UID);
02748                 $mobj = new Mail_mimeDecode($mail);
02749                 $message = $mobj->decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $mail, 'crlf' => "\n", 'charset' => 'utf-8'));
02750                 if ($this->kolabFolderType($fid) == 2)
02751                 {
02752 
02753                     $ev=$this->KolabReadEvent($message,false) ;
02754                     if (! $ev)
02755                     {
02756                         return false ;
02757                     }
02758                     $kolab_uid=strtoupper(bin2hex($ev->uid));
02759 
02760                     //index
02761                     if ($kolab_uid){
02762                         
02763                         $this->CacheCreateIndex($fid,$kolab_uid,$o->uid);
02764                         //index of the endDate too 
02765                         $this->CacheWriteEndDate($fid,$ev);
02766                         if ( $ev->sensitivity != 0)
02767                         {
02768                             //add in cache the sensitivity
02769                             $this->CacheWriteSensitivity($kolab_uid,$ev->sensitivity);
02770                         }
02771                     }
02772                     else
02773                     {
02774                         return False;
02775                     }
02776                 }
02777                 if ($this->kolabFolderType($fid) == 1)
02778                 {
02779                     $ev=$this->KolabReadContact($message,1) ;
02780                     $kolab_uid=strtoupper(bin2hex($ev->uid));
02781                     //index
02782                     if ($kolab_uid){
02783                         $this->CacheCreateIndex($fid,$kolab_uid,$o->uid);
02784                     }
02785                     else
02786                     {
02787                         return False;
02788                     }
02789                 }
02790                 if ($this->kolabFolderType($fid) == 3)
02791                 {
02792                     $ev=$this->KolabReadTask($message,false,false,1) ;
02793                     $kolab_uid=strtoupper(bin2hex($ev->uid));
02794                     //index
02795                     if ($kolab_uid){
02796                         $this->CacheCreateIndex($fid,$kolab_uid,$o->uid);
02797                         if ( $ev->sensitivity != 0)
02798                         {
02799                             //add in cache the sensitivity
02800                             $this->CacheWriteSensitivity($kolab_uid,$ev->sensitivity);
02801                         }
02802                         if ( $ev->complete)
02803                         {
02804                             $this->CacheWriteTaskCompleted($kolab_uid,$ev->complete);
02805                         }
02806                     }
02807                     else
02808                     {
02809                         return False;
02810                     }
02811                 }
02812             }
02813             $m["id"] = $kolab_uid;
02814             //$m["mod"]=  $o->uid;
02815             // 'seen' aka 'read' is the only flag we want to know about
02816             $m["flags"] = 0;
02817             return $m;            
02818         }
02819         private function getImapFolderType($folder)
02820         {
02821             
02822             if (function_exists("imap_getannotation"))
02823             {
02824                 $result = imap_getannotation($this->_mbox, $folder, "/vendor/kolab/folder-type", "value.shared");
02825                 if (isset($result["value.shared"]))
02826                 {
02827                     $anno=$result["value.shared"];
02828                 }
02829                 else
02830                 {
02831                     $anno="";
02832                 }
02833             } 
02834             else
02835             {
02836                 $rec="";
02837                 $anno="";
02838                 $fp = fsockopen(KOLAB_SERVER,KOLAB_IMAP_PORT, $errno, $errstr, 30);
02839                 if (!$fp) 
02840                 {
02841                     return false;
02842                 } else {
02843                     //vidage greeting
02844                     $rec=$rec .  stream_get_line($fp,1024,"\r\n");
02845                     $rec="";
02846                     //envoi login ;
02847                     $out = "01 LOGIN " . $this->_username." ". $this->_password ."\r\n";
02848                     fwrite($fp, $out);   
02849                     $rec=$rec .  stream_get_line($fp,1024,"\r\n");
02850                     if (ereg("01 OK",$rec))
02851                     {
02852                         $r=array();
02853                         //envoi de la commande myrights
02854                         $out='ok getannotation "'.$folder.'" "/vendor/kolab/folder-type" "value"' ."\r\n";
02855                         fwrite($fp, $out);   
02856                         $rec=fread($fp,1024);
02857                         $r=split("\r\n",$rec);
02858                         $rec=$r[0];
02859                         if (ereg("ANNOTATION",$rec))
02860                         {
02861                             //bonne reponse
02862                             //* ANNOTATION "INBOX/Calendrier" "/vendor/kolab/folder-type" ("value.shared" "event.default")
02863 
02864                             $tab=array();
02865                             $reg=  "/value.shared\" \"(.+)\"/";
02866                             if (preg_match($reg,$rec,$tab))
02867                             {
02868                                 $anno=$tab[1];  
02869                             }
02870                         }
02871                         $out="03 LOGOUT\r\n";
02872                         fwrite($fp, $out);   
02873                         fclose($fp);
02874                     }
02875                 }
02876             }
02877             $tab=explode(".",$anno);
02878             $root=explode('/',$folder);
02879             if ( $root[0] != "INBOX")
02880             {
02881                 if (count($tab) == 2)
02882                 {
02883                     $anno = $tab[0];
02884                 }
02885             }
02886             return $anno;
02887 
02888 
02889         }
02890 
02891         private function kolabFolderType($name)
02892         {
02893             if ( $name == "VIRTUAL/calendar")
02894             {
02895                 return 2;
02896             }
02897             if ( $name == "VIRTUAL/contacts")
02898             {
02899                 return 1;
02900             }
02901             if ( $name == "VIRTUAL/tasks")
02902             {
02903                 return 3;
02904             }
02905             $type= $this->readFolderAnnotation($name)  ;
02906             if ( $type == false)
02907             {
02908                 //not in the cache
02909                 $this->saveFolderAnnotation($name);
02910                 $type= $this->readFolderAnnotation($name)  ; 
02911             }
02912             if ($type == "task" || $type == "task.default")
02913             {
02914                 return 3;
02915             }
02916             if ($type == "event" || $type == "event.default")
02917             {
02918                 return 2;
02919             }
02920             if ($type == "contact" || $type == "contact.default") 
02921             {
02922                 return 1;
02923             }
02924             return 0;
02925         }
02926         private function ActiveSyncFolderSyncType($name)
02927         {
02928             $type= $this->readFolderAnnotation($name)  ; 
02929             if ( $type == "task.default")
02930             {
02931                 return SYNC_FOLDER_TYPE_TASK;
02932             }
02933 
02934             if ( $type == "event.default")
02935             {
02936                 return SYNC_FOLDER_TYPE_APPOINTMENT;
02937             }
02938             if ( $type == "contact.default") 
02939             {
02940                 return SYNC_FOLDER_TYPE_CONTACT;
02941             }
02942             if ( $type == "task")
02943             {
02944                 //check if no default folder exist; 
02945                 if ( $this->hasDefaultTaskFolder == false )
02946                 {
02947                     if ($this->isDefaultFolder($name,KOLAB_DEFAULTFOLDER_TASK))
02948                     {
02949                         $this->hasDefaultTaskFolder= true;
02950                         $this->forceDefaultFolder("task",$name);
02951                         return SYNC_FOLDER_TYPE_TASK; 
02952                     }
02953                 }
02954                 return SYNC_FOLDER_TYPE_USER_TASK;
02955             }
02956 
02957             if ( $type == "event")
02958             {
02959                 if ( $this->hasDefaultEventFolder == false )
02960                 {
02961                     if ($this->isDefaultFolder($name,KOLAB_DEFAULTFOLDER_DIARY))
02962                     {
02963                         $this->Log("NOTICE no event default folder set as default: $name");
02964                         $this->forceDefaultFolder("event",$name); 
02965                         $this->hasDefaultEventFolder= true;
02966                         return SYNC_FOLDER_TYPE_APPOINTMENT;   
02967                     }
02968                 }
02969                 return SYNC_FOLDER_TYPE_USER_APPOINTMENT;
02970             }
02971             if ( $type == "contact") 
02972             {
02973                 if ( $this->hasDefaultContactFolder == false )
02974                 {
02975                     if ($this->isDefaultFolder($name,KOLAB_DEFAULTFOLDER_CONTACT))
02976                     {
02977                         $this->forceDefaultFolder("contact",$name); 
02978                         $this->hasDefaultContactFolder= true;
02979                         return SYNC_FOLDER_TYPE_CONTACT;   
02980                     }
02981                 }
02982                 return SYNC_FOLDER_TYPE_USER_CONTACT;
02983             }
02984         }
02985         private function isDefaultFolder($folder,$defaultchain)
02986         {
02987             $folder=strtolower($folder); 
02988             $f=split(":",strtolower($defaultchain));
02989             foreach($f as $value)
02990             {
02991                 if ($value == $folder)
02992                 {
02993                     return true;
02994                 }
02995             }
02996             return false;
02997         }
02998         private function forceDefaultFolder($type,$folder)
02999         {
03000             switch ($type){
03001                 case 1: $type="contact";
03002                 break;
03003                 case 2: $type="event";
03004                 break;
03005                 case 3: $type="task";
03006                 break;
03007             }
03008             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); 
03009             $this->_cache->write("DEFAULT:".$type.".default",$folder); 
03010             $this->_cache->close();   
03011         }
03012         private function saveFolderAnnotation($foldera)
03013         {
03014             $anno=$this->getImapFolderType($foldera);
03015             if (!$anno)
03016             {
03017                 $anno="0";
03018             }
03019             $default=explode(".",$anno);   
03020             //remove the default if this is not in INBOX folder 
03021             //we must detech just INBOX default folder
03022             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); 
03023             if ( isset($default[1]) && $default[1] == "default" )
03024             {
03025                 if (substr($foldera,0,5) == "INBOX") 
03026                 {
03027 
03028                     $this->_cache->write("DEFAULT:".$anno,$foldera);
03029                 }
03030                 else 
03031                 {
03032                     $anno = $default[0];
03033                 } 
03034             }  
03035             if ( $anno =="mail.sentitems")
03036             {
03037                 $this->_cache->write("SENTFOLDER:",$foldera);
03038             }
03039             if ( ! $this->_cache->write("FA:".$foldera,$anno))
03040             {
03041                 $this->Log("ERROR: ".KOLAB_INDEX."/".$this->_username);
03042             }
03043             $this->_cache->close();   
03044             $this->Log("Annotation $foldera : $anno") ;
03045         }
03046         private function readDefaultSentItemFolder()
03047         {
03048             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); 
03049             $sentf=$this->_cache->find("SENTFOLDER:");
03050             $this->_cache->close();
03051             return $sentf;
03052         }
03053         private function readFolderAnnotation($folder)
03054         {
03055             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); 
03056             $anno=$this->_cache->find("FA:".$folder);
03057             $this->_cache->close();
03058             return $anno;
03059         }
03060         private function CacheGetDefaultFolder($type)
03061         {
03062             switch ($type){
03063                 case 1: $type="contact";
03064                 break;
03065                 case 2: $type="event";
03066                 break;
03067                 case 3: $type="task";
03068                 break;
03069             }
03070             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);   
03071             $deffolder=$this->_cache->find("DEFAULT:".$type.".default");
03072             $this->_cache->close();
03073             return $deffolder;
03074         }
03075 
03076         private function CacheReadEndDate($folder,$uid)
03077         {
03078             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);    
03079             $deffolder=$this->_cache->find("ENDDATE:".$folder."/".$uid);
03080             $this->_cache->close();
03081             if ($deffolder == False)
03082             {
03083                 $deffolder = "-1";
03084             }
03085             return $deffolder;
03086         }
03087         private function CacheWriteEndDate($folder,$event)
03088         {   
03089             $uid=strtoupper(bin2hex($event->uid));
03090             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); 
03091            
03092             $edate=-1;
03093             if ($event->recurrence)
03094             {
03095                 //end date in the recurence ? 
03096 
03097                 if (isset($event->recurrence->until))
03098                 {
03099                     if ( strtolower($_GET["DeviceType"]) == "iphone" || strtolower($_GET["DeviceType"]) == "ipod")
03100                     {
03101                         $edate =$event->recurrence->until  - 93599 ; 
03102                     }
03103                     else
03104                     {
03105                         $edate = $event->recurrence->until;
03106                     }
03107                 }
03108                 elseif(isset($event->recurrence->occurrences))
03109                 {
03110                     if ( isset($event->recurrence->interval))
03111                     {
03112                         $interval=$event->recurrence->interval;
03113                     }
03114                     else
03115                     {
03116                         $interval=1;
03117                     }
03118                     switch($event->recurrence->type) 
03119                     { 
03120                         case 0:
03121                         //repeat daily   
03122                         // enddate = startDate + (repeat +(86400 * interval))
03123                         $edate= $event->starttime + ($event->recurrence->occurrences *(86400* $interval)) ;
03124                         break;
03125                         case 2:    
03126                         //approche monts =31 to be sure to not cute it with a complex thing
03127                         $edate= $event->starttime + ($event->recurrence->occurrences *(2678400* $interval)) ;    
03128                         case 5:
03129                         //yearly 
03130                         $edate= $event->starttime + ($event->recurrence->occurrences *(31536000* $interval )) ;  
03131                         break; 
03132                     }
03133                 }     
03134 
03135                 //others stuffs
03136                 }
03137             else
03138             {
03139                 $edate=$event->endtime;
03140             }
03141             $this->_cache->write("ENDDATE:" . $folder."/".$uid,$edate);
03142             $this->_cache->close();         
03143         }
03144         private function CacheWriteSensitivity($uid,$sensitivity)
03145         {
03146             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);  
03147             $this->_cache->write("SENSITIVITY:" .$uid,$sensitivity);
03148             $this->_cache->close();         
03149         }
03150         private function CacheReadSensitivity($uid)
03151         {
03152             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);    
03153             $s=$this->_cache->find("SENSITIVITY:" .$uid);
03154             $this->_cache->close();
03155             return $s;
03156         }
03157         private function CacheWriteTaskCompleted($uid,$completed)
03158         {
03159             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);  
03160             $this->_cache->write("TCOMPLETED:" .$uid,$completed);
03161             $this->_cache->close();         
03162         }
03163         private function CacheReadTaskCompleted($uid)
03164         {
03165             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);    
03166             $s=$this->_cache->find("TCOMPLETED:" .$uid);
03167             $this->_cache->close();
03168             return $s;
03169         }
03170         private function CacheWritePicture($uid,$picture)
03171         {
03172             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);  
03173             $this->_cache->write("CPICTURE:" .$uid,$picture);
03174             $this->_cache->close();         
03175         }
03176         private function CacheReadPicture($uid)
03177         {
03178             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);    
03179             $s=$this->_cache->find("CPICTURE:" .$uid);
03180             $this->_cache->close();
03181             return $s;
03182         }
03183         private function CacheDeletePicture($uid)
03184         {
03185             $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);       
03186             $this->_cache->delete("CPICTURE:".$uid);
03187             $this->_cache->close(); 
03188         }
03189         private function kolabReadGlobalParam()
03190         {
03191             if (function_exists("imap_getannotation"))
03192             {
03193                 $gp=new GlobalParam();
03194                 $result = imap_getannotation($this->_mbox, "INBOX", "/vendor/kolab/activesync", "value.priv");
03195                 if (isset($result["value.priv"])) 
03196                 {
03197                     if ( ! $gp->unserialize($result["value.priv"]))
03198                     {
03199                         return $gp;
03200                     }
03201                 }
03202                 return $gp;
03203             }
03204         }
03205         private function kolabReadFolderParam($folder)
03206         {
03207             if (function_exists("imap_getannotation"))
03208             {
03209                 $gp=new FolderParam(); 
03210                 $result = imap_getannotation($this->_mbox, $folder, "/vendor/kolab/activesync", "value.priv");
03211                 if (isset($result["value.priv"])) 
03212                 {
03213 
03214                     if ( ! $gp->unserialize($result["value.priv"]))
03215                     {
03216                         return $gp;
03217                     }
03218                 }
03219                 return $gp;
03220             }
03221         }
03222         private function kolabWriteGlobalParam($gp)
03223         {
03224             if ( ! $gp)
03225             {
03226                 return false ;
03227             }
03228             $anno=$gp->serialize();
03229             if (function_exists("imap_setannotation"))
03230             {
03231                 //write annotation on the INBOX folder
03232                 $result = @imap_setannotation($this->_mbox, "INBOX", "/vendor/kolab/activesync", "value.priv",$anno);
03233                 if ( ! $result)
03234                 {
03235                     $this->Log("write globalparam :".@imap_last_error());
03236 
03237                     return false;
03238                 }
03239             }
03240             return true ;
03241         }
03242         private function getLdapAccount()
03243         {
03244             //chech if KOLAB_LDAP_SERVER is a URI or an IP
03245             $reg=  "/ldap:\/\/(.+):(.+)/";
03246             if (preg_match($reg,KOLAB_SERVER,$tab))
03247             {
03248                 $addrip=$tab[1];
03249                 $port=$tab[2];  
03250             }
03251             else
03252             {
03253                 $addrip=KOLAB_SERVER;
03254                 $port=389;
03255             }
03256             $conn=ldap_connect($addrip,$port) ;
03257             if ($conn == 0)
03258             {
03259                 $this->Log("ERR LDAP connexion to server : " . KOLAB_SERVER . " failed");
03260                 return 0;
03261             }
03262             if (!ldap_bind ($conn,"",""))
03263             {
03264                 $this->Log("ERR LDAP Invalid credential") ;  
03265                 return 0;
03266             }
03267             //recherche du DN a autentifier
03268             if ( ! $sr=ldap_search($conn,KOLAB_LDAP_BASE,"(uid=".$this->_username.")"))
03269             {
03270                 $this->Log("ERR LDAP ". $this->_username ." not found")  ;
03271                 return 0;
03272             }
03273             $entries=ldap_get_entries($conn,$sr);
03274             if ($entries['count'] == 1)
03275             {
03276                 $this->_email=$entries[0]["mail"][0];
03277                 $this->_cn=$entries[0]["cn"][0];
03278                 $this->_KolabHomeServer=$entries[0]["kolabhomeserver"][0];
03279                 $dn=$entries[0]["dn"];
03280                 //check ACL if KOLAN_LDAP_ACL 
03281                 if (defined("KOLAB_LDAP_ACL"))
03282                 {
03283                     $grp=KOLAB_LDAP_ACL;
03284                 }
03285                 else
03286                 {
03287                     $grp ="";
03288                 }
03289                 if ($grp  != "")
03290                 {
03291                     //check if the dn is in the group as member
03292                     $r = ldap_compare($conn, $grp, "member", $dn) ;
03293                     if ( ! $r)
03294                     {
03295                         $this->Log("ACL member not present in $grp Access Denied");
03296                         return 0;
03297                     }
03298                     if ( $r == -1)
03299                     {
03300                         $this->Log("ACL group $gr not found (acces authorized)");
03301                     }
03302                 }
03303                 return 1;
03304             }
03305         }  
03306         private function rtf2text($data)
03307         {
03308             $rtf_body = new rtf ();
03309             $rtf_body->loadrtf(base64_decode($data));
03310             $rtf_body->output("ascii");
03311             $rtf_body->parse();
03312             $r=$rtf_body->out;
03313             unset($rtf_body);
03314             return $r;
03315         }     
03316     };  
03317     class userCache {
03318         private $_filename;
03319         private $_id;
03320         public $_lastError;
03321         function open($filename)
03322         {
03323             $this->_id = dba_open ($filename.".cache", "cl");
03324 
03325             if (!$this->_id) {
03326                 $this->_lastError = "failed to open $filename";
03327                 return false;
03328             }
03329             $this->_filename=$filename;
03330             return true;
03331         }
03332         function close()
03333         {
03334             dba_close($this->_id);
03335         }
03336         function write($key,$value)
03337         {
03338             $oldvalue=dba_fetch($key, $this->_id);
03339             if ( $oldvalue == $value)
03340             {
03341                 //the key already exist and the value is the same we do nothing
03342                 return 1;
03343             }
03344             if ($oldvalue) 
03345             {
03346                 //the key exist but the value change
03347                 dba_delete($key,$this->_id);
03348             }
03349             return dba_insert($key,$value, $this->_id);
03350 
03351         }
03352         function delete($key)
03353         {
03354             if (dba_exists ($key, $this->_id)) {
03355                 return dba_delete ($key, $this->_id);
03356             }
03357             return 1;
03358         }
03359         function purge()
03360         {
03361 
03362             unlink($this->_filename."cache");
03363 
03364         }
03365         function find($key)
03366         {
03367             return dba_fetch($key,$this->_id);
03368         }
03369 
03370 
03371     }
03372 ?>