source: trunk/zpush/backend/kolab/kolab.php @ 7589

Revision 7589, 138.9 KB checked in by douglas, 11 years ago (diff)

Ticket #3209 - Integrar módulo de sincronização Z-push ao Expresso

RevLine 
[7589]1<?php
2    /*
3    Kolab Z-Push Backend
4
5    Copyright (C) 2009-2010 Free Software Foundation Europe e.V.
6
7    The main author of the Kolab Z-Push Backend is Alain Abbas, with
8    contributions by .......
9
10    This program is Free Software; you can redistribute it and/or
11    modify it under the terms of version two of the GNU General Public
12    License as published by the Free Software Foundation.
13
14    This program is distributed in the hope that it will be useful, but
15    WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17    General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22    02110-1301, USA.
23
24    The licensor of the Kolab Z-Push Backend is the
25    Free Software Foundation Europe (FSFE), Fiduciary Program,
26    Linienstr. 141, 10115 Berlin, Germany, email:ftf@fsfeurope.org.
27    */                                                                   
28    //define('KOLABBACKEND_VERSION', 'SVN developpment 20100307');
29    define('KOLABBACKEND_VERSION', '0.6');   
30    include_once('diffbackend.php');
31
32    // The is an improved version of mimeDecode from PEAR that correctly
33    // handles charsets and charset conversion
34    include_once('mimeDecode.php');
35    include_once('z_RTF.php');
36    include_once('z_RFC822.php');
37    include_once('Horde/Kolab/Kolab_Zpush/lib/kolabActivesyncData.php');
38    require_once 'Horde/Kolab/Format.php';
39
40    class BackendKolab extends BackendDiff {
41        private $_server = "";
42        private $_username ="";
43        private $_domain = "";
44        private $_password = "";
45        private $_cache;
46        private $_deviceType;
47        private $_deviceAgent;
48        private $hasDefaultEventFolder =false;
49        private $hasDefaultContactFolder= false; 
50        private $hasDefaultTaskFolder = false;
51        private $foMode = false;
52        private $_mbox;
53        private $_KolabHomeServer;
54        private $_cn;
55        private $_email;
56        private $sentFolder="";
57        /* Called to logon a user. These are the three authentication strings that you must
58        * specify in ActiveSync on the PDA. Normally you would do some kind of password
59        * check here. Alternatively, you could ignore the password here and have Apache
60        * do authentication via mod_auth_*
61        */
62        function Logon($username, $domain, $password) {
63            $this->_wasteID = false;
64            $this->_sentID = false;
65            $this->_username = $username;
66            $this->_domain = $domain;
67            $this->_password = $password;
68            if (!$this->getLdapAccount())
69            {
70                return false;
71            }
72            $this->_server = "{" . $this->_KolabHomeServer . ":" . KOLAB_IMAP_PORT . "/imap" . KOLAB_IMAP_OPTIONS . "}";
73            $this->Log("Connecting to ". $this->_server);
74            if (!function_exists("imap_open"))
75            {
76                debugLog("ERROR BackendIMAP : PHP-IMAP module not installed!!!!!");
77                $this->Log("module PHP imap not installed ")  ;
78            }
79
80            // open the IMAP-mailbox
81            $this->_mbox = @imap_open($this->_server , $username, $password, OP_HALFOPEN);
82            $this->_mboxFolder = "";
83
84            if ($this->_mbox) {
85                debugLog("KolabBackend Version : " . KOLABBACKEND_VERSION);
86                debugLog("KolabActiveSyndData Version : " .KOLABACTIVESYNCDATA_VERSION);
87                $this->Log("KolabBackend Version : " . KOLABBACKEND_VERSION);
88                $this->Log("KolabActiveSyndData Version : " .KOLABACTIVESYNCDATA_VERSION);
89                $this->Log("IMAP connection opened sucessfully user : " . $username );
90                // set serverdelimiter
91                $this->_serverdelimiter = $this->getServerDelimiter();
92
93                return true;
94            }
95            else {
96                $this->Log("IMAP can't connect: " . imap_last_error() . "  user : " . $this->_user . " Mobile ID:" . $this->_devid);
97                return false;
98            }
99        }
100
101        /* Called before shutting down the request to close the IMAP connection
102        */
103        function Logoff() {
104            if ($this->_mbox) {
105                // list all errors             
106                $errors = imap_errors();
107                if (is_array($errors)) {
108                    foreach ($errors as $e)    debugLog("IMAP-errors: $e");           
109                }             
110                @imap_close($this->_mbox);
111                debugLog("IMAP connection closed");
112                $this->Log("IMAP connection closed");
113                unset($this->_cache);
114            }
115        }
116
117        /* Called directly after the logon. This specifies the client's protocol version
118        * and device id. The device ID can be used for various things, including saving
119        * per-device state information.
120        * The $user parameter here is normally equal to the $username parameter from the
121        * Logon() call. In theory though, you could log on a 'foo', and then sync the emails
122        * of user 'bar'. The $user here is the username specified in the request URL, while the
123        * $username in the Logon() call is the username which was sent as a part of the HTTP
124        * authentication.
125        */   
126        function Setup($user, $devid, $protocolversion) {
127            $this->_user = $user;
128            $this->_devid = $devid;
129            $this->_protocolversion = $protocolversion;
130            if ($devid == "")
131            {
132                //occurs in the OPTION Command
133                return true;
134            }
135            $this->_deviceType=$_REQUEST["DeviceType"];
136            $this->_deviceAgent=$_SERVER["HTTP_USER_AGENT"];
137            $this->Log("Setup : " . $user. " Mobile ID :" . $devid. " Proto Version : " . $protocolversion ." DeviceType : ". $this->_deviceType . " DeviceAgent : ". $this->_deviceAgent);
138            $this->_cache=new userCache();
139            $this->CacheCheckVersion();
140            //read globalparam .
141            $gp=$this->kolabReadGlobalParam();
142
143            $mode=KOLAB_MODE;
144            if ($gp != false )
145            {
146                //search if serial already in it;
147                if ( $gp->getDeviceType($devid))
148                {
149                    if ( $gp->getDeviceMode($devid) != -1)
150                    {
151                        $mode=$gp->getDeviceMode($devid);
152                    }
153                }
154                else
155                {
156                    //no present we must write it;
157                    $gp->setDevice($devid,$this->_deviceType) ;
158                    if ( ! $this->kolabWriteGlobalParam($gp))
159                    {
160                        $this->Log("ERR cant write Globalparam");
161                    }
162                }
163            }
164            switch($mode)
165            {
166                case 0:$this->foMode = false;
167                $this->Log("NOTICE : Forced to flatmode") ;
168                break;
169                case 1:$this->foMode = true;
170                $this->Log("NOTICE : Forced to foldermode") ;
171                break; 
172                case 2:$this->foMode = $this->findMode();
173                break;
174            }
175            return true;
176        }
177
178        /* Sends a message which is passed as rfc822. You basically can do two things
179        * 1) Send the message to an SMTP server as-is
180        * 2) Parse the message yourself, and send it some other way
181        * It is up to you whether you want to put the message in the sent items folder. If you
182        * want it in 'sent items', then the next sync on the 'sent items' folder should return
183        * the new message as any other new message in a folder.
184        */
185        private function findMode()
186        {   
187            $type=explode(":",KOLAB_MOBILES_FOLDERMODE);
188            if (in_array(strtolower($this->_deviceType),$type))
189            {
190                $this->Log("NOTICE : findMode Foldermode") ;
191                return 1;
192            }
193            $this->Log("NOTICE : findMode Flatmode") ; 
194            return 0;
195        }
196        function SendMail($rfc822, $forward = false, $reply = false, $parent = false) {
197            debugLog("IMAP-SendMail: " . $rfc822 . "for: $forward   reply: $reply   parent: $parent" );
198            //
199            $mobj = new Mail_mimeDecode($rfc822);
200            $message = $mobj->decode(array('decode_headers' => false, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $rfc822, 'crlf' => "\n", 'charset' => 'utf-8'));
201
202            $toaddr = $ccaddr = $bccaddr = "";
203            if(isset($message->headers["to"]))
204            $toaddr = $this->parseAddr(Mail_RFC822::parseAddressList($message->headers["to"]));
205            if(isset($message->headers["cc"]))
206            $ccaddr = $this->parseAddr(Mail_RFC822::parseAddressList($message->headers["cc"]));
207            if(isset($message->headers["bcc"]))
208            $bccaddr = $this->parseAddr(Mail_RFC822::parseAddressList($message->headers["bcc"]));
209
210            // save some headers when forwarding mails (content type & transfer-encoding)
211            $headers = "";
212            $forward_h_ct = "";
213            $forward_h_cte = "";
214
215            $use_orgbody = false;
216
217            // clean up the transmitted headers
218            // remove default headers because we are using imap_mail
219            $changedfrom = false;
220            $returnPathSet = false;
221            $body_base64 = false;
222            $org_charset = "";
223            foreach($message->headers as $k => $v) {
224                if ($k == "subject" || $k == "to" || $k == "cc" || $k == "bcc")
225                continue;
226
227                if ($k == "content-type") {
228                    // save the original content-type header for the body part when forwarding
229                    if ($forward) {
230                        $forward_h_ct = $v;
231                        continue;
232                    }
233
234                    // set charset always to utf-8
235                    $org_charset = $v;
236                    $v = preg_replace("/charset=([A-Za-z0-9-\"']+)/", "charset=\"utf-8\"", $v);
237                }
238
239                if ($k == "content-transfer-encoding") {
240                    // if the content was base64 encoded, encode the body again when sending               
241                    if (trim($v) == "base64") $body_base64 = true;
242
243                    // save the original encoding header for the body part when forwarding
244                    if ($forward) {
245                        $forward_h_cte = $v;
246                        continue;
247                    }
248                }
249
250                // if the message is a multipart message, then we should use the sent body
251                if (!$forward && $k == "content-type" && preg_match("/multipart/i", $v)) {
252                    $use_orgbody = true;
253                }
254
255                // check if "from"-header is set
256                if ($k == "from"  ) {
257                    $changedfrom = true;
258                    if (! trim($v) )
259                    {
260                        $v = $this->_email;
261                    }
262                }
263
264                // check if "Return-Path"-header is set
265                if ($k == "return-path") {
266                    $returnPathSet = true;
267                    if (! trim($v) ) {
268                        $v = $this->_email;
269
270                    }
271                }
272
273                // all other headers stay                             
274                if ($headers) $headers .= "\n";
275                $headers .= ucfirst($k) . ": ". $v;
276            }
277           
278            // set "From" header if not set on the device
279            if( !$changedfrom){
280                $v = $this->_email;   
281                if ($headers) $headers .= "\n";
282                $headers .= 'From: '.$v;
283            }
284
285            // set "Return-Path" header if not set on the device
286            if(!$returnPathSet){
287                $v = $this->_email;   
288                if ($headers) $headers .= "\n";
289                $headers .= 'Return-Path: '.$v;
290            }
291             
292            // if this is a multipart message with a boundary, we must use the original body
293            if ($use_orgbody) {
294                list(,$body) = $mobj->_splitBodyHeader($rfc822);
295            }   
296            else
297            $body = $this->getBody($message);
298
299            // reply               
300            if (isset($reply) && isset($parent) &&  $reply && $parent) {
301                $this->imap_reopenFolder($parent);
302                // receive entire mail (header + body) to decode body correctly
303                $origmail = @imap_fetchheader($this->_mbox, $reply, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $reply, FT_PEEK | FT_UID);
304                $mobj2 = new Mail_mimeDecode($origmail);
305                // receive only body
306                $body .= $this->getBody($mobj2->decode(array('decode_headers' => false, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $origmail, 'crlf' => "\n", 'charset' => 'utf-8')));
307                // unset mimedecoder & origmail - free memory           
308                unset($mobj2);
309                unset($origmail);
310            }
311
312            // encode the body to base64 if it was sent originally in base64 by the pda
313            // the encoded body is included in the forward         
314            if ($body_base64) $body = base64_encode($body);
315
316
317            // forward               
318            if (isset($forward) && isset($parent) && $forward && $parent) {
319                $this->imap_reopenFolder($parent);
320                // receive entire mail (header + body)
321                $origmail = @imap_fetchheader($this->_mbox, $forward, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $forward, FT_PEEK | FT_UID);
322
323                // build a new mime message, forward entire old mail as file
324                list($aheader, $body) = $this->mail_attach("forwarded_message.eml",strlen($origmail),$origmail, $body, $forward_h_ct, $forward_h_cte);
325
326                // unset origmail - free memory           
327                unset($origmail);
328
329                // add boundary headers
330                $headers .= "\n" . $aheader;
331            }
332            $headers .="\n";
333            $send =  @imap_mail ( $toaddr, $message->headers["subject"], $body, $headers, $ccaddr, $bccaddr);
334            $errors = imap_errors();
335                if (is_array($errors)) {
336                    foreach ($errors as $e)    debugLog("IMAP-errors: $e");           
337                }             
338            // email sent?
339            if (!$send) {
340                debugLog("The email could not be sent. Last-IMAP-error: ". imap_last_error());
341            }
342            // add message to the sent folder
343            // build complete headers
344            $cheaders  = "To: " . $toaddr. "\n";
345            $cheaders .= $headers;
346            $asf = false; 
347            //try to see if there are a folder with the annotation
348            $sent=$this->readDefaultSentItemFolder();   
349            $body=str_replace("\n","\r\n",$body);
350            $cheaders=str_replace(":  ",": ",$cheaders);
351            $cheaders=str_replace("\n","\r\n",$cheaders);
352            if ($sent) {
353                $asf = $this->addSentMessage($sent, $cheaders, $body);
354            }
355            else if ($this->sentFolder) {
356                $asf = $this->addSentMessage($this->sentFolder, $cheaders, $body);
357                debugLog("IMAP-SendMail: Outgoing mail saved in configured 'Sent' folder '".$this->sentFolder."': ". (($asf)?"success":"failed"));
358            }
359            // No Sent folder set, try defaults
360            else {
361                debugLog("IMAP-SendMail: No Sent mailbox set");
362                if($this->addSentMessage("INBOX/Sent", $cheaders, $body)) {
363                    debugLog("IMAP-SendMail: Outgoing mail saved in 'INBOX/Sent'");
364                    $asf = true;
365                }
366                else if ($this->addSentMessage("Sent", $cheaders, $body)) {
367                    debugLog("IMAP-SendMail: Outgoing mail saved in 'Sent'");
368                    $asf = true;
369                }
370                else if ($this->addSentMessage("Sent Items", $cheaders, $body)) {
371                    debugLog("IMAP-SendMail: Outgoing mail saved in 'Sent Items'");
372                    $asf = true;
373                }
374            }
375            $errors = imap_errors();
376                if (is_array($errors)) {
377                    foreach ($errors as $e)    debugLog("IMAP-errors: $e");           
378                }             
379            // unset mimedecoder - free memory
380            unset($mobj);
381            return ($send && $asf);
382        }
383
384        /* Should return a wastebasket folder if there is one. This is used when deleting
385        * items; if this function returns a valid folder ID, then all deletes are handled
386        * as moves and are sent to your backend as a move. If it returns FALSE, then deletes
387        * are always handled as real deletes and will be sent to your importer as a DELETE
388        */
389        function GetWasteBasket() {
390            return $this->_wasteID;
391        }
392        private function GetMessagesListByType($foldertype,$cutoffdate)
393        {
394            $lastfolder="";
395            $messages=array();
396            $list = @imap_getmailboxes($this->_mbox, $this->_server, "*");
397            if (is_array($list)) { 
398                $list = array_reverse($list);
399                foreach ($list as $val) {
400                    //$folder=imap_utf7_decode(substr($val->name, strlen($this->_server)));
401                    $folder=substr($val->name, strlen($this->_server));
402                    //$this->saveFolderAnnotation($folder);
403                    $ft=$this->kolabFolderType($folder);
404                    if ($ft !=  $foldertype)
405                    {
406                        continue;
407                    }
408                    $isUser=false;
409                    $isShared=false;
410                    if (substr($folder,0,4) =="user"){$isUser=true;}
411                    if (substr($folder,0,6) =="shared"){$isShared=true;}
412                    $fa=$this->kolabReadFolderParam($folder);
413                    //here we must push theo object in the cache to
414                    //dont have to read it again at each message ( for the alarms)
415                    $this->CacheWriteFolderParam($folder,$fa);
416                    $fa->setFolder($folder);
417                    if ( ! $fa->isForSync($this->_devid))
418                    {
419                        //not set to sync
420                        continue;
421                    }
422                    //want user namespace ?
423                    /*
424                    if ( !KOLAB_USERFOLDER_DIARY && $foldertype == 2 && $isUser)
425                    {
426                    continue;
427                    }
428                    if ( !KOLAB_USERFOLDER_CONTACT && $foldertype == 1 && $isUser)
429                    {
430                    continue;
431                    }
432                    //want shared namespace ?
433                    if ( !KOLAB_SHAREDFOLDER_DIARY && $foldertype == 2 && $isShared)
434                    {
435                    continue;
436                    }
437                    if ( !KOLAB_SHAREDFOLDER_CONTACT && $foldertype == 1 && $isShared)
438                    {
439                    continue;
440                    }
441                    */
442                    if ( $this->CacheGetDefaultFolder($foldertype) == false)
443                    {
444                        //no default
445                        if (substr($folder,0,5) == "INBOX")
446                        {
447                            $n=array_pop(explode("/",$folder));
448                            $result=false;
449                            switch($foldertype)
450                            {
451                                case 1: $result=$this->isDefaultFolder($n,KOLAB_DEFAULTFOLDER_CONTACT);
452                                break;
453                                case 2: $result=$this->isDefaultFolder($n,KOLAB_DEFAULTFOLDER_DIARY);
454                                break;
455                                case 3: $result=$this->isDefaultFolder($n,KOLAB_DEFAULTFOLDER_TASK);
456                                break;         
457                            }
458                            if ( $result == true)
459                            {
460                                $this->forceDefaultFolder($foldertype,$folder);
461                            }
462                            else
463                            {
464                                $lastfolder=$folder;
465                            } 
466                        }
467                    }
468
469                    $this->imap_reopenFolder($folder);
470                   
471                    /*trying optimizing the reads*/
472                    /*if ($this->isFolderModified($folder) == false )
473                    {
474                    $this->Log("NOTICE : folder not modified $folder");
475                    $message_folder=$this->CacheReadMessageList($folder);
476                    if (count($message)> 0)
477                    {
478                    $messages=array_merge($messages,$message_folder);
479                    continue;
480                    }     
481                    }   */
482                    $overviews = @imap_fetch_overview($this->_mbox, "1:*",FT_UID);
483                    if (!$overviews) {
484                        debugLog("IMAP-GetMessageList: $folder Failed to retrieve overview");
485                    } else {
486                        $message_infolder=array();
487                        foreach($overviews as $overview) {
488                            $date = "";               
489                            $vars = get_object_vars($overview);
490
491                            if (array_key_exists( "deleted", $vars) && $overview->deleted)               
492                            continue;
493
494                            $message=$this->KolabStat($folder,$overview);
495                            if (! $message){continue;}
496                            //cutoffdate for appointment
497                            if ( $foldertype == 2)
498                            {
499                                //look for kolabuid
500                                $this->Log("try cutoffdate for message id ".$message["id"]);
501                                $enddate= $this->CacheReadEndDate($folder,$message["id"]);
502                                if ($enddate != - 1 && $cutoffdate > $enddate)
503                                {
504                                    //cuteoffdate
505                                    $this->Log("cuteoffDate :" . $message["id"] );
506                                    continue;
507                                }
508                                if ( substr($folder,0,5) != "INBOX")
509                                {
510                                    if ($this->CacheReadSensitivity($message["id"]))
511                                    {
512                                        //check if private for namespace <> INBOX
513                                        continue;
514                                    }
515                                }
516                            }
517                            //check if key is duplicated
518                            if (isset($checkId[$message["id"]]))
519                            {
520                                //uid exist
521                                $this->Log("Key : " .$message["id"] ." duplicated folder :" . $folder ." Imap id : " . $checkId[$message["id"]]);
522                                debugLog("Key : " .$message["id"] ." duplicated folder :" . $folder ." Imap id : " . $checkId[$message["id"]]);
523                                //rewrite the index to have the good imapid
524                                $id=array_pop(explode("/",$checkId[$message["id"]]));
525                                $this->CacheCreateIndex($folder,$message["id"],$id); 
526                                continue;
527                            }
528                            else
529                            {
530                                $checkId[$message["id"]] = $message["mod"];
531                            }
532                            //here check the cutdate for appointments
533                            debugLog("ListMessage : " . $message["id"] . "->" . $message["mod"] ) ;
534                            $messages[]=$message;
535                            $message_infolder[]=$message;
536                        }
537                        $this->CacheStoreMessageList($folder,$message_infolder);
538                    }
539                }
540                //check if we found a default folder for this type
541                if ( $this->CacheGetDefaultFolder($foldertype) == false)
542                {
543                    //no we pur the last folder found as default;
544                    $this->forceDefaultFolder($foldertype,$lastfolder);
545                }
546 
547                unset($checkId);
548                unset($overviews);
549                return $messages;
550            }
551        }
552        private function statImapFolder($folder)
553        {
554            $info=imap_status($this->_mbox, $this->_server .$folder, SA_ALL)  ;
555            return serialize($info);
556        }
557        /* Should return a list (array) of messages, each entry being an associative array
558        * with the same entries as StatMessage(). This function should return stable information; ie
559        * if nothing has changed, the items in the array must be exactly the same. The order of
560        * the items within the array is not important though.
561        *
562        * The cutoffdate is a date in the past, representing the date since which items should be shown.
563        * This cutoffdate is determined by the user's setting of getting 'Last 3 days' of e-mail, etc. If
564        * you ignore the cutoffdate, the user will not be able to select their own cutoffdate, but all
565        * will work OK apart from that.
566        */
567        function GetMessageList($folderid, $cutoffdate)
568        {
569            $messages = array();
570            $checkId = array();
571            if ($folderid == "VIRTUAL/calendar")
572            {
573                //flat mode
574                //search all folders of type calendar
575                $messages=$this->GetMessagesListByType(2,$cutoffdate);
576
577            }
578            else if ($folderid == "VIRTUAL/contacts") 
579            {
580                $messages=$this->GetMessagesListByType(1,$cutoffdate);
581            }
582            else if ($folderid == "VIRTUAL/tasks") 
583            {
584                $messages=$this->GetMessagesListByType(3,$cutoffdate);
585            }
586            else
587            {
588                $this->imap_reopenFolder($folderid, true);
589                //check if the folder as moved by imap stat
590                /*
591                if ($this->isFolderModified($folderid) == false )
592                {
593                $this->Log("NOTICE : folder not modified $folderid");
594                $messages=$this->CacheReadMessageList($folderid);
595                return $messages;     
596                } */
597                $overviews = @imap_fetch_overview($this->_mbox, "1:*",FT_UID);
598                if (!$overviews) {
599                    debugLog("IMAP-GetMessageList: $folderid Failed to retrieve overview");
600                } else {
601                    foreach($overviews as $overview) {
602                        $date = "";               
603                        $vars = get_object_vars($overview);
604                        // cut of deleted messages
605                        if (array_key_exists( "deleted", $vars) && $overview->deleted)               
606                        continue;
607                        $folderType=$this->kolabFolderType($folderid);
608                        if ( $folderType> 0)
609                        {
610                            //kolab contacts and appointment special index
611                            //mode is the imap uid because kolab delete the message and recreate a newone in case
612                            //of modification
613                            $message=$this->KolabStat($folderid,$overview);
614                            if (! $message){continue;}
615                            //cutoffdate for appointment
616                            if ( $folderType == 2)
617                            {
618                                //look for kolabuid
619                                $this->Log("try cutoffdate for message id ".$message["id"]);
620                                $enddate= $this->CacheReadEndDate($folderid,$message["id"]);
621                                if ($enddate != - 1 &&  $cutoffdate > $enddate)
622                                {
623                                    //cuteoffdate
624                                    $this->Log("cuteoffDate too old");
625                                    continue;
626                                }
627                                if ( substr($folderid,0,5) != "INBOX")
628                                {
629                                    if ($this->CacheReadSensitivity($message["id"]))
630                                    {
631                                        //check if private for namespace <> INBOX
632                                        continue;
633                                    }
634                                }
635                            }
636                            //check if key is duplicated
637                            if (isset($checkId[$message["id"]]))
638                            {
639                                $this->Log("Key : " .$message["id"] ." duplicated folder :" . $folder ." Imap id : " . $checkId[$message["id"]]);
640                                debugLog("Key : " .$message["id"] ." duplicated folder :" . $folder ." Imap id : " . $checkId[$message["id"]]);
641                                //rewrite the index to have the good imapid
642                                $id=array_pop(explode("/",$checkId[$message["id"]]));
643                                $this->CacheCreateIndex($folder,$message["id"],$id);
644                                continue;
645                            }
646                            else
647                            {
648                                $checkId[$message["id"]] = $message["mod"];
649                            }
650                            //here check the cutdate for appointments
651                            debugLog("ListMessage : " . $message["id"] . "->" . $message["mod"] ) ;
652                            $messages[]=$message;
653                        }
654                        else
655                        {
656
657                            if (array_key_exists( "date", $vars)) {               
658                                // message is out of range for cutoffdate, ignore it
659
660                                if(strtotime($overview->date) < $cutoffdate) continue;
661                                $date = $overview->date;
662                            }
663                            if (array_key_exists( "uid", $vars))
664                            {               
665                                $message = array();
666                                $message["mod"] = $date;
667                                $message["id"] = $overview->uid;
668                                // 'seen' aka 'read' is the only flag we want to know about
669                                $message["flags"] = 0;
670                                if(array_key_exists( "seen", $vars) && $overview->seen)
671                                $message["flags"] = 1;
672                                array_push($messages, $message);
673                            }
674                        }
675                    }
676                }
677                //clean the index before leave
678                $this->CacheIndexClean($messages) ;
679                //$this->Log("Get Message List : " . count($messages)) ;
680                }
681
682            debugLog("MEM GetmessageList End:" . memory_get_usage())  ;
683            $this->CacheStoreMessageList($folderid,$messages);
684            return $messages;
685
686
687        }
688        private function isFolderModified($folder)
689        {
690            $newstatus=@imap_status($this->_mbox,$this->_server. $folder,SA_ALL);
691            $oldstatus=$this->CacheReadImapStatus($folder);
692            //found the old status;
693            //we compare
694            if ( $oldstatus->uidnext == $newstatus->uidnext && $oldstatus->messages == $newstatus->messages)
695            {
696                //the folder has not been modified
697                return False;
698            }
699            $this->CacheStoreImapStatus($folder,$newstatus);
700            return true;
701        }   
702        /* This function is analogous to GetMessageList.
703        *
704        */
705        function GetFolderList()
706        {
707 
708            if ( $this->foMode == true)
709            {
710                return $this->GetFolderListFoMode();
711            }
712            else
713            {
714                return $this->GetFolderListFlMode();
715            }
716        }
717        private function GetFolderListFlMode()
718        {
719            $folders = array();     
720            $list = @imap_getmailboxes($this->_mbox, $this->_server, "*");
721            //add the virtual folders for contacts calendars and tasks
722            $virtual=array("VIRTUAL/calendar","VIRTUAL/contacts","VIRTUAL/tasks");   
723            //$virtual=array("VIRTUAL/calendar","VIRTUAL/contacts");
724            foreach ($virtual as $v)
725            {
726                $box=array();
727                $box["id"]=$v;
728                $box["mod"] =$v;
729                $box["flags"]=0;
730                $folders[]=$box;
731            }           
732            if (is_array($list)) { 
733                $list = array_reverse($list);
734                foreach ($list as $val) {
735                    $box = array();
736                    // cut off serverstring
737                    $box["flags"]=0;
738                    //$box["id"] = imap_utf7_decode(substr($val->name, strlen($this->_server)));
739                    $box["id"] =substr($val->name, strlen($this->_server));
740                    //rerid the annotations
741                    $this->saveFolderAnnotation($box["id"]);
742                    $foldertype=$this->readFolderAnnotation($box["id"]);
743                    //if folder type > 0 escape
744                    if ( substr($foldertype,0,5) == "event")
745                    {
746                        continue;
747                    }
748                    if ( substr($foldertype,0,7) == "contact")
749                    {
750                        continue;
751                    }
752                    if ( substr($foldertype,0,4) == "task")
753                    {
754                        continue;
755                    }
756                    //other folders (mails)
757                    //$box["id"] = imap_utf7_encode( $box["id"]); 
758                    $fhir = explode("/", $box["id"]);
759                    if (count($fhir) > 1) {
760                        $box["mod"] = imap_utf7_encode(array_pop($fhir)); // mod is last part of path
761                        $box["parent"] = imap_utf7_encode(implode("/", $fhir)); // parent is all previous parts of path
762                        }
763                    else {
764                        $box["mod"] = imap_utf7_encode($box["id"]);
765                        $box["parent"] = "0";
766                    }
767
768                    $folders[]=$box; 
769                }
770            }
771            else {
772                debugLog("GetFolderList: imap_list failed: " . imap_last_error());
773            }
774            return $folders;   
775        }
776        private function GetFolderListFoMode() {
777            $folders = array();     
778            $list = @imap_getmailboxes($this->_mbox, $this->_server, "*");
779            $this->hasDefaultEventFolder=false;
780            $this->hasDefaultContactFolder=false; 
781            $this->hasDefaultTaskFolder=false; 
782            if (is_array($list)) {
783
784                //create the
785                // reverse list to obtain folders in right order
786                $list = array_reverse($list);
787                foreach ($list as $val) {
788                    $box = array();
789                    // cut off serverstring
790                    $box["flags"]=0;
791                    //$box["id"] = imap_utf7_decode(substr($val->name, strlen($this->_server)));
792                    $box["id"]= substr($val->name, strlen($this->_server));
793                    //determine the type en default folder
794                    $isUser=false;
795                    $isShared=false;
796                    $isInbox=false;
797                    //rerid the annotations
798                    $this->saveFolderAnnotation($box["id"]);
799                    $foldertype=$this->readFolderAnnotation($box["id"]);
800                    $defaultfolder = false;
801                    //defaultfolder ?
802                    if ( $foldertype == "event.default")
803                    {
804                        $this->hasDefaultEventFolder=true;
805                        $defaultfolder = true;
806                    }
807                    if ( $foldertype == "contact.default")
808                    {
809                        $this->hasDefaultContactFolder=true;
810                        $defaultfolder = true;
811                    }
812                    if ( $foldertype == "task.default")
813                    {
814                        $this->hasDefaultTaskFolder=true;
815                        $defaultfolder = true;
816                    }
817                    // workspace of the folder;
818                    if (substr( $box["id"],0,6) == "shared")
819                    {
820                        //this is a shared folder 
821                        $isShared=true;
822                    }
823
824                    if (substr( $box["id"],0,4) == "user")
825                    {
826                        //this is a User shared folder 
827                        $isUser=true;
828                    }
829                    if (substr( $box["id"],0,5) == "INBOX")
830                    {
831                        $isInbox=true;
832                    }
833                    //selection of the folder depending to the setup
834                    if (! $defaultfolder)
835                    {
836                                       
837                        //test annotation
838                        $fa=$this->kolabReadFolderParam($box["id"]);
839                        //for later use (in getMessage)
840
841                        $this->CacheWriteFolderParam($box["id"],$fa);
842                        $fa->setfolder($box["id"]);   
843                        if ( ! $fa->isForSync($this->_devid))
844                        {
845                            //not set to sync
846                            continue;
847                        }
848                    }
849                    $this->Log("NOTICE SyncFolderList Add folder ".$box["id"]);
850                    //$box["id"] = imap_utf7_encode( $box["id"]);
851                    if ($isShared)
852                    {
853                        $fhir = explode(".", $box["id"]);
854                        $box["mod"] = imap_utf7_encode($fhir[1]);
855                        $box["parent"] = "shared";
856                    }
857                    elseif ($isUser)
858                    {
859                        $box["mod"] = imap_utf7_encode(array_pop($fhir));
860                        $box["parent"] = "user"; 
861                    }
862                    else
863                    {
864
865                        // explode hierarchies
866                        $fhir = explode("/", $box["id"]);
867                        $t=count($fhir);
868                        if (count($fhir) > 1) {
869                            $box["mod"] = imap_utf7_encode(array_pop($fhir)); // mod is last part of path
870                            $box["parent"] = imap_utf7_encode(implode("/", $fhir)); // parent is all previous parts of path
871                            }
872                        else {
873                            $box["mod"] = imap_utf7_encode($box["id"]);
874                            $box["parent"] = "0";
875                        }
876                    }                   
877                    $folders[]=$box;
878                }
879            }
880            else {
881                debugLog("GetFolderList: imap_list failed: " . imap_last_error());
882            }
883            return $folders;
884        }
885
886        /* GetFolder should return an actual SyncFolder object with all the properties set. Folders
887        * are pretty simple really, having only a type, a name, a parent and a server ID.
888        */
889
890        function GetFolder($id) {
891            $folder = new SyncFolder();
892            $folder->serverid = $id;
893            // explode hierarchy
894            $fhir = explode("/", $id);
895            if ( substr($id,0,6) == "shared")
896            {
897                $parent="shared";
898            }
899            else
900            {
901                $ftmp=$fhir;
902                array_pop($ftmp);
903                $parent=implode("/", $ftmp);
904            }
905            //get annotation type
906            // compare on lowercase strings
907            $lid = strtolower($id);
908            $fimap=$id;
909            if($lid == "inbox") {
910                $folder->parentid = "0"; // Root
911                $folder->displayname = "Inbox";
912                $folder->type = SYNC_FOLDER_TYPE_INBOX;
913            }
914            // courier-imap outputs
915            else if($lid == "inbox/drafts") {
916                $folder->parentid = $fhir[0];
917                $folder->displayname = "Drafts";
918                $folder->type = SYNC_FOLDER_TYPE_DRAFTS;
919            }
920            else if($lid == "inbox/trash") {
921                $folder->parentid = $fhir[0];
922                $folder->displayname = "Trash";
923                $folder->type = SYNC_FOLDER_TYPE_WASTEBASKET;
924                $this->_wasteID = $id;
925            }
926            else if($lid == "inbox/sent") {
927                $folder->parentid = $fhir[0];
928                $folder->displayname = "Sent";
929                $this->sentFolder=$id;
930                $folder->type = SYNC_FOLDER_TYPE_SENTMAIL;
931                $this->_sentID = $id;
932            }
933            // define the rest as other-folders
934            //check if flatmode
935
936            else if ( $this->foMode == False && $id == "VIRTUAL/calendar")
937            {
938                $folder->parentid ="VIRTUAL";
939                $folder->displayname = $id;
940                $folder->type = SYNC_FOLDER_TYPE_APPOINTMENT;
941                $this->_sentID = $id;
942            }
943            else if ( $this->foMode == False && $id == "VIRTUAL/contacts")
944            {
945                $folder->parentid = "VIRTUAL";
946                $folder->displayname = "Contacts";
947                $folder->type = SYNC_FOLDER_TYPE_CONTACT;
948                $this->_sentID = $id;
949            }
950            else if ( $this->foMode == False && $id == "VIRTUAL/tasks")
951            {
952                $folder->parentid = "VIRTUAL";
953                $folder->displayname = $id;
954                $folder->type = SYNC_FOLDER_TYPE_TASK;
955                $this->_sentID = $id;
956            }
957            else if ( $this->kolabfolderType($id) == 1)
958            {
959                //contact kolab
960                $folder->parentid = $parent;
961                $folder->displayname = $this->folderDisplayName($id);
962                $folder->type = $this->ActiveSyncFolderSyncType($id); 
963                $this->_sentID = $id;
964
965            }
966            else if ($this->kolabfolderType($id) == 2)
967            {
968
969                // shared folder in UPPER ,
970                $folder->parentid = $parent;
971                $folder->displayname =  $this->folderDisplayName($id); 
972                $folder->type = $this->ActiveSyncFolderSyncType($id);
973                $this->_sentID = $id;
974            }
975            else if ($this->kolabfolderType($id) == 3)
976            {
977                $folder->parentid = $parent;
978                $folder->displayname =  $this->folderDisplayName($id);   
979                $folder->type = $this->ActiveSyncFolderSyncType($id);
980                $this->_sentID = $id;
981            }
982            else {
983                if (count($fhir) > 1) {
984
985                    $folder->displayname = windows1252_to_utf8(imap_utf7_decode(array_pop($fhir)));
986                    $folder->parentid = implode("/", $fhir);
987                }
988                else {
989                    $folder->displayname = windows1252_to_utf8(imap_utf7_decode($id));
990                    $folder->parentid = "0";
991                }
992                $folder->type = SYNC_FOLDER_TYPE_OTHER;
993            }
994
995            //advanced debugging
996            //debugLog("IMAP-GetFolder(id: '$id') -> " . print_r($folder, 1));
997            return $folder;
998        }
999
1000        /* Return folder stats. This means you must return an associative array with the
1001        * following properties:
1002        * "id" => The server ID that will be used to identify the folder. It must be unique, and not too long
1003        *         How long exactly is not known, but try keeping it under 20 chars or so. It must be a string.
1004        * "parent" => The server ID of the parent of the folder. Same restrictions as 'id' apply.
1005        * "mod" => This is the modification signature. It is any arbitrary string which is constant as long as
1006        *          the folder has not changed. In practice this means that 'mod' can be equal to the folder name
1007        *          as this is the only thing that ever changes in folders. (the type is normally constant)
1008        */
1009        private function folderDisplayName($folder)
1010        {
1011
1012            $f = explode("/", $folder);
1013            if (substr($f[0],0,6) == "shared" )
1014            {
1015                // shared folder in UPPER
1016                $s=explode(".",$folder) ;
1017                return strtoupper(windows1252_to_utf8(imap_utf7_decode($s[1])));
1018
1019            }
1020            if ($f[0] == "INBOX")
1021            {
1022                $type=$this->readFolderAnnotation($folder);
1023                if ($type =="contact.default" || $type =="event.default" || $type =="task.default")
1024                {
1025                    //default folder all min lowaercase
1026
1027                    $r=windows1252_to_utf8(imap_utf7_decode($f[1]));
1028                    return strtolower(windows1252_to_utf8(imap_utf7_decode(array_pop($f))));
1029                }
1030                else
1031                {
1032                    //others    AA problem when we have sub sub folder
1033                    //must keep the last one
1034                    return ucfirst(windows1252_to_utf8(imap_utf7_decode(array_pop($f))));
1035                }
1036            }
1037            if ($f[0] == "user")
1038            {
1039                $type=$this->readFolderAnnotation($folder);
1040                $t=explode(".",$type);
1041
1042                //find the user
1043                $fname=array_pop($f);
1044                $r=windows1252_to_utf8(imap_utf7_decode($fname."(".$f[1].")"));
1045                return windows1252_to_utf8($r);
1046            }
1047        }
1048        function StatFolder($id) {
1049
1050            $folder = $this->GetFolder($id);
1051
1052            $stat = array();
1053            $stat["id"] = $id;
1054            $stat["parent"] = $folder->parentid;
1055            $stat["mod"] = $folder->displayname;
1056
1057            return $stat;
1058        }
1059
1060        /* Creates or modifies a folder
1061        * "folderid" => id of the parent folder
1062        * "oldid" => if empty -> new folder created, else folder is to be renamed
1063        * "displayname" => new folder name (to be created, or to be renamed to)
1064        * "type" => folder type, ignored in IMAP
1065        *
1066        */
1067        function ChangeFolder($folderid, $oldid, $displayname, $type){
1068            debugLog("ChangeFolder: (parent: '$folderid'  oldid: '$oldid'  displayname: '$displayname'  type: '$type')");
1069
1070            // go to parent mailbox
1071            $this->imap_reopenFolder($folderid);
1072
1073            // build name for new mailbox
1074            $newname = $this->_server . str_replace(".", $this->_serverdelimiter, $folderid) . $this->_serverdelimiter . $displayname;
1075
1076            $csts = false;
1077            // if $id is set => rename mailbox, otherwise create
1078            if ($oldid) {
1079                // rename doesn't work properly with IMAP
1080                // the activesync client doesn't support a 'changing ID'
1081                //$csts = imap_renamemailbox($this->_mbox, $this->_server . imap_utf7_encode(str_replace(".", $this->_serverdelimiter, $oldid)), $newname);
1082                }
1083            else {
1084                $csts = @imap_createmailbox($this->_mbox, $newname);
1085            }
1086            if ($csts) {
1087                return $this->StatFolder($folderid . "." . $displayname);
1088            }
1089            else
1090            return false;
1091        }
1092
1093        /* Should return attachment data for the specified attachment. The passed attachment identifier is
1094        * the exact string that is returned in the 'AttName' property of an SyncAttachment. So, you should
1095        * encode any information you need to find the attachment in that 'attname' property.
1096        */   
1097        function GetAttachmentData($attname) {
1098            debugLog("getAttachmentDate: (attname: '$attname')");   
1099
1100            list($folderid, $id, $part) = explode(":", $attname);
1101
1102            $this->imap_reopenFolder($folderid);
1103            $mail = @imap_fetchheader($this->_mbox, $id, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $id, FT_PEEK | FT_UID);
1104
1105            $mobj = new Mail_mimeDecode($mail);
1106            $message = $mobj->decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $mail, 'crlf' => "\n", 'charset' => 'utf-8'));
1107
1108            if (isset($message->parts[$part]->body))
1109            print $message->parts[$part]->body;
1110
1111            // unset mimedecoder & mail
1112            unset($mobj);           
1113            unset($mail);   
1114            return true;
1115        }
1116
1117        /* StatMessage should return message stats, analogous to the folder stats (StatFolder). Entries are:
1118        * 'id'     => Server unique identifier for the message. Again, try to keep this short (under 20 chars)
1119        * 'flags'     => simply '0' for unread, '1' for read
1120        * 'mod'    => modification signature. As soon as this signature changes, the item is assumed to be completely
1121        *             changed, and will be sent to the PDA as a whole. Normally you can use something like the modification
1122        *             time for this field, which will change as soon as the contents have changed.
1123        */
1124
1125        function StatMessage($folderid, $id) {
1126            debugLog("IMAP-StatMessage: (fid: '$folderid'  id: '$id' )");   
1127            //search the imap id
1128            if ( $this->kolabFolderType($folderid))
1129            {
1130                //in case of synchor app or contacts we work with kolab_uid
1131               
1132                if (substr($folderid,0,7) == "VIRTUAL")
1133                {
1134                    //must find the right folder
1135                    $folderid=$this->CacheIndexUid2FolderUid($id);
1136                    debugLog("StatMessage Flmode: $id - > $folderid");
1137                    $this->Log("NOTICE StatMessage Flmode: $id - > $folderid");
1138                }
1139                $imap_id=$this->CacheIndexUid2Id($folderid,$id);
1140                if ($imap_id)
1141                {
1142                    $entry=array();
1143                    $entry["mod"]=$folderid ."/".$imap_id;
1144                    $entry["id"]=$id;
1145                    $entry["flags"] = 0;
1146                    return $entry;
1147                }
1148                else
1149                {
1150                    //kolab_uid -> imap_id must be exist
1151                    debugLog("StatMessage: Failed to retrieve imap_id from index: ". $id);     
1152                    return false;
1153                }
1154            }
1155            //normal case for imap mails synchro
1156
1157            $this->imap_reopenFolder($folderid); 
1158            $overview = @imap_fetch_overview( $this->_mbox , $id , FT_UID);
1159
1160            if (!$overview) {
1161                debugLog("IMAP-StatMessage: Failed to retrieve overview: ". imap_last_error());
1162                return false;
1163            }
1164            else {
1165                // check if variables for this overview object are available           
1166                $vars = get_object_vars($overview[0]);
1167
1168                // without uid it's not a valid message
1169                if (! array_key_exists( "uid", $vars)) return false;
1170
1171                $entry = array();
1172                $entry["mod"] = (array_key_exists( "date", $vars)) ? $overview[0]->date : "";
1173                $entry["id"] = $overview[0]->uid;
1174                // 'seen' aka 'read' is the only flag we want to know about
1175                $entry["flags"] = 0;
1176
1177                if(array_key_exists( "seen", $vars) && $overview[0]->seen)
1178                $entry["flags"] = 1;
1179            }
1180            //advanced debugging
1181            //debugLog("IMAP-StatMessage-parsed: ". print_r($entry,1));
1182
1183            return $entry;
1184
1185        }
1186
1187        /* GetMessage should return the actual SyncXXX object type. You may or may not use the '$folderid' parent folder
1188        * identifier here.
1189        * Note that mixing item types is illegal and will be blocked by the engine; ie returning an Email object in a
1190        * Tasks folder will not do anything. The SyncXXX objects should be filled with as much information as possible,
1191        * but at least the subject, body, to, from, etc.
1192        */
1193        function GetMessage($folderid, $id, $truncsize) {
1194            debugLog("KOLAB-GetMessage: (fid: '$folderid'  id: '$id'  truncsize: $truncsize)");
1195            // Get flags, etc 
1196 
1197            $stat = $this->StatMessage($folderid, $id);
1198            if ($stat) { 
1199                if ( $this->kolabFolderType($folderid))
1200                {
1201                    //get the imap_id 
1202                    $imap_id=array_pop(explode("/",$stat['mod']));
1203                    //$imap_id=$stat['mod'];
1204
1205                    if ( substr($folderid,0,7) == "VIRTUAL")
1206                    {
1207
1208                        $folderid=$this->CacheIndexUid2FolderUid($id);
1209                        debugLog("GetMessage Flmode: $id - > $folderid");
1210                        $this->Log("NOTICE GetMessage Flmode: $id - > $folderid");
1211                    }
1212                }   
1213                else
1214                {
1215                    $imap_id=$id;
1216                }
1217                $this->imap_reopenFolder($folderid);
1218                $mail = @imap_fetchheader($this->_mbox, $imap_id, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $imap_id, FT_PEEK | FT_UID);
1219
1220                $mobj = new Mail_mimeDecode($mail);
1221                $message = $mobj->decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $mail, 'crlf' => "\n", 'charset' => 'utf-8'));
1222
1223                if ($this->kolabFolderType($folderid) == 1)
1224                {
1225                    $output=$this->KolabReadContact($message,0);
1226                    $this->Log("Changed on Server C: $folderid /" .$id. "imap id : " .$imap_id );
1227                    $this->Log("                  : " . u2w($output->fileas));
1228                    $this->CacheCreateIndex($folderid,$id,$imap_id);
1229                    return $output;
1230                }
1231                elseif ($this->kolabFolderType($folderid) == 2 )
1232                {
1233                    //bug #9 we must test if we want alarms or not
1234                    // for the moment disable it if namespace <> INBOX
1235                    $fa=$this->CacheReadFolderParam($folderid);
1236                    $fa->setFolder($folderid)  ;
1237                    if ( $fa->showAlarm($this->_devid))
1238                    {   
1239                        $output=$this->KolabReadEvent($message,$id,false)   ;    //alarm must be shown
1240                        }
1241                    else
1242                    {
1243                        $output=$this->KolabReadEvent($message,$id,true)   ; 
1244                    }
1245                    $this->Log("Changed on Server A: $folderid/" .$id );
1246                    $this->Log("                  : " . u2w($output->subject));
1247                    $this->CacheCreateIndex($folderid,$id,$imap_id)   ;
1248                    $this->CacheWriteSensitivity($id,$output->sensitivity);
1249                    return $output;
1250                }
1251                elseif ($this->kolabFolderType($folderid) == 3 )
1252                {   
1253                   
1254                    $output=$this->KolabReadTask($message,$id)   ;
1255                    $this->Log("Changed on Server T: $folderid /" .$id );
1256                    $this->Log("                  : " . u2w($output->subject));
1257                    $this->CacheCreateIndex($folderid,$id,$imap_id)   ;
1258                    //rewrite completion
1259                    $this->CacheWriteTaskCompleted($id,$output->completed);
1260                    $this->CacheWriteSensitivity($id,$output->sensitivity);
1261                    return $output;
1262                }
1263                else
1264                {
1265                    $output = new SyncMail();
1266
1267                    // decode body to truncate it
1268                    $body = utf8_to_windows1252($this->getBody($message));
1269                    $truncsize=2048;
1270                    if(strlen($body) > $truncsize) {
1271                        $body = substr($body, 0, $truncsize);
1272                        $output->bodytruncated = 1;
1273                    } else {
1274                        $body = $body;
1275                        $output->bodytruncated = 0;
1276                    }
1277                    $body = str_replace("\n","\r\n", windows1252_to_utf8(str_replace("\r","",$body)));
1278
1279                    $output->bodysize = strlen($body);
1280                    $output->body = $body;
1281                    $output->datereceived = isset($message->headers["date"]) ? strtotime($message->headers["date"]) : null;
1282                    $output->displayto = isset($message->headers["to"]) ? $message->headers["to"] : null;
1283                    $output->importance = isset($message->headers["x-priority"]) ? preg_replace("/\D+/", "", $message->headers["x-priority"]) : null;
1284                    $output->messageclass = "IPM.Note";
1285                    $output->subject = isset($message->headers["subject"]) ? $message->headers["subject"] : "";
1286                    $output->read = $stat["flags"];
1287                    $output->to = isset($message->headers["to"]) ? $message->headers["to"] : null;
1288                    $output->cc = isset($message->headers["cc"]) ? $message->headers["cc"] : null;
1289                    $output->from = isset($message->headers["from"]) ? $message->headers["from"] : null;
1290                    $output->reply_to = isset($message->headers["reply-to"]) ? $message->headers["reply-to"] : null;
1291
1292                    // Attachments are only searched in the top-level part
1293                    $n = 0;
1294                    if(isset($message->parts)) {
1295                        foreach($message->parts as $part) {
1296                            if(isset($part->disposition) && ($part->disposition == "attachment" || $part->disposition == "inline")) {
1297                                $attachment = new SyncAttachment();
1298
1299                                if (isset($part->body))
1300                                $attachment->attsize = strlen($part->body);
1301
1302                                if(isset($part->d_parameters['filename']))
1303                                $attname = $part->d_parameters['filename'];
1304                                else if(isset($part->ctype_parameters['name']))
1305                                $attname = $part->ctype_parameters['name'];
1306                                else if(isset($part->headers['content-description']))
1307                                $attname = $part->headers['content-description'];
1308                                else $attname = "unknown attachment";
1309
1310                                $attachment->displayname = $attname;
1311                                $attachment->attname = $folderid . ":" . $id . ":" . $n;
1312                                $attachment->attmethod = 1;
1313                                $attachment->attoid = isset($part->headers['content-id']) ? $part->headers['content-id'] : "";
1314                                array_push($output->attachments, $attachment);
1315                            }
1316                            $n++;
1317                        }
1318                    }
1319                    // unset mimedecoder & mail
1320                    unset($mobj);
1321                    unset($mail);
1322                    return $output;
1323                }
1324            }
1325            return false;
1326        }
1327
1328        /* This function is called when the user has requested to delete (really delete) a message. Usually
1329        * this means just unlinking the file its in or somesuch. After this call has succeeded, a call to
1330        * GetMessageList() should no longer list the message. If it does, the message will be re-sent to the PDA
1331        * as it will be seen as a 'new' item. This means that if you don't implement this function, you will
1332        * be able to delete messages on the PDA, but as soon as you sync, you'll get the item back
1333        */
1334        function DeleteMessage($folderid, $id) {
1335            debugLog("KOLAB-DeleteMessage: (fid: '$folderid'  id: '$id' )");
1336            if ( $this->kolabFolderType($folderid) >0 )
1337            {
1338                if (substr($folderid,0,7) == "VIRTUAL")
1339                {
1340                    $folderid=$this->CacheIndexUid2FolderUid($id);
1341                    debugLog("DeleteMessage Flmode: $id - > $folderid");
1342                    $this->Log("NOTICE DeleteMessage Flmode: $id - > $folderid");
1343                }
1344
1345                //kolab_uid -> imap_id
1346                $imap_id=$this->CacheIndexUid2Id($folderid,$id);
1347            }   
1348            else
1349            {
1350                $imap_id=$id;
1351            }
1352            $this->imap_reopenFolder($folderid);
1353            $s1 = @imap_delete ($this->_mbox, $imap_id, FT_UID);
1354            $s11 = @imap_setflag_full($this->_mbox, $imap_id, "\\Deleted", FT_UID);
1355            $s2 = @imap_expunge($this->_mbox);
1356            $this->CacheIndexDeletebyId($folderid,$id);
1357            debugLog("IMAP-DeleteMessage: s-delete: $s1   s-expunge: $s2    setflag: $s11");
1358
1359            return ($s1 && $s2 && $s11);
1360        }
1361
1362        /* This should change the 'read' flag of a message on disk. The $flags                                                  r
1363        * parameter can only be '1' (read) or '0' (unread). After a call to
1364        * SetReadFlag(), GetMessageList() should return the message with the
1365        * new 'flags' but should not modify the 'mod' parameter. If you do
1366        * change 'mod', simply setting the message to 'read' on the PDA will trigger
1367        * a full resync of the item from the server
1368        */
1369        function SetReadFlag($folderid, $id, $flags) {
1370            debugLog("IMAP-SetReadFlag: (fid: '$folderid'  id: '$id'  flags: '$flags' )");
1371
1372            $this->imap_reopenFolder($folderid);
1373
1374            if ($flags == 0) {
1375                // set as "Unseen" (unread)
1376                $status = @imap_clearflag_full ( $this->_mbox, $id, "\\Seen", ST_UID);
1377            } else {
1378                // set as "Seen" (read)
1379                $status = @imap_setflag_full($this->_mbox, $id, "\\Seen",ST_UID);
1380            }
1381
1382            debugLog("IMAP-SetReadFlag -> set as " . (($flags) ? "read" : "unread") . "-->". $status);
1383
1384            return $status;
1385        }
1386
1387        /* This function is called when a message has been changed on the PDA. You should parse the new
1388        * message here and save the changes to disk. The return value must be whatever would be returned
1389        * from StatMessage() after the message has been saved. This means that both the 'flags' and the 'mod'
1390        * properties of the StatMessage() item may change via ChangeMessage().
1391        * Note that this function will never be called on E-mail items as you can't change e-mail items, you
1392        * can only set them as 'read'.
1393        */
1394        function ChangeMessage($folderid, $id, $message) {
1395   
1396            $modify=false;
1397            $this->Log("PDA Folder : " . $folderid .  "  object uid : " . $id);
1398            if (substr($folderid,0,6) == "shared" && KOLAB_SHAREDFOLDERS_RO  ==1 )
1399            {
1400                //shared folders are protected
1401                $this->Log("PDA Folder : READ ONLY Cancel " . $folderid .  "  object uid : " . $id);
1402                return false;
1403            }
1404            if ( $id != FALSE )
1405            {                                                                             
1406                //finding the kolab_uid for this id
1407                if ( $this->kolabFolderType($folderid)> 0)
1408                {
1409                    if (substr($folderid,0,7) == "VIRTUAL")
1410                    {
1411                        $folderid=$this->CacheIndexUid2FolderUid($id);
1412                        debugLog("ChangeMessage Flmode: $id - > $folderid");
1413                        $this->Log("NOTICE ChangeMessage Flmode: $id - > $folderid");
1414                    }
1415                    //message exist on the server delete it
1416                    $imap_id=$this->CacheIndexUid2Id($folderid,$id);
1417                    $this->imap_reopenFolder($folderid);
1418                    $s1 = @imap_delete ($this->_mbox, $imap_id, FT_UID);
1419                    $s11 = @imap_setflag_full($this->_mbox, $imap_id, "\\Deleted", FT_UID);
1420                    $s2 = @imap_expunge($this->_mbox);
1421                    $this->Log("Change delete imap message : " . $folderid . " " . $imap_id)  ;
1422                    $kolab_uid=$id;
1423                    $modify=true;
1424                }
1425                else
1426                {
1427                    //delete du mail
1428                    $this->DeleteMessage($folderid,$id);
1429                }
1430            }                                                                               
1431            // mail is an Array [uid,date,RFC822Message]      *
1432            if ($folderid == "VIRTUAL/calendar")
1433            {
1434                $folderid=$this->CacheGetDefaultFolder("event");
1435            }
1436            if ($folderid == "VIRTUAL/contacts")
1437            {
1438                $folderid=$this->CacheGetDefaultFolder("contact");
1439            }
1440            if ($folderid == "VIRTUAL/tasks")
1441            {
1442                $folderid=$this->CacheGetDefaultFolder("task");
1443            }
1444
1445            if ( $this->kolabFolderType($folderid) == 1)
1446            {
1447                $mail=$this->KolabWriteContact($message,$kolab_uid);
1448
1449            }
1450            elseif ($this->kolabFolderType($folderid) == 2)
1451            {
1452
1453                $mail=$this->KolabWriteEvent($message,$kolab_uid);
1454            }
1455            elseif ($this->kolabFolderType($folderid) == 3)
1456            {
1457                $mail=$this->KolabWriteTask($message,$kolab_uid);
1458            }
1459            // now we can insert it again
1460            $this->imap_reopenFolder($folderid);
1461            $info=imap_status($this->_mbox, $this->_server . $folderid, SA_ALL)  ;   
1462            $r=@imap_append($this->_mbox,$this->_server . $folderid,$mail[2] ,"\\Seen");
1463            $id=$info->uidnext;     
1464            if ( $r == TRUE)   
1465            {
1466                $this->Log("create message : " . $folderid . " " . $id)  ;   
1467                $this->CacheCreateIndex($folderid,$mail[0],$id);
1468                if ( $this->kolabFolderType($folderid) ==2)
1469                {
1470                    //cache the end date
1471                    $this->CacheWriteEndDate($folderid,$message) ;   
1472
1473                }
1474                if ($this->kolabFolderType($folderid) == 3)
1475                {
1476                    $this->CacheWriteTaskCompleted($id,$message->completed);
1477                    $this->CacheWriteSensitivity($id,$message->sensitivity);
1478                }
1479                $entry["mod"] = $folderid ."/".$id;
1480                $entry["id"]=strtoupper($mail[0]);
1481                $entry["flags"]=0;
1482                return $entry;
1483            }
1484            $this->Log("IMAP can't add mail : " . imap_last_error());
1485            return false;
1486        }
1487
1488        /* This function is called when the user moves an item on the PDA. You should do whatever is needed
1489        * to move the message on disk. After this call, StatMessage() and GetMessageList() should show the items
1490        * to have a new parent. This means that it will disappear from GetMessageList() will not return the item
1491        * at all on the source folder, and the destination folder will show the new message
1492        *
1493        */
1494        function MoveMessage($folderid, $id, $newfolderid) {
1495            debugLog("IMAP-MoveMessage: (sfid: '$folderid'  id: '$id'  dfid: '$newfolderid' )");
1496            $this->imap_reopenFolder($folderid);
1497
1498            // read message flags
1499            $overview = @imap_fetch_overview ( $this->_mbox , $id, FT_UID);
1500
1501            if (!$overview) {
1502                debugLog("IMAP-MoveMessage: Failed to retrieve overview");
1503                return false;
1504            }
1505            else {
1506                // move message                   
1507                $s1 = imap_mail_move($this->_mbox, $id, $newfolderid, FT_UID);
1508
1509                // delete message in from-folder
1510                $s2 = imap_expunge($this->_mbox);
1511
1512                // open new folder
1513                $this->imap_reopenFolder($newfolderid);
1514
1515                // remove all flags
1516                $s3 = @imap_clearflag_full ($this->_mbox, $id, "\\Seen \\Answered \\Flagged \\Deleted \\Draft", FT_UID);
1517                $newflags = "";
1518                if ($overview[0]->seen) $newflags .= "\\Seen";   
1519                if ($overview[0]->flagged) $newflags .= " \\Flagged";
1520                if ($overview[0]->answered) $newflags .= " \\Answered";
1521                $s4 = @imap_setflag_full ($this->_mbox, $id, $newflags, FT_UID);
1522
1523                debugLog("MoveMessage: (" . $folderid . "->" . $newfolderid . ") s-move: $s1   s-expunge: $s2    unset-Flags: $s3    set-Flags: $s4");
1524
1525                return ($s1 && $s2 && $s3 && $s4);
1526            }
1527        }
1528
1529        // ----------------------------------------
1530        // imap-specific internals
1531
1532        /* Parse the message and return only the plaintext body
1533        */
1534        function getBody($message) {
1535            $body = "";
1536            $htmlbody = "";
1537
1538            $this->getBodyRecursive($message, "plain", $body);
1539
1540            if(!isset($body) || $body === "") {
1541                $this->getBodyRecursive($message, "html", $body);
1542                // remove css-style tags
1543                $body = preg_replace("/<style.*?<\/style>/is", "", $body);
1544                // remove all other html
1545                $body = strip_tags($body);
1546            }
1547
1548            return $body;
1549        }
1550
1551        // Get all parts in the message with specified type and concatenate them together, unless the
1552        // Content-Disposition is 'attachment', in which case the text is apparently an attachment
1553        function getBodyRecursive($message, $subtype, &$body) {
1554            if(!isset($message->ctype_primary)) return;
1555            if(strcasecmp($message->ctype_primary,"text")==0 && strcasecmp($message->ctype_secondary,$subtype)==0 && isset($message->body))
1556            $body .= $message->body;
1557
1558            if(strcasecmp($message->ctype_primary,"multipart")==0 && isset($message->parts) && is_array($message->parts)) {
1559                foreach($message->parts as $part) {
1560                    if(!isset($part->disposition) || strcasecmp($part->disposition,"attachment"))  {
1561                        $this->getBodyRecursive($part, $subtype, $body);
1562                    }
1563                }
1564            }
1565        }
1566
1567        // save the serverdelimiter for later folder (un)parsing
1568        function getServerDelimiter() {
1569            $list = @imap_getmailboxes($this->_mbox, $this->_server, "*");
1570            if (is_array($list)) {
1571                $val = $list[0];   
1572
1573                return $val->delimiter;
1574            }       
1575            return "."; // default "."
1576            }
1577
1578        // speed things up
1579        // remember what folder is currently open and only change if necessary
1580        function imap_reopenFolder($folderid, $force = false) {
1581            // to see changes, the folder has to be reopened!
1582            if ($this->_mboxFolder != $folderid || $force) {
1583                $s = @imap_reopen($this->_mbox, $this->_server . $folderid);
1584                if (!$s) debugLog("failed to change folder: ". implode(", ", imap_errors()));
1585                $this->_mboxFolder = $folderid;
1586            }
1587        }
1588
1589
1590        // build a multipart email, embedding body and one file (for attachments)
1591        function mail_attach($filenm,$filesize,$file_cont,$body, $body_ct, $body_cte,$file_ct,$picture=null) {
1592
1593            $boundary = strtoupper(md5(uniqid(time())));
1594            if ( $file_ct == "")
1595            {
1596                $file_ct="text/plain"  ;
1597            }   
1598            $mail_header = "Content-Type: multipart/mixed; boundary=$boundary\r\n";
1599
1600            // build main body with the sumitted type & encoding from the pda
1601            $mail_body  = "This is a multi-part message in MIME format\r\n\r\n";
1602            $mail_body .= "--$boundary\r\n";
1603            $mail_body .= "Content-Type:$body_ct\r\n";
1604            if ($body_cte != "")
1605            {
1606                $mail_body .= "Content-Transfer-Encoding:$body_cte\r\n\r\n";
1607            }
1608            $mail_body .= "$body\r\n\r\n";
1609
1610            $mail_body .= "--$boundary\r\n";
1611            $mail_body .= "Content-Type: ".$file_ct."; name=\"$filenm\"\r\n";
1612            $mail_body .= "Content-Transfer-Encoding: base64\r\n";
1613            $mail_body .= "Content-Disposition: attachment; filename=\"$filenm\"\r\n";
1614            $mail_body .= "Content-Description: $filenm\r\n\r\n";
1615            $mail_body .= base64_encode($file_cont) . "\r\n\r\n";
1616
1617
1618            if ( $picture)
1619            {
1620                //add picture
1621                $mail_body .= "--$boundary\r\n"; 
1622                $mail_body .= "Content-Type: image/jpeg; name=\"photo.jpeg\"\r\n";
1623                $mail_body .= "Content-Transfer-Encoding: base64\r\n";
1624                $mail_body .= "Content-Disposition: attachment; filename=\"photo.jpeg\"\r\n\r\n";
1625                $mail_body .=$picture . "\r\n\r\n"; 
1626
1627            }
1628            $mail_body .= "--$boundary--\r\n\r\n"; 
1629            return array($mail_header, $mail_body);
1630        }
1631
1632        // adds a message as seen to a specified folder (used for saving sent mails)
1633        function addSentMessage($folderid, $header, $body) {
1634            return @imap_append($this->_mbox,$this->_server . $folderid, $header . "\r\n" . $body ,"\\Seen");
1635        }
1636
1637
1638        // parses address objects back to a simple "," separated string
1639        function parseAddr($ad) {
1640            $addr_string = "";
1641            if (isset($ad) && is_array($ad)) {
1642                foreach($ad as $addr) {
1643                    if ($addr_string) $addr_string .= ",";
1644                    $addr_string .= $addr->mailbox . "@" . $addr->host;
1645                }
1646            }
1647            return $addr_string;
1648        }
1649
1650        private function KolabReadContact($message,$with_uid)
1651        {
1652               
1653            $contact=NULL; 
1654            $kolabXml=NULL;
1655            $images=array();
1656            if(isset($message->parts))
1657            {
1658                $parts=$message->parts;
1659                foreach($parts as $part)
1660                {
1661                    if(isset($part->disposition) && ($part->disposition == "attachment" || $part->disposition == "inline"))
1662                    {
1663                        $type=$part->headers;
1664                        //kolab contact attachment ?
1665                        $ctype=explode(";",$type["content-type"] )  ;
1666                        if ($ctype[0] == " application/x-vnd.kolab.contact")
1667                        {
1668                            $kolabXml=$part->body;
1669                        }
1670                        if ($ctype[0] == " image/jpeg")
1671                        {
1672                            $name=$part->ctype_parameters["name"]; 
1673                            $images[$name]=$part->body;
1674                        }
1675                        $n++;
1676                    }
1677                }
1678                if (! $kolabXml)
1679                {
1680                    //nothing in the mail
1681                    return "";
1682                }
1683                //processing
1684                $factory=new Horde_Kolab_Format;
1685                $format = $factory->factory('XML', 'contact'); 
1686                $kcontact=$format->load($kolabXml);
1687                unset($format);
1688                unset($factory);
1689                if ($kcontact instanceof PEAR_Error)
1690                {
1691                    //parsing error
1692                    debugLog("ERROR ".$kcontact->message);
1693                    debugLog("Xml kolab :     $body")  ;
1694                    $this->Log("ERROR ".$kcontact->message);
1695                    $this->Log("XML : $body")  ;   
1696                    unset($kcontact);
1697                    return "";
1698
1699                } 
1700                //mappage
1701                $contact=new SyncContact();   
1702                if ( $with_uid != 0)
1703                {
1704                    $contact->uid= hex2bin($kcontact['uid']);
1705                }
1706                $contact->fileas= w2u($kcontact['last-name'].", " . $kcontact['given-name']);
1707                $contact->firstname= w2u($kcontact['given-name'])   ;
1708                $contact->lastname= w2u($kcontact['last-name']);
1709                $contact->middlename=w2u($kcontact['middle-names']);
1710                $contact->webpage=$kcontact['web-page'] ;
1711                $contact->jobtitle=w2u($kcontact["job-title"]) ;
1712                $contact->title=w2u($kcontact["prefix"]) ;
1713                $contact->suffix=w2u($kcontact['suffix']);
1714                $contact->companyname =w2u($kcontact['organization']) ;
1715                $contact->email1address=$kcontact['emails'];
1716                if ( isset($kcontact["picture"]))
1717                {
1718                    $contact->picture=base64_encode($images[$kcontact["picture"]]);
1719                    $this->CacheWritePicture($kcontact['uid'],$contact->picture);
1720                }
1721                if (isset($kcontact["phone-business1"]))
1722                {
1723                    if ( $this->checkPhoneNumber($kcontact["phone-business1"]))
1724                    {
1725                        $contact->businessphonenumber=$kcontact["phone-business1"] ;
1726                    }
1727                    else
1728                    {
1729                        $this->Log("ERR: ".$contact->fileas ." ---> " . $kcontact["phone-business1"] );
1730                    }
1731                }
1732                if (isset($kcontact["phone-business2"]))
1733                {
1734                    if ( $this->checkPhoneNumber($kcontact["phone-business2"]))
1735                    {
1736                        $contact->business2phonenumber=$kcontact["phone-business1"] ;
1737                    }
1738                    else
1739                    {
1740                        $this->Log("ERR: ".$contact->fileas ." ---> " . $kcontact["phone-business2"] );
1741                    }
1742                }
1743                if (isset($kcontact["phone-home1"]))
1744                {
1745                    if ( $this->checkPhoneNumber($kcontact["phone-home1"]))
1746                    {
1747                        $contact->homephonenumber=$kcontact["phone-home1"] ;
1748                    }
1749                    else
1750                    {
1751                        $this->Log("ERR: ".$contact->fileas ." ---> " . $kcontact["phone-home1"] );
1752                    }
1753                }
1754                if (isset($kcontact["phone-mobile"]))
1755                {
1756                    if ( $this->checkPhoneNumber($kcontact["phone-mobile"]))
1757                    {
1758                        $contact->mobilephonenumber=$kcontact["phone-mobile"] ;
1759                    }
1760                    else
1761                    {
1762                        $this->Log("ERR: ".$contact->fileas ." ---> " . $kcontact["phone-mobile"] );
1763                    }
1764                }
1765                if (isset($kcontact["phone-businessfax"]))
1766                {
1767                    if ( $this->checkPhoneNumber($kcontact["phone-businessfax"]))
1768                    {
1769                        $contact->businessfaxnumber=$kcontact["phone-businessfax"] ;
1770                    }
1771                    else
1772                    {
1773                        $this->Log("ERR: ".$contact->fileas ." ---> " . $kcontact["phone-businessfax"] );
1774                    }
1775                }
1776                $contact->otherstreet=w2u($kcontact["addr-other-street"]);
1777                $contact->othercity=w2u($kcontact["addr-other-locality"]);
1778                $contact->otherpostalcode=$kcontact["addr-other-postal-code"];
1779                $contact->otherstate=$kcontact["addr-other-region"]   ;   
1780                $contact->othercountry=w2u($kcontact["addr-other-country"]);
1781                $contact->businessstreet=w2u($kcontact["addr-business-street"]);
1782                $contact->businesscity=w2u($kcontact["addr-business-locality"]);
1783                $contact->businesspostalcode=$kcontact["addr-business-postal-code"];
1784                $contact->businessstate=$kcontact["addr-business-region"]   ;   
1785                $contact->businesscountry=w2u($kcontact["addr-business-country"]);
1786                $contact->homestreet=w2u($kcontact["addr-home-street"]);
1787                $contact->homecity=w2u($kcontact["addr-home-locality"]);
1788                $contact->homepostalcode=$kcontact["addr-home-postal-code"];
1789                $contact->homestate=$kcontact["addr-home-region"]   ;
1790                $contact->homecountry=w2u($kcontact["addr-home-country"]);
1791                $contact->body=w2u($kcontact['body'] );
1792                $contact->spouse=w2u($kcontact['spouse-name']);
1793                $contact->nickname=w2u($kcontact['nick-name']);
1794                $contact->pagernumber=w2u($kcontact['phone-pager']);
1795                $contact->assistantname=w2u($kcontact['assistant']);
1796                $contact->department=w2u($kcontact['department']);
1797                $contact->officelocation=w2u($kcontact{'office-location'});
1798                if (isset($kcontact['anniversary']))
1799                {
1800                    $contact->anniversary=$this->KolabDate2Unix($kcontact['anniversary']);
1801                }
1802                if (isset($kcontact['birthday']))
1803                {     
1804                    $contact->birthday=$this->KolabDate2Unix($kcontact['birthday']);
1805                }
1806                if ($kcontact["children"])
1807                {
1808                    $children=array();
1809                    $children[]= $kcontact["children"];
1810                    $contact->children=$children;
1811                }
1812                if ($contact->fileas == false)
1813                {
1814                    $contact->fileas =w2u($kcontact["organization"]);
1815                }
1816                if ($contact->fileas == false)
1817                {
1818                    $contact->fileas =$kcontact["phone-mobile"];
1819                }
1820                if ($contact->fileas == false)
1821                {
1822                    $contact->fileas =$kcontact["phone-business1"];
1823                }
1824                if ($contact->fileas == false)
1825                {
1826                    $this->Log("ERR: fileAs empty" );
1827                }
1828                return $contact;
1829            }
1830            return ""     ;
1831        }
1832        private function checkPhoneNumber($phone)
1833        {
1834            if (preg_match( '/^[0-9,\+,\*,\#,\(,\),\s,\.\-]+$/', $phone))
1835            {
1836                return $phone;
1837            }   
1838            return "";
1839        }
1840        private function KolabWriteContact($message,$uid)
1841        {
1842            if ( $uid == '')
1843            {
1844                $uid =  strtoupper(md5(uniqid(time())));
1845            }
1846            $object = array(
1847            'uid' => $uid,
1848            'full-name' => u2w($message->asfile) ,
1849            'given-name' =>u2w($message->firstname),
1850            'last-name' => u2w($message->lastname),
1851            'middle-names' => u2w($message->middlename),
1852            'prefix' => u2w($message->title),
1853            'suffix' => u2w($message->suffix),
1854            'job-title' => u2w($message->jobtitle),
1855            'web-page' => $message->webpage,
1856            'emails' => $message->email1address,
1857            'phone-mobile' => $message->mobilephonenumber,
1858            'phone-business1' => $message->businessphonenumber,
1859            'phone-business2' => $message->business2phonenumber,
1860            'phone-home1' => $message->homephonenumber,
1861            'phone-pager' => $message->pagernumber,
1862            'phone-businessfax' => $message->businessfaxnumber,
1863            'addr-business-street' => u2w($message->businessstreet),
1864            'addr-business-locality' => u2w($message->businesscity),
1865            'addr-business-postal-code' => $message->businesspostalcode,
1866            'addr-business-region' => $message->businessstate,
1867            'addr-business-country' => $message->businesscountry,
1868            'addr-home-street'=> u2w($message->homestreet),
1869            'addr-home-locality'  => u2w($message->homecity)  ,
1870            'addr-home-postal-code' => $message->homepostalcode,
1871            'addr-home-region' => $message->homesstate, 
1872            'addr-home-country' => $message->homecountry, 
1873            'addr-other-street'=> u2w($message->otherstreet),
1874            'addr-other-locality'  => u2w($message->othercity)  ,
1875            'addr-other-postal-code' => $message->otherpostalcode,
1876            'addr-other-region' => $message->othersstate, 
1877            'addr-other-country' => $message->othercountry,             
1878            'organization' => u2w($message->companyname) ,
1879            'department' => u2w($message->department), 
1880            'spouse-name'=> u2w($message->spouse),
1881            'children' =>u2w($message->children),
1882            'nick-name'=> u2w($message->nickname),
1883            'assistant' => u2w($message->assistantname),
1884            'department' => u2w($message->department) ,
1885            'office-location' => u2w($message->officelocation)
1886            );
1887            if ($message->body != "")
1888            {
1889                $object['body']=u2w($message->body);
1890            }
1891            elseif ($message->rtf)
1892            {
1893                $object['body']=$this->rtf2text($message->rtf);
1894            }
1895            //bithday
1896            if (  isset($message->anniversary))
1897            {
1898                $object['anniversary'] =substr($this->KolabDateUnix2Kolab($message->anniversary),0,10);
1899            }
1900            if (  isset($message->birthday))
1901            {
1902                $object['birthday']  = substr($this->KolabDateUnix2Kolab($message->birthday),0,10);
1903            }
1904            //children
1905            $children=$message->children;
1906            if ($children != NULL)
1907            {
1908                $object['children']=join(",",$children);
1909            }
1910            //picture
1911            if ( is_null($message->picture) )
1912            {
1913                //no image or not modified
1914                //check if picture has been modified
1915                $message->picture=$this->CacheReadPicture($uid);
1916                if ($message->picture)
1917                {
1918                    $object['picture'] ="photo.jpeg";   
1919                }
1920            }
1921            else
1922            {
1923                if ( $message->picture == "")
1924                {
1925                    //erase the picture
1926                    $this->CacheDeletePicture($uid);     
1927                }
1928                else
1929                {
1930                    $object['picture'] ="photo.jpeg";   
1931                    $this->CacheWritePicture($uid,$message->picture);
1932                }
1933            }
1934
1935            //check mail for android
1936            if (preg_match("/\<(.+)\>/",$object['emails'],$m))
1937            {
1938                $object['emails']=$m[1];
1939            }
1940            //fulname empty    (happen sometimes with iphone)
1941            if ( $object['full-name'] == "")
1942            {
1943                $object['full-name']= $object['given-name']. ' ' . $object['last-name'];
1944            }
1945            $format = Horde_Kolab_Format::factory('XML', 'contact'); 
1946            $xml = $format->save($object);
1947            unset($format);
1948            // set the mail
1949            // attach the XML file
1950            $mail=$this->mail_attach("kolab.xml",0,$xml,"kolab message","text/plain", "plain","application/x-vnd.kolab.contact",$message->picture);
1951            //add the picture if needed
1952            //add header
1953            $h["from"]=$this->_email;
1954            $h["to"]=$this->_email;
1955            $h["X-Mailer"]="z-push-Kolab Backend";
1956            $h["subject"]= $object["uid"];
1957            $h["message-id"]= "<" . strtoupper(md5(uniqid(time()))) . ">";
1958            $h["date"]=date(DATE_RFC2822);
1959            foreach(array_keys($h) as $i)
1960            {
1961                $header= $header . $i . ": " . $h[$i] ."\r\n";
1962            }
1963            //return the mail formatted
1964            return array($uid,$h['date'],$header  .$mail[0]."\r\n" .$mail[1]);
1965
1966        }
1967
1968        private function KolabReadEvent($message,$id,$disableAlarm=false)
1969        {
1970            $event=NULL;
1971            //searching the righ attachment Kolab XML
1972            if(isset($message->parts))
1973            {
1974                foreach($message->parts as $part)
1975                {
1976                    if(isset($part->disposition) && ($part->disposition == "attachment" || $part->disposition == "inline"))
1977                    {
1978                        $type=$part->headers;
1979                        //kolab contact attachment ?
1980                        $ctype=explode(";",$type["content-type"] )  ;
1981                        if ($ctype[0] == " application/x-vnd.kolab.event")
1982                        {
1983                            $format = Horde_Kolab_Format::factory('XML', 'event'); 
1984                            $body=$part->body; 
1985                            $kevent=$format->load($body);
1986                            unset($format);
1987                            if ($kevent instanceof PEAR_Error)
1988                            {
1989                                //parsing error
1990                                debugLog("ERROR ".$kevent->message);
1991                                debugLog("Xml kolab :     $body")  ;
1992                                $this->Log("ERROR ".$kevent->message);
1993                                $this->Log("XML : $body")  ;
1994                                unset ($kevent); 
1995                                return "";
1996                            }
1997
1998                            //mappage
1999                            $event=new SyncAppointment();
2000                            $event->uid = hex2bin($kevent['uid']);
2001                            $event->dtstamp = time();
2002                            $event->subject=w2u($kevent['summary']);
2003                            $event->starttime=$kevent['start-date'];
2004                            $event->endtime=$kevent['end-date'];
2005
2006                            switch(strtolower($kevent['sensitivity']))
2007                            {
2008                                case "private":
2009                                $event->sensitivity="2";
2010                                break;
2011                                case "confidential":
2012                                $event->sensitivity="3";
2013                            }
2014                            //bug #9 Alarm mus not be shown for all folders
2015                            if ($disableAlarm == false)
2016                            {
2017                                if ($kevent['alarm'] > 0)
2018                                {
2019                                    $event->reminder=$kevent['alarm'];
2020                                }
2021                            }
2022                            else
2023                            {
2024                                $event->reminder=NULL;
2025                            }
2026                            $event->location=w2u($kevent['location']);
2027                            $event->busystatus="2";
2028                            if ($kevent['show-time-as'] == 'busy' )
2029                            {
2030                                $event->busystatus="2";
2031                            }
2032                            elseif ($kevent['show-time-as'] == 'free')
2033                            {
2034                                $event->busystatus="0";
2035                            }
2036                            elseif ($kevent['show-time-as'] == 'tentative')
2037                            {
2038                                $event->busystatus="1";
2039                            }
2040                            elseif ($kevent['show-time-as'] == 'outofoffice')
2041                            {
2042                                $event->busystatus="3";
2043                            }
2044                            $event->body=w2u($kevent['body']);
2045                            //sensitivity
2046                            $event->meetingstatus="0";
2047                            $event->alldayevent="0";
2048                            //timezone must be fixed
2049                            $event->timezone="xP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAIAAAAAAAAAxP///w==" ;
2050                            $event->bodytruncated = 0; 
2051                            if (isset($kevent["organizer"]["smtp-address"]))
2052                            {
2053                                $event->organizername=w2u($kevent["organizer"]["display-name"]);
2054                                $event->organizeremail=w2u($kevent["organizer"]["smtp-address"]);
2055                            }
2056                            else
2057                            {
2058                                $event->organizername=w2u($this->_cn);
2059                                $event->organizeremail=w2u($this->_email);
2060                            }
2061
2062                            //reccurence process
2063                            if (isset($kevent["recurrence"]))
2064                            {
2065                                $event->reccurence=$this->kolabReadRecurrence($kevent);
2066                            }
2067                            return $event;
2068                        }
2069                        $n++;
2070                    }
2071                }
2072            }
2073            return ""     ;
2074
2075        }
2076        private function kolabReadRecurrence($kevent,$type=0)
2077        {
2078            $numMonth=array(
2079            "january"   => 1,
2080            "february"  => 2,
2081            "march"     => 3,
2082            "april"     => 4,
2083            "may"       => 5,
2084            "june"      => 6,
2085            "july"      => 7,
2086            "august"    => 8,
2087            "september" => 9,
2088            "october"   => 10,
2089            "november"  => 11,
2090            "december"  => 12
2091            );
2092            if (isset($kevent["recurrence"]))
2093            {
2094                if ($type == 0)
2095                {
2096                    $recurrence = new SyncRecurrence;
2097                }
2098                else
2099                {
2100                    $recurrence= new SyncTaskRecurrence;
2101                }
2102                $rec=$kevent["recurrence"];
2103                //cycle
2104                if ($rec["cycle"] == "daily")
2105                {
2106                    $recurrence->type =  0 ;
2107                }
2108                elseif($rec["cycle"] == "weekly")
2109                {
2110                    $recurrence->type =  1 ;
2111                    //dayofweek
2112                    //tableau jour 1=sunday 128 =saturday
2113                    $nday=0;
2114                    $recurrence->dayofweek=$this->KolabDofW2pda($rec["day"]);
2115                } 
2116                elseif($rec["cycle"] == "monthly") 
2117                {
2118
2119                    // sous type by day
2120                    if ($rec["type"] == "daynumber")
2121                    {
2122                        $recurrence->type =  2 ;   
2123                        $recurrence->dayofmonth =   $rec["daynumber"] ;
2124                    }
2125                    elseif ($rec["type"] == "weekday")
2126                    {
2127                        $recurrence->type =  3 ;       
2128                        $recurrence->weekofmonth = $rec["daynumber"];
2129                        //day of week
2130                        $recurrence->dayofweek=$this->KolabDofW2pda($rec["day"]);
2131                    }       
2132                }
2133                // year
2134                elseif($rec["cycle"] == "yearly")   
2135                {
2136                    if ($rec["type"] == "monthday")
2137                    {
2138
2139                        $recurrence->type =5   ; 
2140                        $recurrence->dayofmonth =   $rec["daynumber"] ;
2141                        $recurrence->monthofyear= $numMonth[$rec["month"]];
2142                    }
2143                    elseif ($rec["type"] == "weekday")
2144                    {
2145                        $recurrence->type =6   ; 
2146                        $recurrence->weekofmonth = $rec["daynumber"];
2147                        $recurrence->monthofyear= $numMonth[$rec["month"]];
2148                        $recurrence->dayofweek=$this->KolabDofW2pda($rec["day"]);
2149                    }
2150                }
2151                //interval
2152                $recurrence->interval = $rec["interval"] ;
2153                //range
2154                if ($rec["range-type"] == "number")
2155                {
2156                    $recurrence->occurrences =$rec["range"];
2157                } 
2158                elseif ($rec["range-type"] == "date")
2159                {
2160                    if ( strtolower($_GET["DeviceType"]) == "iphone")     
2161                    {
2162                        $recurrence->until =$rec["range"] + 93599;
2163                    }
2164                    else
2165                    {
2166                        $recurrence->until =$rec["range"];
2167                    }
2168
2169                }   
2170
2171                return $recurrence;
2172            }
2173            else
2174            {
2175                return NULL;
2176            }
2177        }
2178        private function KolabWriteEvent($message,$uid)
2179        { 
2180
2181
2182            $attendee = array(
2183            'display-name'  => $this->_cn,
2184            'smtp-address'  => $this->_email,
2185            'uid'           => "" 
2186            );
2187            $object = array(
2188            'uid' => bin2hex($message->uid),
2189            'start-date' => $message->starttime,
2190            'end-date'   => $message->endtime,
2191            'summary'   => u2w($message->subject),
2192            'reminder'  => $message->reminder,
2193            'location'  => $message->location,
2194            'alarm' => $message->reminder,
2195            'color-label' => "none"    ,
2196            'show-time-as' => "busy",
2197            'organizer' => $attendee,
2198            'location' => u2w($message->location)
2199            );
2200            if ($message->body != "")
2201            {
2202                $object['body']=u2w($message->body);
2203            }
2204            elseif ($message->rtf)
2205            {
2206                $object['body']=$this->rtf2text($message->rtf);
2207            }
2208            if ($message->alldayevent == 1)
2209            {
2210                $object['_is_all_day']=True;
2211            }
2212            switch($message->busystatus )
2213            {
2214                case 0:
2215                $object['show-time-as'] = "free";
2216                break;
2217                case 1:
2218                $object['show-time-as'] = "tentative";
2219                break;
2220                case 2:
2221                $object['show-time-as'] = "busy";
2222                break;
2223                case 3:
2224                $object['show-time-as'] = "outofoffice";
2225                break;
2226
2227            }
2228            switch($message->sensitivity)
2229            {
2230                case 1:
2231                case 2:
2232                $object["sensitivity"] = "private";
2233                break;
2234                case 3:
2235                $object["sensitivity"] = "confidential";
2236            }
2237
2238            //recurence
2239            if(isset($message->recurrence))
2240            {
2241                $object["recurrence"]=$this->kolabWriteReccurence($message->reccurence);
2242            }
2243            $format = Horde_Kolab_Format::factory('XML', 'event'); 
2244            $xml = $format->save($object);
2245            unset($format);
2246            // set the mail
2247            // attach the XML file
2248            $mail=$this->mail_attach("kolab.xml",0,$xml,"kolab message","text/plain", "plain","application/x-vnd.kolab.event");
2249            //add header
2250            $h["from"]=$this->_email;
2251            $h["to"]=$this->_email;
2252            $h["X-Mailer"]="z-push-Kolab Backend";
2253            $h["subject"]= $object["uid"];
2254            $h["message-id"]= "<" . strtoupper(md5(uniqid(time()))) . ">";
2255            $h["date"]=date(DATE_RFC2822);
2256            foreach(array_keys($h) as $i)
2257            {
2258                $header= $header . $i . ": " . $h[$i] ."\r\n";
2259            }
2260            //return the mail formatted
2261            return array($object['uid'],$h['date'],$header  .$mail[0]."\r\n" .$mail[1]);
2262
2263        }
2264        private function kolabWriteReccurence($reccurence)
2265        {
2266            $month=array("dummy","january","february","march","april","may","june","july","august","september","october","november","december");
2267            $rec=array();
2268            switch($recurrence->type)
2269            {
2270                case 0:
2271                //repeat daily
2272                $rec["cycle"] = "daily";
2273                break;
2274                case 1:
2275                //repeat weekly
2276                $rec["cycle"] = "weekly"; 
2277                $rec["day"] = $this->KolabPda2DofW($recurrence->dayofweek );
2278                break;
2279                case 2:
2280                //montly daynumber
2281                $rec["cycle"] = "monthly";
2282                $rec["type"] ="daynumber";
2283                $rec["daynumber"] =$recurrence->dayofmonth  ;
2284                break;
2285                case 3:
2286                //monthly day of week
2287                $rec["cycle"] = "monthly";
2288                $rec["type"] ="weekday";
2289                $rec["daynumber"] =$recurrence->weekofmonth  ;
2290                $rec["day"] = $this->KolabPda2DofW($recurrence->dayofweek );
2291                break; 
2292                case 5:
2293                //yearly
2294                $rec["cycle"] = "yearly";
2295                $rec["type"] ="monthday";
2296                $rec["daynumber"] =$recurrence->dayofmonth  ;
2297                $rec["month"]=$month[$recurrence->monthofyear];
2298                break; 
2299                //   
2300                case 6:
2301                //yearly
2302                $rec["cycle"] = "yearly";
2303                $rec["type"] ="weekday";
2304                $rec["daynumber"] =$recurrence->weekofmonth  ;
2305                $rec["month"]=$month[$recurrence->monthofyear];
2306                $rec["day"] = $this->KolabPda2DofW($recurrence->dayofweek );
2307                break; 
2308            }
2309            //interval
2310            if (isset($recurrence->interval))
2311            {
2312                $rec["interval"] = $recurrence->interval;
2313            }
2314            else
2315            {
2316                $rec["interval"] = 1;
2317            }
2318            if (isset($recurrence->occurrences))
2319            {
2320                //by ocurence
2321                $rec["range-type"] = "number";
2322                $rec["range"] =$recurrence->occurrences;
2323            }
2324            elseif (isset($recurrence->until))
2325            {
2326                //by end date
2327                $rec["range-type"] = "date";
2328                if ( strtolower($_GET["DeviceType"]) == "iphone" || strtolower($_GET["DeviceType"]) == "ipod")
2329                {
2330                    $rec["range"] =$recurrence->until  - 93599 ;
2331                }
2332                else
2333                {
2334                    $rec["range"] =$recurrence->until;
2335                }
2336            }
2337            else
2338            {
2339                $rec["range-type"] ="none";
2340            }
2341            return $rec;   
2342        }
2343        private function KolabReadTask($message,$id,$disableAlarm=false,$with_uid=false)
2344        {
2345            $task=NULL;
2346           
2347            if(isset($message->parts))
2348            {
2349                foreach($message->parts as $part)
2350                {
2351                    if(isset($part->disposition) && ($part->disposition == "attachment" || $part->disposition == "inline"))
2352                    {
2353                        $type=$part->headers;
2354                        //kolab contact attachment ?
2355                        $ctype=explode(";",$type["content-type"] )  ;
2356                        if ($ctype[0] == " application/x-vnd.kolab.task")
2357                        {
2358                            $format = Horde_Kolab_Format::factory('XML', 'task'); 
2359                            $body=$part->body; 
2360                            $ktask=$format->load($body);
2361                            unset($format);
2362                            if ($ktask instanceof PEAR_Error)
2363                            {
2364                                //parsing error
2365                                debugLog("ERROR ".$ktask->message);
2366                                debugLog("Xml kolab :     $body")  ;
2367                                $this->Log("ERROR ".$ktask->message);
2368                                $this->Log("XML : $body")  ;
2369                                unset ($ktask); 
2370                                return "";
2371                            }
2372
2373                            //mappage
2374                            $task=new SyncTask();
2375                            if ( $with_uid != 0)
2376                            {
2377                                $task->uid= hex2bin($ktask['uid']);
2378                            }
2379                            $task->subject=w2u($ktask['name']);
2380                            if ($ktask['start'])
2381                            {
2382                                $offset=date('Z',$ktask['start']);
2383                                $task->utcstartdate=$kstart['start'];
2384                                $task->startdate=$ktask['start'] + $offset;
2385                            }
2386                            if($ktask['due'])
2387                            {
2388                                $offset=date('Z',$ktask['due']);
2389                                $task->utcduedate=$ktask['due'];
2390                                $task->duedate=$ktask['due'] + $offset;
2391                            }   
2392                            $task->complete=$ktask['completed'];
2393                            if (isset($ktask['completed_date']))
2394                            {
2395                                $task->datecompleted=$ktask['completed_date'];
2396                            }
2397                            //categories
2398                            if (isset($ktask['categories']))
2399                            {
2400                                $cat=split(',',w2u($ktask['categories']));
2401                                $task->categories=$cat;
2402                            }
2403                            switch($ktask['priority'])
2404                            {
2405                                case 1: $task->importance= 2;
2406                                break;
2407                                case 2:
2408                                case 3:
2409                                case 4: $task->importance=1;
2410                                break;
2411                                case 5: $task->importance=0;
2412                            }
2413                            switch(strtolower($ktask['sensitivity']))
2414                            {
2415                                case "public":
2416                                $task->sensitivity=0;
2417                                break;
2418                                case "private":
2419                                $task->sensitivity=2;
2420                                break;
2421                                case "confidential":
2422                                $task->sensitivity=3;
2423                            }
2424                            //bug #9 Alarm mus not be shown for all folders
2425                            if ($disableAlarm == false)
2426                            {
2427                                if ($ktask['alarm'] > 0)
2428                                {
2429                                    $task->remindertime=$ktask["start"] +($ktask['alarm'] * 60);
2430                                    $task->reminderset=1;
2431                                }
2432                            }
2433                            else
2434                            {
2435                                $task->reminderset=NULL;
2436                                $task->remindertime=NULL;
2437                            }
2438                            $task->body=w2u($ktask['body']);
2439                            //timezone must be fixed
2440                            $task->bodytruncated = 0; 
2441                            //reccurence process
2442                            if (isset($ktask["recurrence"]))
2443                            {
2444                                $task->reccurence=$this->kolabReadRecurrence($ktask,1);
2445                            }
2446                            return $task;
2447                        }
2448                        $n++;
2449                    }
2450                }
2451            }
2452            return ""     ;
2453
2454        }
2455        private function KolabWriteTask($message,$id)
2456        {
2457           
2458            if ( ! $id )
2459            {
2460                $uid=strtoupper(md5(uniqid(time())));
2461            }
2462            else
2463            {
2464                $uid=$id;
2465            }
2466            $object = array(
2467            'uid' => $uid,
2468            'start' => $message->utcstartdate,
2469            'due'   => $message->utcduedate,
2470            'name'   => u2w($message->subject),
2471            );
2472            if (isset($message->rtf))
2473            {
2474                $object['body']=$this->rtf2text($message->rtf);                 
2475            }
2476            if ($message->reminderset == 1)
2477            {
2478                $object['alarm']=($message->remindertime - $message->utcstartdate) / 60;
2479            }
2480            //categories
2481            if (isset($message->categories))
2482            {
2483                $object['categories']=u2w(join(',',$message->categories));
2484            }
2485            switch($message->importance)
2486            {
2487                case 0: $object["priority"] = 5;
2488                break;
2489                case 1: $object["priority"] = 3;
2490                break;     
2491                case 2: $object["priority"] = 1;
2492                break;                 
2493            }
2494            if ( $message->complete == 1)
2495            {
2496                $object['completed'] = 100;
2497                $object['completed_date'] = $message->datecompleted;
2498            }
2499            else
2500            {
2501                $object['completed'] = 0;
2502            }
2503            switch($message->sensitivity)
2504            {
2505                case 1:
2506                case 2:
2507                $object["sensitivity"] = "private";
2508                break;
2509                case 3:
2510                $object["sensitivity"] = "confidential";
2511            }
2512
2513            //recurence
2514            if(isset($message->recurrence))
2515            {
2516                $object["recurrence"]=$this->kolabWriteReccurence($message->reccurence);
2517            }
2518            $format = Horde_Kolab_Format::factory('XML', 'task'); 
2519            $xml = $format->save($object);
2520            unset($format);
2521            // set the mail
2522            // attach the XML file
2523            $mail=$this->mail_attach("kolab.xml",0,$xml,"kolab message","text/plain", "plain","application/x-vnd.kolab.task");
2524            //add header
2525            $h["from"]=$this->_email;
2526            $h["to"]=$this->_email;
2527            $h["X-Mailer"]="z-push-Kolab Backend";
2528            $h["subject"]= $object["uid"];
2529            $h["message-id"]= "<" . strtoupper(md5(uniqid(time()))) . ">";
2530            $h["date"]=date(DATE_RFC2822);
2531            foreach(array_keys($h) as $i)
2532            {
2533                $header= $header . $i . ": " . $h[$i] ."\r\n";
2534            }
2535            //return the mail formatted
2536            return array($object['uid'],$h['date'],$header  .$mail[0]."\r\n" .$mail[1]);
2537
2538        }
2539        //return the date for Kolab
2540        private function KolabDateUnix2Kolab($timestamp)
2541        {
2542            $d=date(DATE_W3C ,$timestamp);
2543            $d=substr($d,0,19) . "Z"  ;
2544            return $d;
2545        }
2546        private function KolabDate2Unix($kdate)
2547        {
2548            if (! $kdate)
2549            {
2550                return NULL;
2551            }
2552            else
2553            {
2554                $tm= gmmktime(0, 0, 0, substr($kdate,5,2), substr($kdate,8,2), substr($kdate,0,4));
2555                return $tm;
2556            }
2557        }
2558        /*CacheCreateIndex : create an index to retrieve easly the uid-> id and the id->uid
2559        */
2560        private function CacheCreateIndex($folderid,$kolab_uid,$imap_uid)
2561        {
2562
2563            $kolab_uid=strtoupper($kolab_uid);
2564            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);
2565            $this->_cache->write("IMAP:".$folderid."/".$imap_uid,$kolab_uid);
2566            $this->_cache->write("KOLAB:".$folderid."/".$kolab_uid,$imap_uid);
2567            //must another index to find the folder of the uid
2568            $this->_cache->write("FLMODE:".$kolab_uid, $folderid);
2569            $this->_cache->close();
2570        }
2571        private function CacheIndexUid2FolderUid($uid)
2572        {
2573            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);
2574            $result= $this->_cache->find("FLMODE:".$uid);
2575            $this->_cache->close();
2576            return $result;
2577        }
2578        private function CacheStoreMessageList($folder,$mlist)
2579        {
2580            $stat=serialize($mlist);
2581            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);
2582            $this->_cache->write("MLIST:".$folder,$stat);
2583            $this->_cache->close();
2584        }
2585        private function CacheReadMessageList($folder)
2586        {
2587            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);
2588            $result= $this->_cache->find("MLIST:".$folder);
2589            $this->_cache->close();
2590            return unserialize($result);
2591        }
2592        private function CacheStoreImapStatus($folder,$stat)
2593        {
2594
2595            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);
2596            $this->_cache->write("FIMAPSTAT:".$folder,serialize($stat));
2597            $this->_cache->close();
2598        }
2599        private function CacheReadImapStatus($folder)
2600        {
2601            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);
2602            $result= $this->_cache->find("FIMAPSTAT:".$folder);
2603            $this->_cache->close();
2604            return unserialize($result);
2605        }
2606        private function CacheIndexId2Uid($folderid,$id)
2607        {
2608            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);
2609            $result= $this->_cache->find("IMAP:".$folderid."/".$id);
2610            $this->_cache->close();
2611            return $result;
2612        }
2613        private function CacheIndexUid2Id($folderid,$uid)
2614        {
2615            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); 
2616            $result= $this->_cache->find("KOLAB:".$folderid."/".$uid);
2617            $this->_cache->close();
2618            return $result;
2619        }
2620        private function CacheIndexDeletebyId($folderid,$id)
2621        {
2622
2623            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); 
2624            $uid= $this->_cache->find("IMAP:".$folderid."/".$id);
2625            $this->_cache->delete("IMAP:".$folderid."/".$id);
2626            $this->_cache->delete("KOLAB:".$folderid."/".$uid);
2627            $this->_cache->delete("ENDDATE:".$folderid."/".$uid);   
2628            $this->_cache->delete("FLMODE:".$uid);
2629            $this->_cache->close();
2630            return $result;
2631        }
2632        private function CacheCheckVersion()
2633        {
2634
2635            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);
2636            $version= $this->_cache->find("CACHEVERSION");
2637            if ( $version != KOLABBACKEND_VERSION)
2638            {
2639                //reinit cache
2640                $this->_cache->close();
2641                $this->_cache->purge();
2642                $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);   
2643                $this->_cache->write("CACHEVERSION",KOLABBACKEND_VERSION);
2644            }
2645            $this->_cache->close();     
2646        }
2647        private function CacheIndexClean($messagelist)
2648        {
2649            return;
2650        }
2651        private function CacheWriteFolderParam($folder,$fa)
2652        {
2653            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);
2654            $this->_cache->write("FOLDERPARAM:".$folder,$fa->serialize());
2655            $this->_cache->close();
2656        }
2657        private function CacheReadFolderParam($folder)
2658        {
2659            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);
2660            $result= $this->_cache->find("FOLDERPARAM:".$folder);
2661            $this->_cache->close();
2662            $fa=new folderParam();
2663            $fa->unserialize($result);
2664            return $fa;
2665        }
2666        private function KolabgetMail($username)
2667        {
2668            return  $username . "@localhost.localdomain";
2669        }
2670        private function KolabDofW2pda($recday)
2671        {
2672            foreach ($recday as $day)
2673            {
2674                if($day == "sunday")
2675                {
2676                    $nday=$nday +1;
2677                }
2678                elseif ($day == "monday")
2679                {
2680                    $nday=$nday +2;
2681                }
2682                elseif ($day == "tuesday")
2683                {
2684                    $nday=$nday + 4;
2685                }
2686                elseif ($day == "wednesday")
2687                {
2688                    $nday=$nday + 8;
2689                }
2690                elseif ($day == "thursday")
2691                {
2692                    $nday=$nday + 16;
2693                }
2694                elseif ($day == "friday")
2695                {
2696                    $nday=$nday + 32;
2697                }
2698                elseif ($day == "saturday")
2699                {
2700                    $nday=$nday + 64;
2701                }                           
2702            }
2703            return $nday;
2704
2705        }
2706        private function KolabPda2DofW($value)
2707        {
2708            $days=array();
2709            $test = $value & 8;
2710            $value=$value *1; //conversion in long ...
2711            if ( ($value & 1) >0){$days[]="sunday";}   
2712            if ( ($value & 2) >0){$days[]="monday";}
2713            if ( ($value & 4) >0){$days[]="tuesday";}     
2714            if ( ($value & 8) >0)
2715            {
2716                $days[]="wednesday";
2717            }     
2718            if ( ($value & 16) >0){$days[]="thursday";}     
2719            if ( ($value & 32) >0){$days[]="friday";}     
2720            if ( ($value & 64) >0){$days[]="saturday";}     
2721            return $days ;     
2722        } 
2723        private function Log($message) {
2724            if (KOLAB_LOGFILE != ""  )
2725            {
2726                @$fp = fopen(KOLAB_LOGFILE ,"a+");
2727                @$date = strftime("%x %X");
2728                @fwrite($fp, "$date [". getmypid() ."] : " . $this->_username . " : $message\n");
2729                @fclose($fp);
2730            }
2731        }
2732        private function KolabStat($fid,$o)
2733        {
2734
2735            if ( !$o)
2736            {
2737                return false;
2738            }
2739            $kolab_uid="";
2740            $m= array();
2741            $m["mod"] = $fid .'/'.$o->uid;
2742            //search the kolab uid in index if nofound read the mail to find it
2743            $kolab_uid=$this->CacheIndexId2Uid($fid,$o->uid);
2744            if (! $kolab_uid)
2745            {
2746                //no found read the message
2747                $mail = @imap_fetchheader($this->_mbox, $o->uid, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $o->uid, FT_PEEK | FT_UID);
2748                $mobj = new Mail_mimeDecode($mail);
2749                $message = $mobj->decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $mail, 'crlf' => "\n", 'charset' => 'utf-8'));
2750                if ($this->kolabFolderType($fid) == 2)
2751                {
2752
2753                    $ev=$this->KolabReadEvent($message,false) ;
2754                    if (! $ev)
2755                    {
2756                        return false ;
2757                    }
2758                    $kolab_uid=strtoupper(bin2hex($ev->uid));
2759
2760                    //index
2761                    if ($kolab_uid){
2762                       
2763                        $this->CacheCreateIndex($fid,$kolab_uid,$o->uid);
2764                        //index of the endDate too
2765                        $this->CacheWriteEndDate($fid,$ev);
2766                        if ( $ev->sensitivity != 0)
2767                        {
2768                            //add in cache the sensitivity
2769                            $this->CacheWriteSensitivity($kolab_uid,$ev->sensitivity);
2770                        }
2771                    }
2772                    else
2773                    {
2774                        return False;
2775                    }
2776                }
2777                if ($this->kolabFolderType($fid) == 1)
2778                {
2779                    $ev=$this->KolabReadContact($message,1) ;
2780                    $kolab_uid=strtoupper(bin2hex($ev->uid));
2781                    //index
2782                    if ($kolab_uid){
2783                        $this->CacheCreateIndex($fid,$kolab_uid,$o->uid);
2784                    }
2785                    else
2786                    {
2787                        return False;
2788                    }
2789                }
2790                if ($this->kolabFolderType($fid) == 3)
2791                {
2792                    $ev=$this->KolabReadTask($message,false,false,1) ;
2793                    $kolab_uid=strtoupper(bin2hex($ev->uid));
2794                    //index
2795                    if ($kolab_uid){
2796                        $this->CacheCreateIndex($fid,$kolab_uid,$o->uid);
2797                        if ( $ev->sensitivity != 0)
2798                        {
2799                            //add in cache the sensitivity
2800                            $this->CacheWriteSensitivity($kolab_uid,$ev->sensitivity);
2801                        }
2802                        if ( $ev->complete)
2803                        {
2804                            $this->CacheWriteTaskCompleted($kolab_uid,$ev->complete);
2805                        }
2806                    }
2807                    else
2808                    {
2809                        return False;
2810                    }
2811                }
2812            }
2813            $m["id"] = $kolab_uid;
2814            //$m["mod"]=  $o->uid;
2815            // 'seen' aka 'read' is the only flag we want to know about
2816            $m["flags"] = 0;
2817            return $m;           
2818        }
2819        private function getImapFolderType($folder)
2820        {
2821           
2822            if (function_exists("imap_getannotation"))
2823            {
2824                $result = imap_getannotation($this->_mbox, $folder, "/vendor/kolab/folder-type", "value.shared");
2825                if (isset($result["value.shared"]))
2826                {
2827                    $anno=$result["value.shared"];
2828                }
2829                else
2830                {
2831                    $anno="";
2832                }
2833            }
2834            else
2835            {
2836                $rec="";
2837                $anno="";
2838                $fp = fsockopen(KOLAB_SERVER,KOLAB_IMAP_PORT, $errno, $errstr, 30);
2839                if (!$fp)
2840                {
2841                    return false;
2842                } else {
2843                    //vidage greeting
2844                    $rec=$rec .  stream_get_line($fp,1024,"\r\n");
2845                    $rec="";
2846                    //envoi login ;
2847                    $out = "01 LOGIN " . $this->_username." ". $this->_password ."\r\n";
2848                    fwrite($fp, $out);   
2849                    $rec=$rec .  stream_get_line($fp,1024,"\r\n");
2850                    if (ereg("01 OK",$rec))
2851                    {
2852                        $r=array();
2853                        //envoi de la commande myrights
2854                        $out='ok getannotation "'.$folder.'" "/vendor/kolab/folder-type" "value"' ."\r\n";
2855                        fwrite($fp, $out);   
2856                        $rec=fread($fp,1024);
2857                        $r=split("\r\n",$rec);
2858                        $rec=$r[0];
2859                        if (ereg("ANNOTATION",$rec))
2860                        {
2861                            //bonne reponse
2862                            //* ANNOTATION "INBOX/Calendrier" "/vendor/kolab/folder-type" ("value.shared" "event.default")
2863
2864                            $tab=array();
2865                            $reg=  "/value.shared\" \"(.+)\"/";
2866                            if (preg_match($reg,$rec,$tab))
2867                            {
2868                                $anno=$tab[1]; 
2869                            }
2870                        }
2871                        $out="03 LOGOUT\r\n";
2872                        fwrite($fp, $out);   
2873                        fclose($fp);
2874                    }
2875                }
2876            }
2877            $tab=explode(".",$anno);
2878            $root=explode('/',$folder);
2879            if ( $root[0] != "INBOX")
2880            {
2881                if (count($tab) == 2)
2882                {
2883                    $anno = $tab[0];
2884                }
2885            }
2886            return $anno;
2887
2888
2889        }
2890
2891        private function kolabFolderType($name)
2892        {
2893            if ( $name == "VIRTUAL/calendar")
2894            {
2895                return 2;
2896            }
2897            if ( $name == "VIRTUAL/contacts")
2898            {
2899                return 1;
2900            }
2901            if ( $name == "VIRTUAL/tasks")
2902            {
2903                return 3;
2904            }
2905            $type= $this->readFolderAnnotation($name)  ;
2906            if ( $type == false)
2907            {
2908                //not in the cache
2909                $this->saveFolderAnnotation($name);
2910                $type= $this->readFolderAnnotation($name)  ;
2911            }
2912            if ($type == "task" || $type == "task.default")
2913            {
2914                return 3;
2915            }
2916            if ($type == "event" || $type == "event.default")
2917            {
2918                return 2;
2919            }
2920            if ($type == "contact" || $type == "contact.default")
2921            {
2922                return 1;
2923            }
2924            return 0;
2925        }
2926        private function ActiveSyncFolderSyncType($name)
2927        {
2928            $type= $this->readFolderAnnotation($name)  ;
2929            if ( $type == "task.default")
2930            {
2931                return SYNC_FOLDER_TYPE_TASK;
2932            }
2933
2934            if ( $type == "event.default")
2935            {
2936                return SYNC_FOLDER_TYPE_APPOINTMENT;
2937            }
2938            if ( $type == "contact.default")
2939            {
2940                return SYNC_FOLDER_TYPE_CONTACT;
2941            }
2942            if ( $type == "task")
2943            {
2944                //check if no default folder exist;
2945                if ( $this->hasDefaultTaskFolder == false )
2946                {
2947                    if ($this->isDefaultFolder($name,KOLAB_DEFAULTFOLDER_TASK))
2948                    {
2949                        $this->hasDefaultTaskFolder= true;
2950                        $this->forceDefaultFolder("task",$name);
2951                        return SYNC_FOLDER_TYPE_TASK;
2952                    }
2953                }
2954                return SYNC_FOLDER_TYPE_USER_TASK;
2955            }
2956
2957            if ( $type == "event")
2958            {
2959                if ( $this->hasDefaultEventFolder == false )
2960                {
2961                    if ($this->isDefaultFolder($name,KOLAB_DEFAULTFOLDER_DIARY))
2962                    {
2963                        $this->Log("NOTICE no event default folder set as default: $name");
2964                        $this->forceDefaultFolder("event",$name);
2965                        $this->hasDefaultEventFolder= true;
2966                        return SYNC_FOLDER_TYPE_APPOINTMENT;   
2967                    }
2968                }
2969                return SYNC_FOLDER_TYPE_USER_APPOINTMENT;
2970            }
2971            if ( $type == "contact")
2972            {
2973                if ( $this->hasDefaultContactFolder == false )
2974                {
2975                    if ($this->isDefaultFolder($name,KOLAB_DEFAULTFOLDER_CONTACT))
2976                    {
2977                        $this->forceDefaultFolder("contact",$name);
2978                        $this->hasDefaultContactFolder= true;
2979                        return SYNC_FOLDER_TYPE_CONTACT;   
2980                    }
2981                }
2982                return SYNC_FOLDER_TYPE_USER_CONTACT;
2983            }
2984        }
2985        private function isDefaultFolder($folder,$defaultchain)
2986        {
2987            $folder=strtolower($folder);
2988            $f=split(":",strtolower($defaultchain));
2989            foreach($f as $value)
2990            {
2991                if ($value == $folder)
2992                {
2993                    return true;
2994                }
2995            }
2996            return false;
2997        }
2998        private function forceDefaultFolder($type,$folder)
2999        {
3000            switch ($type){
3001                case 1: $type="contact";
3002                break;
3003                case 2: $type="event";
3004                break;
3005                case 3: $type="task";
3006                break;
3007            }
3008            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);
3009            $this->_cache->write("DEFAULT:".$type.".default",$folder);
3010            $this->_cache->close();   
3011        }
3012        private function saveFolderAnnotation($foldera)
3013        {
3014            $anno=$this->getImapFolderType($foldera);
3015            if (!$anno)
3016            {
3017                $anno="0";
3018            }
3019            $default=explode(".",$anno);   
3020            //remove the default if this is not in INBOX folder
3021            //we must detech just INBOX default folder
3022            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);
3023            if ( isset($default[1]) && $default[1] == "default" )
3024            {
3025                if (substr($foldera,0,5) == "INBOX")
3026                {
3027
3028                    $this->_cache->write("DEFAULT:".$anno,$foldera);
3029                }
3030                else
3031                {
3032                    $anno = $default[0];
3033                }
3034            } 
3035            if ( $anno =="mail.sentitems")
3036            {
3037                $this->_cache->write("SENTFOLDER:",$foldera);
3038            }
3039            if ( ! $this->_cache->write("FA:".$foldera,$anno))
3040            {
3041                $this->Log("ERROR: ".KOLAB_INDEX."/".$this->_username);
3042            }
3043            $this->_cache->close();   
3044            $this->Log("Annotation $foldera : $anno") ;
3045        }
3046        private function readDefaultSentItemFolder()
3047        {
3048            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);
3049            $sentf=$this->_cache->find("SENTFOLDER:");
3050            $this->_cache->close();
3051            return $sentf;
3052        }
3053        private function readFolderAnnotation($folder)
3054        {
3055            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);
3056            $anno=$this->_cache->find("FA:".$folder);
3057            $this->_cache->close();
3058            return $anno;
3059        }
3060        private function CacheGetDefaultFolder($type)
3061        {
3062            switch ($type){
3063                case 1: $type="contact";
3064                break;
3065                case 2: $type="event";
3066                break;
3067                case 3: $type="task";
3068                break;
3069            }
3070            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);   
3071            $deffolder=$this->_cache->find("DEFAULT:".$type.".default");
3072            $this->_cache->close();
3073            return $deffolder;
3074        }
3075
3076        private function CacheReadEndDate($folder,$uid)
3077        {
3078            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);   
3079            $deffolder=$this->_cache->find("ENDDATE:".$folder."/".$uid);
3080            $this->_cache->close();
3081            if ($deffolder == False)
3082            {
3083                $deffolder = "-1";
3084            }
3085            return $deffolder;
3086        }
3087        private function CacheWriteEndDate($folder,$event)
3088        {   
3089            $uid=strtoupper(bin2hex($event->uid));
3090            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);
3091           
3092            $edate=-1;
3093            if ($event->recurrence)
3094            {
3095                //end date in the recurence ?
3096
3097                if (isset($event->recurrence->until))
3098                {
3099                    if ( strtolower($_GET["DeviceType"]) == "iphone" || strtolower($_GET["DeviceType"]) == "ipod")
3100                    {
3101                        $edate =$event->recurrence->until  - 93599 ;
3102                    }
3103                    else
3104                    {
3105                        $edate = $event->recurrence->until;
3106                    }
3107                }
3108                elseif(isset($event->recurrence->occurrences))
3109                {
3110                    if ( isset($event->recurrence->interval))
3111                    {
3112                        $interval=$event->recurrence->interval;
3113                    }
3114                    else
3115                    {
3116                        $interval=1;
3117                    }
3118                    switch($event->recurrence->type)
3119                    {
3120                        case 0:
3121                        //repeat daily   
3122                        // enddate = startDate + (repeat +(86400 * interval))
3123                        $edate= $event->starttime + ($event->recurrence->occurrences *(86400* $interval)) ;
3124                        break;
3125                        case 2:   
3126                        //approche monts =31 to be sure to not cute it with a complex thing
3127                        $edate= $event->starttime + ($event->recurrence->occurrences *(2678400* $interval)) ;   
3128                        case 5:
3129                        //yearly
3130                        $edate= $event->starttime + ($event->recurrence->occurrences *(31536000* $interval )) ; 
3131                        break;
3132                    }
3133                }     
3134
3135                //others stuffs
3136                }
3137            else
3138            {
3139                $edate=$event->endtime;
3140            }
3141            $this->_cache->write("ENDDATE:" . $folder."/".$uid,$edate);
3142            $this->_cache->close();         
3143        }
3144        private function CacheWriteSensitivity($uid,$sensitivity)
3145        {
3146            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); 
3147            $this->_cache->write("SENSITIVITY:" .$uid,$sensitivity);
3148            $this->_cache->close();         
3149        }
3150        private function CacheReadSensitivity($uid)
3151        {
3152            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);   
3153            $s=$this->_cache->find("SENSITIVITY:" .$uid);
3154            $this->_cache->close();
3155            return $s;
3156        }
3157        private function CacheWriteTaskCompleted($uid,$completed)
3158        {
3159            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); 
3160            $this->_cache->write("TCOMPLETED:" .$uid,$completed);
3161            $this->_cache->close();         
3162        }
3163        private function CacheReadTaskCompleted($uid)
3164        {
3165            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);   
3166            $s=$this->_cache->find("TCOMPLETED:" .$uid);
3167            $this->_cache->close();
3168            return $s;
3169        }
3170        private function CacheWritePicture($uid,$picture)
3171        {
3172            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid); 
3173            $this->_cache->write("CPICTURE:" .$uid,$picture);
3174            $this->_cache->close();         
3175        }
3176        private function CacheReadPicture($uid)
3177        {
3178            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);   
3179            $s=$this->_cache->find("CPICTURE:" .$uid);
3180            $this->_cache->close();
3181            return $s;
3182        }
3183        private function CacheDeletePicture($uid)
3184        {
3185            $this->_cache->open(KOLAB_INDEX."/".$this->_username."_".$this->_devid);       
3186            $this->_cache->delete("CPICTURE:".$uid);
3187            $this->_cache->close();
3188        }
3189        private function kolabReadGlobalParam()
3190        {
3191            if (function_exists("imap_getannotation"))
3192            {
3193                $gp=new GlobalParam();
3194                $result = imap_getannotation($this->_mbox, "INBOX", "/vendor/kolab/activesync", "value.priv");
3195                if (isset($result["value.priv"]))
3196                {
3197                    if ( ! $gp->unserialize($result["value.priv"]))
3198                    {
3199                        return $gp;
3200                    }
3201                }
3202                return $gp;
3203            }
3204        }
3205        private function kolabReadFolderParam($folder)
3206        {
3207            if (function_exists("imap_getannotation"))
3208            {
3209                $gp=new FolderParam();
3210                $result = imap_getannotation($this->_mbox, $folder, "/vendor/kolab/activesync", "value.priv");
3211                if (isset($result["value.priv"]))
3212                {
3213
3214                    if ( ! $gp->unserialize($result["value.priv"]))
3215                    {
3216                        return $gp;
3217                    }
3218                }
3219                return $gp;
3220            }
3221        }
3222        private function kolabWriteGlobalParam($gp)
3223        {
3224            if ( ! $gp)
3225            {
3226                return false ;
3227            }
3228            $anno=$gp->serialize();
3229            if (function_exists("imap_setannotation"))
3230            {
3231                //write annotation on the INBOX folder
3232                $result = @imap_setannotation($this->_mbox, "INBOX", "/vendor/kolab/activesync", "value.priv",$anno);
3233                if ( ! $result)
3234                {
3235                    $this->Log("write globalparam :".@imap_last_error());
3236
3237                    return false;
3238                }
3239            }
3240            return true ;
3241        }
3242        private function getLdapAccount()
3243        {
3244            //chech if KOLAB_LDAP_SERVER is a URI or an IP
3245            $reg=  "/ldap:\/\/(.+):(.+)/";
3246            if (preg_match($reg,KOLAB_SERVER,$tab))
3247            {
3248                $addrip=$tab[1];
3249                $port=$tab[2]; 
3250            }
3251            else
3252            {
3253                $addrip=KOLAB_SERVER;
3254                $port=389;
3255            }
3256            $conn=ldap_connect($addrip,$port) ;
3257            if ($conn == 0)
3258            {
3259                $this->Log("ERR LDAP connexion to server : " . KOLAB_SERVER . " failed");
3260                return 0;
3261            }
3262            if (!ldap_bind ($conn,"",""))
3263            {
3264                $this->Log("ERR LDAP Invalid credential") ; 
3265                return 0;
3266            }
3267            //recherche du DN a autentifier
3268            if ( ! $sr=ldap_search($conn,KOLAB_LDAP_BASE,"(uid=".$this->_username.")"))
3269            {
3270                $this->Log("ERR LDAP ". $this->_username ." not found")  ;
3271                return 0;
3272            }
3273            $entries=ldap_get_entries($conn,$sr);
3274            if ($entries['count'] == 1)
3275            {
3276                $this->_email=$entries[0]["mail"][0];
3277                $this->_cn=$entries[0]["cn"][0];
3278                $this->_KolabHomeServer=$entries[0]["kolabhomeserver"][0];
3279                $dn=$entries[0]["dn"];
3280                //check ACL if KOLAN_LDAP_ACL
3281                if (defined("KOLAB_LDAP_ACL"))
3282                {
3283                    $grp=KOLAB_LDAP_ACL;
3284                }
3285                else
3286                {
3287                    $grp ="";
3288                }
3289                if ($grp  != "")
3290                {
3291                    //check if the dn is in the group as member
3292                    $r = ldap_compare($conn, $grp, "member", $dn) ;
3293                    if ( ! $r)
3294                    {
3295                        $this->Log("ACL member not present in $grp Access Denied");
3296                        return 0;
3297                    }
3298                    if ( $r == -1)
3299                    {
3300                        $this->Log("ACL group $gr not found (acces authorized)");
3301                    }
3302                }
3303                return 1;
3304            }
3305        } 
3306        private function rtf2text($data)
3307        {
3308            $rtf_body = new rtf ();
3309            $rtf_body->loadrtf(base64_decode($data));
3310            $rtf_body->output("ascii");
3311            $rtf_body->parse();
3312            $r=$rtf_body->out;
3313            unset($rtf_body);
3314            return $r;
3315        }     
3316    }; 
3317    class userCache {
3318        private $_filename;
3319        private $_id;
3320        public $_lastError;
3321        function open($filename)
3322        {
3323            $this->_id = dba_open ($filename.".cache", "cl");
3324
3325            if (!$this->_id) {
3326                $this->_lastError = "failed to open $filename";
3327                return false;
3328            }
3329            $this->_filename=$filename;
3330            return true;
3331        }
3332        function close()
3333        {
3334            dba_close($this->_id);
3335        }
3336        function write($key,$value)
3337        {
3338            $oldvalue=dba_fetch($key, $this->_id);
3339            if ( $oldvalue == $value)
3340            {
3341                //the key already exist and the value is the same we do nothing
3342                return 1;
3343            }
3344            if ($oldvalue)
3345            {
3346                //the key exist but the value change
3347                dba_delete($key,$this->_id);
3348            }
3349            return dba_insert($key,$value, $this->_id);
3350
3351        }
3352        function delete($key)
3353        {
3354            if (dba_exists ($key, $this->_id)) {
3355                return dba_delete ($key, $this->_id);
3356            }
3357            return 1;
3358        }
3359        function purge()
3360        {
3361
3362            unlink($this->_filename."cache");
3363
3364        }
3365        function find($key)
3366        {
3367            return dba_fetch($key,$this->_id);
3368        }
3369
3370
3371    }
3372?>
Note: See TracBrowser for help on using the repository browser.