PageRenderTime 58ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/utils/utils.php

https://github.com/MikeEvans/PHP-Push-2
PHP | 872 lines | 590 code | 40 blank | 242 comment | 68 complexity | 9e62920181f683784bd507fbe1530886 MD5 | raw file
Possible License(s): AGPL-3.0
  1. <?php
  2. /***********************************************
  3. * File : utils.php
  4. * Project : Z-Push
  5. * Descr : Several utility functions
  6. *
  7. * Created : 03.04.2008
  8. *
  9. * Copyright 2007 - 2011 Zarafa Deutschland GmbH
  10. *
  11. * This program is free software: you can redistribute it and/or modify
  12. * it under the terms of the GNU Affero General Public License, version 3,
  13. * as published by the Free Software Foundation with the following additional
  14. * term according to sec. 7:
  15. *
  16. * According to sec. 7 of the GNU Affero General Public License, version 3,
  17. * the terms of the AGPL are supplemented with the following terms:
  18. *
  19. * "Zarafa" is a registered trademark of Zarafa B.V.
  20. * "Z-Push" is a registered trademark of Zarafa Deutschland GmbH
  21. * The licensing of the Program under the AGPL does not imply a trademark license.
  22. * Therefore any rights, title and interest in our trademarks remain entirely with us.
  23. *
  24. * However, if you propagate an unmodified version of the Program you are
  25. * allowed to use the term "Z-Push" to indicate that you distribute the Program.
  26. * Furthermore you may use our trademarks where it is necessary to indicate
  27. * the intended purpose of a product or service provided you use it in accordance
  28. * with honest practices in industrial or commercial matters.
  29. * If you want to propagate modified versions of the Program under the name "Z-Push",
  30. * you may only do so if you have a written permission by Zarafa Deutschland GmbH
  31. * (to acquire a permission please contact Zarafa at trademark@zarafa.com).
  32. *
  33. * This program is distributed in the hope that it will be useful,
  34. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  35. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  36. * GNU Affero General Public License for more details.
  37. *
  38. * You should have received a copy of the GNU Affero General Public License
  39. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  40. *
  41. * Consult LICENSE file for details
  42. ************************************************/
  43. class Utils {
  44. /**
  45. * Prints a variable as string
  46. * If a boolean is sent, 'true' or 'false' is displayed
  47. *
  48. * @param string $var
  49. * @access public
  50. * @return string
  51. */
  52. static public function PrintAsString($var) {
  53. return ($var)?(($var===true)?'true':$var):(($var===false)?'false':(($var==='')?'empty':$var));
  54. //return ($var)?(($var===true)?'true':$var):'false';
  55. }
  56. /**
  57. * Splits a "domain\user" string into two values
  58. * If the string cotains only the user, domain is returned empty
  59. *
  60. * @param string $domainuser
  61. *
  62. * @access public
  63. * @return array index 0: user 1: domain
  64. */
  65. static public function SplitDomainUser($domainuser) {
  66. $pos = strrpos($domainuser, '\\');
  67. if($pos === false){
  68. $user = $domainuser;
  69. $domain = '';
  70. }
  71. else{
  72. $domain = substr($domainuser,0,$pos);
  73. $user = substr($domainuser,$pos+1);
  74. }
  75. return array($user, $domain);
  76. }
  77. /**
  78. * iPhone defines standard summer time information for current year only,
  79. * starting with time change in February. Dates from the 1st January until
  80. * the time change are undefined and the server uses GMT or its current time.
  81. * The function parses the ical attachment and replaces DTSTART one year back
  82. * in VTIMEZONE section if the event takes place in this undefined time.
  83. * See also http://developer.berlios.de/mantis/view.php?id=311
  84. *
  85. * @param string $ical iCalendar data
  86. *
  87. * @access public
  88. * @return string
  89. */
  90. static public function IcalTimezoneFix($ical) {
  91. $eventDate = substr($ical, (strpos($ical, ":", strpos($ical, "DTSTART", strpos($ical, "BEGIN:VEVENT")))+1), 8);
  92. $posStd = strpos($ical, "DTSTART:", strpos($ical, "BEGIN:STANDARD")) + strlen("DTSTART:");
  93. $posDst = strpos($ical, "DTSTART:", strpos($ical, "BEGIN:DAYLIGHT")) + strlen("DTSTART:");
  94. $beginStandard = substr($ical, $posStd , 8);
  95. $beginDaylight = substr($ical, $posDst , 8);
  96. if (($eventDate < $beginStandard) && ($eventDate < $beginDaylight) ) {
  97. ZLog::Write(LOGLEVEL_DEBUG,"icalTimezoneFix for event on $eventDate, standard:$beginStandard, daylight:$beginDaylight");
  98. $year = intval(date("Y")) - 1;
  99. $ical = substr_replace($ical, $year, (($beginStandard < $beginDaylight) ? $posDst : $posStd), strlen($year));
  100. }
  101. return $ical;
  102. }
  103. /**
  104. * Build an address string from the components
  105. *
  106. * @param string $street the street
  107. * @param string $zip the zip code
  108. * @param string $city the city
  109. * @param string $state the state
  110. * @param string $country the country
  111. *
  112. * @access public
  113. * @return string the address string or null
  114. */
  115. static public function BuildAddressString($street, $zip, $city, $state, $country) {
  116. $out = "";
  117. if (isset($country) && $street != "") $out = $country;
  118. $zcs = "";
  119. if (isset($zip) && $zip != "") $zcs = $zip;
  120. if (isset($city) && $city != "") $zcs .= (($zcs)?" ":"") . $city;
  121. if (isset($state) && $state != "") $zcs .= (($zcs)?" ":"") . $state;
  122. if ($zcs) $out = $zcs . "\r\n" . $out;
  123. if (isset($street) && $street != "") $out = $street . (($out)?"\r\n\r\n". $out: "") ;
  124. return ($out)?$out:null;
  125. }
  126. /**
  127. * Build the fileas string from the components according to the configuration.
  128. *
  129. * @param string $lastname
  130. * @param string $firstname
  131. * @param string $middlename
  132. * @param string $company
  133. *
  134. * @access public
  135. * @return string fileas
  136. */
  137. static public function BuildFileAs($lastname = "", $firstname = "", $middlename = "", $company = "") {
  138. if (defined('FILEAS_ORDER')) {
  139. $fileas = $lastfirst = $firstlast = "";
  140. $names = trim ($firstname . " " . $middlename);
  141. $lastname = trim($lastname);
  142. $company = trim($company);
  143. // lastfirst is "lastname, firstname middlename"
  144. // firstlast is "firstname middlename lastname"
  145. if (strlen($lastname) > 0) {
  146. $lastfirst = $lastname;
  147. if (strlen($names) > 0){
  148. $lastfirst .= ", $names";
  149. $firstlast = "$names $lastname";
  150. }
  151. else {
  152. $firstlast = $lastname;
  153. }
  154. }
  155. elseif (strlen($names) > 0) {
  156. $lastfirst = $firstlast = $names;
  157. }
  158. // if fileas with a company is selected
  159. // but company is emtpy then it will
  160. // fallback to firstlast or lastfirst
  161. // (depending on which is selected for company)
  162. switch (FILEAS_ORDER) {
  163. case SYNC_FILEAS_COMPANYONLY:
  164. if (strlen($company) > 0) {
  165. $fileas = $company;
  166. }
  167. elseif (strlen($firstlast) > 0)
  168. $fileas = $firstlast;
  169. break;
  170. case SYNC_FILEAS_COMPANYLAST:
  171. if (strlen($company) > 0) {
  172. $fileas = $company;
  173. if (strlen($lastfirst) > 0)
  174. $fileas .= "($lastfirst)";
  175. }
  176. elseif (strlen($lastfirst) > 0)
  177. $fileas = $lastfirst;
  178. break;
  179. case SYNC_FILEAS_COMPANYFIRST:
  180. if (strlen($company) > 0) {
  181. $fileas = $company;
  182. if (strlen($firstlast) > 0) {
  183. $fileas .= " ($firstlast)";
  184. }
  185. }
  186. elseif (strlen($firstlast) > 0) {
  187. $fileas = $firstlast;
  188. }
  189. break;
  190. case SYNC_FILEAS_FIRSTCOMPANY:
  191. if (strlen($firstlast) > 0) {
  192. $fileas = $firstlast;
  193. if (strlen($company) > 0) {
  194. $fileas .= " ($company)";
  195. }
  196. }
  197. elseif (strlen($company) > 0) {
  198. $fileas = $company;
  199. }
  200. break;
  201. case SYNC_FILEAS_LASTCOMPANY:
  202. if (strlen($lastfirst) > 0) {
  203. $fileas = $lastfirst;
  204. if (strlen($company) > 0) {
  205. $fileas .= " ($company)";
  206. }
  207. }
  208. elseif (strlen($company) > 0) {
  209. $fileas = $company;
  210. }
  211. break;
  212. case SYNC_FILEAS_LASTFIRST:
  213. if (strlen($lastfirst) > 0) {
  214. $fileas = $lastfirst;
  215. }
  216. break;
  217. default:
  218. $fileas = $firstlast;
  219. break;
  220. }
  221. if (strlen($fileas) == 0)
  222. ZLog::Write(LOGLEVEL_DEBUG, "Fileas is empty.");
  223. return $fileas;
  224. }
  225. ZLog::Write(LOGLEVEL_DEBUG, "FILEAS_ORDER not defined. Add it to your config.php.");
  226. return null;
  227. }
  228. /**
  229. * Checks if the PHP-MAPI extension is available and in a requested version
  230. *
  231. * @param string $version the version to be checked ("6.30.10-18495", parts or build number)
  232. *
  233. * @access public
  234. * @return boolean installed version is superior to the checked strin
  235. */
  236. static public function CheckMapiExtVersion($version = "") {
  237. // compare build number if requested
  238. if (preg_match('/^\d+$/', $version) && strlen($version) > 3) {
  239. $vs = preg_split('/-/', phpversion("mapi"));
  240. return ($version <= $vs[1]);
  241. }
  242. if (extension_loaded("mapi")){
  243. if (version_compare(phpversion("mapi"), $version) == -1){
  244. return false;
  245. }
  246. }
  247. else
  248. return false;
  249. return true;
  250. }
  251. /**
  252. * Parses and returns an ecoded vCal-Uid from an
  253. * OL compatible GlobalObjectID
  254. *
  255. * @param string $olUid an OL compatible GlobalObjectID
  256. *
  257. * @access public
  258. * @return string the vCal-Uid if available in the olUid, else the original olUid as HEX
  259. */
  260. static public function GetICalUidFromOLUid($olUid){
  261. //check if "vCal-Uid" is somewhere in outlookid case-insensitive
  262. $icalUid = stristr($olUid, "vCal-Uid");
  263. if ($icalUid !== false) {
  264. //get the length of the ical id - go back 4 position from where "vCal-Uid" was found
  265. $begin = unpack("V", substr($olUid, strlen($icalUid) * (-1) - 4, 4));
  266. //remove "vCal-Uid" and packed "1" and use the ical id length
  267. return substr($icalUid, 12, ($begin[1] - 13));
  268. }
  269. return strtoupper(bin2hex($olUid));
  270. }
  271. /**
  272. * Checks the given UID if it is an OL compatible GlobalObjectID
  273. * If not, the given UID is encoded inside the GlobalObjectID
  274. *
  275. * @param string $icalUid an appointment uid as HEX
  276. *
  277. * @access public
  278. * @return string an OL compatible GlobalObjectID
  279. *
  280. */
  281. static public function GetOLUidFromICalUid($icalUid) {
  282. if (strlen($icalUid) <= 64) {
  283. $len = 13 + strlen($icalUid);
  284. $OLUid = pack("V", $len);
  285. $OLUid .= "vCal-Uid";
  286. $OLUid .= pack("V", 1);
  287. $OLUid .= $icalUid;
  288. return hex2bin("040000008200E00074C5B7101A82E0080000000000000000000000000000000000000000". bin2hex($OLUid). "00");
  289. }
  290. else
  291. return hex2bin($icalUid);
  292. }
  293. /**
  294. * Extracts the basedate of the GlobalObjectID and the RecurStartTime
  295. *
  296. * @param string $goid OL compatible GlobalObjectID
  297. * @param long $recurStartTime
  298. *
  299. * @access public
  300. * @return long basedate
  301. */
  302. static public function ExtractBaseDate($goid, $recurStartTime) {
  303. $hexbase = substr(bin2hex($goid), 32, 8);
  304. $day = hexdec(substr($hexbase, 6, 2));
  305. $month = hexdec(substr($hexbase, 4, 2));
  306. $year = hexdec(substr($hexbase, 0, 4));
  307. if ($day && $month && $year) {
  308. $h = $recurStartTime >> 12;
  309. $m = ($recurStartTime - $h * 4096) >> 6;
  310. $s = $recurStartTime - $h * 4096 - $m * 64;
  311. return gmmktime($h, $m, $s, $month, $day, $year);
  312. }
  313. else
  314. return false;
  315. }
  316. /**
  317. * Converts SYNC_FILTERTYPE into a timestamp
  318. *
  319. * @param int Filtertype
  320. *
  321. * @access public
  322. * @return long
  323. */
  324. static public function GetCutOffDate($restrict) {
  325. switch($restrict) {
  326. case SYNC_FILTERTYPE_1DAY:
  327. $back = 60 * 60 * 24;
  328. break;
  329. case SYNC_FILTERTYPE_3DAYS:
  330. $back = 60 * 60 * 24 * 3;
  331. break;
  332. case SYNC_FILTERTYPE_1WEEK:
  333. $back = 60 * 60 * 24 * 7;
  334. break;
  335. case SYNC_FILTERTYPE_2WEEKS:
  336. $back = 60 * 60 * 24 * 14;
  337. break;
  338. case SYNC_FILTERTYPE_1MONTH:
  339. $back = 60 * 60 * 24 * 31;
  340. break;
  341. case SYNC_FILTERTYPE_3MONTHS:
  342. $back = 60 * 60 * 24 * 31 * 3;
  343. break;
  344. case SYNC_FILTERTYPE_6MONTHS:
  345. $back = 60 * 60 * 24 * 31 * 6;
  346. break;
  347. default:
  348. break;
  349. }
  350. if(isset($back)) {
  351. $date = time() - $back;
  352. return $date;
  353. } else
  354. return 0; // unlimited
  355. }
  356. /**
  357. * Converts SYNC_TRUNCATION into bytes
  358. *
  359. * @param int SYNC_TRUNCATION
  360. *
  361. * @return long
  362. */
  363. static public function GetTruncSize($truncation) {
  364. switch($truncation) {
  365. case SYNC_TRUNCATION_HEADERS:
  366. return 0;
  367. case SYNC_TRUNCATION_512B:
  368. return 512;
  369. case SYNC_TRUNCATION_1K:
  370. return 1024;
  371. case SYNC_TRUNCATION_2K:
  372. return 2*1024;
  373. case SYNC_TRUNCATION_5K:
  374. return 5*1024;
  375. case SYNC_TRUNCATION_10K:
  376. return 10*1024;
  377. case SYNC_TRUNCATION_20K:
  378. return 20*1024;
  379. case SYNC_TRUNCATION_50K:
  380. return 50*1024;
  381. case SYNC_TRUNCATION_100K:
  382. return 100*1024;
  383. case SYNC_TRUNCATION_ALL:
  384. return 1024*1024; // We'll limit to 1MB anyway
  385. default:
  386. return 1024; // Default to 1Kb
  387. }
  388. }
  389. /**
  390. * Truncate an UTF-8 encoded sting correctly
  391. *
  392. * If it's not possible to truncate properly, an empty string is returned
  393. *
  394. * @param string $string - the string
  395. * @param string $length - position where string should be cut
  396. * @return string truncated string
  397. */
  398. static public function Utf8_truncate($string, $length) {
  399. // make sure length is always an interger
  400. $length = (int)$length;
  401. if (strlen($string) <= $length)
  402. return $string;
  403. while($length >= 0) {
  404. if ((ord($string[$length]) < 0x80) || (ord($string[$length]) >= 0xC0))
  405. return substr($string, 0, $length);
  406. $length--;
  407. }
  408. return "";
  409. }
  410. /**
  411. * Indicates if the specified folder type is a system folder
  412. *
  413. * @param int $foldertype
  414. *
  415. * @access public
  416. * @return boolean
  417. */
  418. static public function IsSystemFolder($foldertype) {
  419. return ($foldertype == SYNC_FOLDER_TYPE_INBOX || $foldertype == SYNC_FOLDER_TYPE_DRAFTS || $foldertype == SYNC_FOLDER_TYPE_WASTEBASKET || $foldertype == SYNC_FOLDER_TYPE_SENTMAIL ||
  420. $foldertype == SYNC_FOLDER_TYPE_OUTBOX || $foldertype == SYNC_FOLDER_TYPE_TASK || $foldertype == SYNC_FOLDER_TYPE_APPOINTMENT || $foldertype == SYNC_FOLDER_TYPE_CONTACT ||
  421. $foldertype == SYNC_FOLDER_TYPE_NOTE || $foldertype == SYNC_FOLDER_TYPE_JOURNAL) ? true:false;
  422. }
  423. /**
  424. * Our own utf7_decode function because imap_utf7_decode converts a string
  425. * into ISO-8859-1 encoding which doesn't have euro sign (it will be converted
  426. * into two chars: [space](ascii 32) and "ÂŹ" ("not sign", ascii 172)). Also
  427. * php iconv function expects '+' as delimiter instead of '&' like in IMAP.
  428. *
  429. * @param string $string IMAP folder name
  430. *
  431. * @access public
  432. * @return string
  433. */
  434. static public function Utf7_iconv_decode($string) {
  435. //do not alter string if there aren't any '&' or '+' chars because
  436. //it won't have any utf7-encoded chars and nothing has to be escaped.
  437. if (strpos($string, '&') === false && strpos($string, '+') === false ) return $string;
  438. //Get the string length and go back through it making the replacements
  439. //necessary
  440. $len = strlen($string) - 1;
  441. while ($len > 0) {
  442. //look for '&-' sequence and replace it with '&'
  443. if ($len > 0 && $string{($len-1)} == '&' && $string{$len} == '-') {
  444. $string = substr_replace($string, '&', $len - 1, 2);
  445. $len--; //decrease $len as this char has alreasy been processed
  446. }
  447. //search for '&' which weren't found in if clause above and
  448. //replace them with '+' as they mark an utf7-encoded char
  449. if ($len > 0 && $string{($len-1)} == '&') {
  450. $string = substr_replace($string, '+', $len - 1, 1);
  451. $len--; //decrease $len as this char has alreasy been processed
  452. }
  453. //finally "escape" all remaining '+' chars
  454. if ($len > 0 && $string{($len-1)} == '+') {
  455. $string = substr_replace($string, '+-', $len - 1, 1);
  456. }
  457. $len--;
  458. }
  459. return $string;
  460. }
  461. /**
  462. * Our own utf7_encode function because the string has to be converted from
  463. * standard UTF7 into modified UTF7 (aka UTF7-IMAP).
  464. *
  465. * @param string $str IMAP folder name
  466. *
  467. * @access public
  468. * @return string
  469. */
  470. static public function Utf7_iconv_encode($string) {
  471. //do not alter string if there aren't any '&' or '+' chars because
  472. //it won't have any utf7-encoded chars and nothing has to be escaped.
  473. if (strpos($string, '&') === false && strpos($string, '+') === false ) return $string;
  474. //Get the string length and go back through it making the replacements
  475. //necessary
  476. $len = strlen($string) - 1;
  477. while ($len > 0) {
  478. //look for '&-' sequence and replace it with '&'
  479. if ($len > 0 && $string{($len-1)} == '+' && $string{$len} == '-') {
  480. $string = substr_replace($string, '+', $len - 1, 2);
  481. $len--; //decrease $len as this char has alreasy been processed
  482. }
  483. //search for '&' which weren't found in if clause above and
  484. //replace them with '+' as they mark an utf7-encoded char
  485. if ($len > 0 && $string{($len-1)} == '+') {
  486. $string = substr_replace($string, '&', $len - 1, 1);
  487. $len--; //decrease $len as this char has alreasy been processed
  488. }
  489. //finally "escape" all remaining '+' chars
  490. if ($len > 0 && $string{($len-1)} == '&') {
  491. $string = substr_replace($string, '&-', $len - 1, 1);
  492. }
  493. $len--;
  494. }
  495. return $string;
  496. }
  497. /**
  498. * Converts an UTF-7 encoded string into an UTF-8 string.
  499. *
  500. * @param string $string to convert
  501. *
  502. * @access public
  503. * @return string
  504. */
  505. static public function Utf7_to_utf8($string) {
  506. if (function_exists("iconv")){
  507. return @iconv("UTF-7", "UTF-8", $string);
  508. }
  509. return $string;
  510. }
  511. /**
  512. * Converts an UTF-8 encoded string into an UTF-7 string.
  513. *
  514. * @param string $string to convert
  515. *
  516. * @access public
  517. * @return string
  518. */
  519. static public function Utf8_to_utf7($string) {
  520. if (function_exists("iconv")){
  521. return @iconv("UTF-8", "UTF-7", $string);
  522. }
  523. return $string;
  524. }
  525. /**
  526. * Checks for valid email addresses
  527. * The used regex actually only checks if a valid email address is part of the submitted string
  528. * it also returns true for the mailbox format, but this is not checked explicitly
  529. *
  530. * @param string $email address to be checked
  531. *
  532. * @access public
  533. * @return boolean
  534. */
  535. static public function CheckEmail($email) {
  536. return (bool) preg_match('#([a-zA-Z0-9_\-])+(\.([a-zA-Z0-9_\-])+)*@((\[(((([0-1])?([0-9])?[0-9])|(2[0-4][0-9])|(2[0-5][0-5])))\.(((([0-1])?([0-9])?[0-9])|(2[0-4][0-9])|(2[0-5][0-5])))\.(((([0-1])?([0-9])?[0-9])|(2[0-4][0-9])|(2[0-5][0-5])))\.(((([0-1])?([0-9])?[0-9])|(2[0-4][0-9])|(2[0-5][0-5]))\]))|((([a-zA-Z0-9])+(([\-])+([a-zA-Z0-9])+)*\.)+([a-zA-Z])+(([\-])+([a-zA-Z0-9])+)*)|localhost)#', $email);
  537. }
  538. /**
  539. * Checks if a string is base64 encoded
  540. *
  541. * @param string $string the string to be checked
  542. *
  543. * @access public
  544. * @return boolean
  545. */
  546. static public function IsBase64String($string) {
  547. return (bool) preg_match("#^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+/]{4})?$#", $string);
  548. }
  549. /**
  550. * Decodes base64 encoded query parameters. Based on dw2412 contribution.
  551. *
  552. * @param string $query the query to decode
  553. *
  554. * @access public
  555. * @return array
  556. */
  557. static public function DecodeBase64URI($query) {
  558. /*
  559. * The query string has a following structure. Number in () is position:
  560. * 1 byte - protocoll version (0)
  561. * 1 byte - command code (1)
  562. * 2 bytes - locale (2)
  563. * 1 byte - device ID length (4)
  564. * variable - device ID (4+device ID length)
  565. * 1 byte - policy key length (5+device ID length)
  566. * 0 or 4 bytes - policy key (5+device ID length + policy key length)
  567. * 1 byte - device type length (6+device ID length + policy key length)
  568. * variable - device type (6+device ID length + policy key length + device type length)
  569. * variable - command parameters, array which consists of:
  570. * 1 byte - tag
  571. * 1 byte - length
  572. * variable - value of the parameter
  573. *
  574. */
  575. $decoded = base64_decode($query);
  576. $devIdLength = ord($decoded[4]); //device ID length
  577. $polKeyLength = ord($decoded[5+$devIdLength]); //policy key length
  578. $devTypeLength = ord($decoded[6+$devIdLength+$polKeyLength]); //device type length
  579. //unpack the decoded query string values
  580. $unpackedQuery = unpack("CProtVer/CCommand/vLocale/CDevIDLen/H".($devIdLength*2)."DevID/CPolKeyLen".($polKeyLength == 4 ? "/VPolKey" : "")."/CDevTypeLen/A".($devTypeLength)."DevType", $decoded);
  581. //get the command parameters
  582. $pos = 7 + $devIdLength + $polKeyLength + $devTypeLength;
  583. $decoded = substr($decoded, $pos);
  584. while (strlen($decoded) > 0) {
  585. $paramLength = ord($decoded[1]);
  586. $unpackedParam = unpack("CParamTag/CParamLength/A".$paramLength."ParamValue", $decoded);
  587. $unpackedQuery[ord($decoded[0])] = $unpackedParam['ParamValue'];
  588. //remove parameter from decoded query string
  589. $decoded = substr($decoded, 2 + $paramLength);
  590. }
  591. return $unpackedQuery;
  592. }
  593. /**
  594. * Returns a command string for a given command code.
  595. *
  596. * @param int $code
  597. *
  598. * @access public
  599. * @return string or false if code is unknown
  600. */
  601. public static function GetCommandFromCode($code) {
  602. switch ($code) {
  603. case ZPush::COMMAND_SYNC: return 'Sync';
  604. case ZPush::COMMAND_SENDMAIL: return 'SendMail';
  605. case ZPush::COMMAND_SMARTFORWARD: return 'SmartForward';
  606. case ZPush::COMMAND_SMARTREPLY: return 'SmartReply';
  607. case ZPush::COMMAND_GETATTACHMENT: return 'GetAttachment';
  608. case ZPush::COMMAND_FOLDERSYNC: return 'FolderSync';
  609. case ZPush::COMMAND_FOLDERCREATE: return 'FolderCreate';
  610. case ZPush::COMMAND_FOLDERDELETE: return 'FolderDelete';
  611. case ZPush::COMMAND_FOLDERUPDATE: return 'FolderUpdate';
  612. case ZPush::COMMAND_MOVEITEMS: return 'MoveItems';
  613. case ZPush::COMMAND_GETITEMESTIMATE: return 'GetItemEstimate';
  614. case ZPush::COMMAND_MEETINGRESPONSE: return 'MeetingResponse';
  615. case ZPush::COMMAND_SEARCH: return 'Search';
  616. case ZPush::COMMAND_SETTINGS: return 'Settings';
  617. case ZPush::COMMAND_PING: return 'Ping';
  618. case ZPush::COMMAND_ITEMOPERATIONS: return 'ItemOperations';
  619. case ZPush::COMMAND_PROVISION: return 'Provision';
  620. case ZPush::COMMAND_RESOLVERECIPIENTS: return 'ResolveRecipients';
  621. case ZPush::COMMAND_VALIDATECERT: return 'ValidateCert';
  622. // Deprecated commands
  623. case ZPush::COMMAND_GETHIERARCHY: return 'GetHierarchy';
  624. case ZPush::COMMAND_CREATECOLLECTION: return 'CreateCollection';
  625. case ZPush::COMMAND_DELETECOLLECTION: return 'DeleteCollection';
  626. case ZPush::COMMAND_MOVECOLLECTION: return 'MoveCollection';
  627. case ZPush::COMMAND_NOTIFY: return 'Notify';
  628. // Webservice commands
  629. case ZPush::COMMAND_WEBSERVICE_DEVICE: return 'WebserviceDevice';
  630. }
  631. return false;
  632. }
  633. /**
  634. * Returns a command code for a given command.
  635. *
  636. * @param string $command
  637. *
  638. * @access public
  639. * @return int or false if command is unknown
  640. */
  641. public static function GetCodeFromCommand($command) {
  642. switch ($command) {
  643. case 'Sync': return ZPush::COMMAND_SYNC;
  644. case 'SendMail': return ZPush::COMMAND_SENDMAIL;
  645. case 'SmartForward': return ZPush::COMMAND_SMARTFORWARD;
  646. case 'SmartReply': return ZPush::COMMAND_SMARTREPLY;
  647. case 'GetAttachment': return ZPush::COMMAND_GETATTACHMENT;
  648. case 'FolderSync': return ZPush::COMMAND_FOLDERSYNC;
  649. case 'FolderCreate': return ZPush::COMMAND_FOLDERCREATE;
  650. case 'FolderDelete': return ZPush::COMMAND_FOLDERDELETE;
  651. case 'FolderUpdate': return ZPush::COMMAND_FOLDERUPDATE;
  652. case 'MoveItems': return ZPush::COMMAND_MOVEITEMS;
  653. case 'GetItemEstimate': return ZPush::COMMAND_GETITEMESTIMATE;
  654. case 'MeetingResponse': return ZPush::COMMAND_MEETINGRESPONSE;
  655. case 'Search': return ZPush::COMMAND_SEARCH;
  656. case 'Settings': return ZPush::COMMAND_SETTINGS;
  657. case 'Ping': return ZPush::COMMAND_PING;
  658. case 'ItemOperations': return ZPush::COMMAND_ITEMOPERATIONS;
  659. case 'Provision': return ZPush::COMMAND_PROVISION;
  660. case 'ResolveRecipients': return ZPush::COMMAND_RESOLVERECIPIENTS;
  661. case 'ValidateCert': return ZPush::COMMAND_VALIDATECERT;
  662. // Deprecated commands
  663. case 'GetHierarchy': return ZPush::COMMAND_GETHIERARCHY;
  664. case 'CreateCollection': return ZPush::COMMAND_CREATECOLLECTION;
  665. case 'DeleteCollection': return ZPush::COMMAND_DELETECOLLECTION;
  666. case 'MoveCollection': return ZPush::COMMAND_MOVECOLLECTION;
  667. case 'Notify': return ZPush::COMMAND_NOTIFY;
  668. // Webservice commands
  669. case 'WebserviceDevice': return ZPush::COMMAND_WEBSERVICE_DEVICE;
  670. }
  671. return false;
  672. }
  673. /**
  674. * Normalize the given timestamp to the start of the day
  675. *
  676. * @param long $timestamp
  677. *
  678. * @access private
  679. * @return long
  680. */
  681. public static function getDayStartOfTimestamp($timestamp) {
  682. return $timestamp - ($timestamp % (60 * 60 * 24));
  683. }
  684. /**
  685. * Returns a formatted string output from an optional timestamp.
  686. * If no timestamp is sent, NOW is used.
  687. *
  688. * @param long $timestamp
  689. *
  690. * @access public
  691. * @return string
  692. */
  693. public static function GetFormattedTime($timestamp = false) {
  694. if (!$timestamp)
  695. return @strftime("%d/%m/%Y %H:%M:%S");
  696. else
  697. return @strftime("%d/%m/%Y %H:%M:%S", $timestamp);
  698. }
  699. /**
  700. * Get charset name from a codepage
  701. *
  702. * @see http://msdn.microsoft.com/en-us/library/dd317756(VS.85).aspx
  703. *
  704. * Table taken from common/codepage.cpp
  705. *
  706. * @param integer codepage Codepage
  707. *
  708. * @access public
  709. * @return string iconv-compatible charset name
  710. */
  711. public static function GetCodepageCharset($codepage) {
  712. $codepages = array(
  713. 20106 => "DIN_66003",
  714. 20108 => "NS_4551-1",
  715. 20107 => "SEN_850200_B",
  716. 950 => "big5",
  717. 50221 => "csISO2022JP",
  718. 51932 => "euc-jp",
  719. 51936 => "euc-cn",
  720. 51949 => "euc-kr",
  721. 949 => "euc-kr",
  722. 936 => "gb18030",
  723. 52936 => "csgb2312",
  724. 852 => "ibm852",
  725. 866 => "ibm866",
  726. 50220 => "iso-2022-jp",
  727. 50222 => "iso-2022-jp",
  728. 50225 => "iso-2022-kr",
  729. 1252 => "windows-1252",
  730. 28591 => "iso-8859-1",
  731. 28592 => "iso-8859-2",
  732. 28593 => "iso-8859-3",
  733. 28594 => "iso-8859-4",
  734. 28595 => "iso-8859-5",
  735. 28596 => "iso-8859-6",
  736. 28597 => "iso-8859-7",
  737. 28598 => "iso-8859-8",
  738. 28599 => "iso-8859-9",
  739. 28603 => "iso-8859-13",
  740. 28605 => "iso-8859-15",
  741. 20866 => "koi8-r",
  742. 21866 => "koi8-u",
  743. 932 => "shift-jis",
  744. 1200 => "unicode",
  745. 1201 => "unicodebig",
  746. 65000 => "utf-7",
  747. 65001 => "utf-8",
  748. 1250 => "windows-1250",
  749. 1251 => "windows-1251",
  750. 1253 => "windows-1253",
  751. 1254 => "windows-1254",
  752. 1255 => "windows-1255",
  753. 1256 => "windows-1256",
  754. 1257 => "windows-1257",
  755. 1258 => "windows-1258",
  756. 874 => "windows-874",
  757. 20127 => "us-ascii"
  758. );
  759. if(isset($codepages[$codepage])) {
  760. return $codepages[$codepage];
  761. } else {
  762. // Defaulting to iso-8859-15 since it is more likely for someone to make a mistake in the codepage
  763. // when using west-european charsets then when using other charsets since utf-8 is binary compatible
  764. // with the bottom 7 bits of west-european
  765. return "iso-8859-15";
  766. }
  767. }
  768. /**
  769. * Converts a string encoded with codepage into an UTF-8 string
  770. *
  771. * @param int $codepage
  772. * @param string $string
  773. *
  774. * @access public
  775. * @return string
  776. */
  777. public static function ConvertCodepageStringToUtf8($codepage, $string) {
  778. if (function_exists("iconv")) {
  779. $charset = self::GetCodepageCharset($codepage);
  780. return iconv($charset, "utf-8", $string);
  781. }
  782. return $string;
  783. }
  784. }
  785. // TODO Win1252/UTF8 functions are deprecated and will be removed sometime
  786. //if the ICS backend is loaded in CombinedBackend and Zarafa > 7
  787. //STORE_SUPPORTS_UNICODE is true and the convertion will not be done
  788. //for other backends.
  789. function utf8_to_windows1252($string, $option = "", $force_convert = false) {
  790. //if the store supports unicode return the string without converting it
  791. if (!$force_convert && defined('STORE_SUPPORTS_UNICODE') && STORE_SUPPORTS_UNICODE == true) return $string;
  792. if (function_exists("iconv")){
  793. return @iconv("UTF-8", "Windows-1252" . $option, $string);
  794. }else{
  795. return utf8_decode($string); // no euro support here
  796. }
  797. }
  798. function windows1252_to_utf8($string, $option = "", $force_convert = false) {
  799. //if the store supports unicode return the string without converting it
  800. if (!$force_convert && defined('STORE_SUPPORTS_UNICODE') && STORE_SUPPORTS_UNICODE == true) return $string;
  801. if (function_exists("iconv")){
  802. return @iconv("Windows-1252", "UTF-8" . $option, $string);
  803. }else{
  804. return utf8_encode($string); // no euro support here
  805. }
  806. }
  807. function w2u($string) { return windows1252_to_utf8($string); }
  808. function u2w($string) { return utf8_to_windows1252($string); }
  809. function w2ui($string) { return windows1252_to_utf8($string, "//TRANSLIT"); }
  810. function u2wi($string) { return utf8_to_windows1252($string, "//TRANSLIT"); }
  811. ?>