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