PageRenderTime 770ms CodeModel.GetById 37ms RepoModel.GetById 12ms app.codeStats 0ms

/backend/kolab/kolab.php

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