1<?php 2 3class GoSyncUtils { 4 5 6 7 8 /** 9 * Get the Group-Office Sync settings for the given user 10 * If no user is given then it will take the settings for the current user 11 * 12 * @return \GO\Sync\Model\Settings 13 */ 14 public static function getUserSettings($user = false) { 15 16 if (empty($user)) 17 $user = \GO::user(); 18 19 return \GO\Sync\Model\Settings::model()->findForUser($user); 20 } 21 22// public static function getEntityModSeq($entity) { 23// $entityModSeq = go()->getDbConnection() 24// ->selectSingleValue("MAX(modSeq)") 25// ->from("core_change") 26// ->where([ 27// "entityTypeId" => $entity->getType()->getId(), 28// "entityId" => $entity->id 29// ]) 30// ->single(); 31// 32// if(empty($entityModSeq)) { 33// return false; 34// } 35// 36// $userModSeq = go()->getDbConnection() 37// ->selectSingleValue("MAX(modSeq)") 38// ->from("core_change_user") 39// ->where([ 40// "entityTypeId" => $entity->getType()->getId(), 41// "entityId" => $entity->id, 42// "userId" => go()->getUserId() 43// ]) 44// ->single(); 45// 46// if(empty($entityModSeq)) { 47// return false; 48// } 49// 50// return $entityModSeq.':'.$userModSeq; 51// 52// } 53 54 /** 55 * Returns the best match of preferred body preference types. 56 * 57 * @param array $bpTypes 58 * 59 * @access private 60 * @return int 61 */ 62 public static function getBodyPreferenceMatch($bpTypes, $supported = array(SYNC_BODYPREFERENCE_PLAIN, SYNC_BODYPREFERENCE_HTML)) { 63 64 ZLog::Write(LOGLEVEL_DEBUG, 'GoSyncUtils->getBodyPreferenceMatch() ~~ bpTypes = ' . var_export($bpTypes, true)); 65 66 if (is_array($bpTypes)) { 67 68 // The best choice is RTF, then HTML and then MIME in order to save bandwidth 69 // because MIME is a complete message including the headers and attachments 70 if (in_array(SYNC_BODYPREFERENCE_RTF, $bpTypes) && in_array(SYNC_BODYPREFERENCE_RTF, $supported)) 71 return SYNC_BODYPREFERENCE_RTF; 72 if (in_array(SYNC_BODYPREFERENCE_HTML, $bpTypes) && in_array(SYNC_BODYPREFERENCE_HTML, $supported)) 73 return SYNC_BODYPREFERENCE_HTML; 74 if (in_array(SYNC_BODYPREFERENCE_MIME, $bpTypes) && in_array(SYNC_BODYPREFERENCE_MIME, $supported)) 75 return SYNC_BODYPREFERENCE_MIME; 76 } 77 78 if (defined("BACKEND_GO_DEFAULT_BODY_PREFENCE")) { 79 return BACKEND_GO_DEFAULT_BODY_PREFENCE; 80 } 81 82 return SYNC_BODYPREFERENCE_PLAIN; 83 } 84 85 /** 86 * Get the correct formatted \SyncBaseBody from an attribute of a model from GO. 87 * 88 * @param \GO\Base\Db\ActiveRecord $model 89 * @param StringHelper $attribute 90 * @param int $sbReturnType 91 * @return \SyncBaseBody 92 */ 93 public static function createASBodyForMessage($model, $attribute, $sbReturnType = SYNC_BODYPREFERENCE_HTML) { 94 95 $sbBody = new SyncBaseBody(); 96 97 $asBodyData = \GO\Base\Util\StringHelper::normalizeCrlf($model->$attribute); 98 99 if(!isset($asBodyData)) { 100 $asBodyData = ""; 101 } 102 103 if ($sbReturnType == SYNC_BODYPREFERENCE_HTML) { 104 105 ZLog::Write(LOGLEVEL_DEBUG, 'SYNCUTILS HTML'); 106 107 $sbBody->type = SYNC_BODYPREFERENCE_HTML; 108 109 $asBodyData = \GO\Base\Util\StringHelper::text_to_html($asBodyData); 110 } else { 111 112 $sbBody->type = SYNC_BODYPREFERENCE_PLAIN; 113 } 114 ZLog::Write(LOGLEVEL_DEBUG, $asBodyData); 115 116 ZLog::Write(LOGLEVEL_DEBUG, 'SYNCUTILS END'); 117 118 $sbBody->estimatedDataSize = strlen($asBodyData); 119 $sbBody->data = StringStreamWrapper::Open($asBodyData); 120 $sbBody->truncated = 0; 121 122 return $sbBody; 123 } 124 125 /** 126 * Get the body text of the message 127 * 128 * @param \SyncObject $message 129 * @return StringHelper 130 */ 131 public static function getBodyFromMessage($message) { 132 133 if (Request::GetProtocolVersion() >= 12.0) { 134 return isset($message->asbody) && isset($message->asbody->data) ? stream_get_contents($message->asbody->data) : ""; 135 } else { 136 if (!empty($message->body)) 137 return $message->body; 138 139 if (isset($message->rtf)) { 140 $rtfParser = new \GO\Base\Util\Rtf(); 141 $rtfParser->output('ascii'); 142 $rtfParser->loadrtf(base64_decode($message->rtf)); 143 $rtfParser->parse(); 144 return (string) $rtfParser->out; 145 } 146 } 147 return ""; 148 } 149 150 /* Translates recurrence information in ActiveSync format to the rrule field 151 * for the tasks table or calendar event table. 152 */ 153 154 public static function importRecurrence($recur, $eventStartTime) { 155 $rrule = ''; 156 $freq = ""; 157 switch ($recur->type) { 158 case 0: 159 $freq = "DAILY"; 160 break; 161 case 1: 162 $freq = "WEEKLY"; 163 break; 164 case 2: 165 $freq = "MONTHLY"; 166 break; 167 case 3: 168 $freq = "MONTHLY"; 169 break; 170 case 5: 171 case 6: 172 $freq = "YEARLY"; 173 break; 174 } 175 176 if ($freq) { 177 178 $rrule = new \GO\Base\Util\Icalendar\Rrule(); 179 $rrule->eventStartTime = $eventStartTime; 180 $rrule->freq = $freq; 181 $rrule->interval = $recur->interval; 182 if (!empty($recur->until)) 183 $rrule->until = $recur->until; 184 185 $rrule->byday = self::aSync2weekday($recur->dayofweek); 186 if (!empty($recur->weekofmonth)) 187 $rrule->bysetpos = $recur->weekofmonth; 188 189// $rrule->shiftDays(true); 190 191 return $rrule->createRrule(); 192 }else { 193 return false; 194 } 195 } 196 197 public static function aSync2weekday($number) { 198 $weekdays = array(); 199 if ($number >= 128 || $number < 0) { 200 throw new \Exception('The way the recurrence days were coded, is corrupted!'); 201 } 202 if ($number >= 64) { 203 $number -=64; 204 $weekdays[] = 'SA'; 205 } 206 if ($number >= 32) { 207 $number -=32; 208 $weekdays[] = 'FR'; 209 } 210 if ($number >= 16) { 211 $number -=16; 212 $weekdays[] = 'TH'; 213 } 214 if ($number >= 8) { 215 $number -=8; 216 $weekdays[] = 'WE'; 217 } 218 if ($number >= 4) { 219 $number -=4; 220 $weekdays[] = 'TU'; 221 } 222 if ($number >= 2) { 223 $number -=2; 224 $weekdays[] = 'MO'; 225 } 226 if ($number >= 1) { 227 $number -=1; 228 $weekdays[] = 'SU'; 229 } 230 return $weekdays; 231 } 232 233 public static function weekday2ASync($weekdays) { 234 //ZLog::Write(LOGLEVEL_DEBUG, var_export($weekdays, true)); 235 $ASyncDay = 0; 236 foreach ($weekdays as $weekday) { 237 switch ($weekday) { 238 case 'MO': 239 $ASyncDay += 2; 240 break; 241 case 'TU': 242 $ASyncDay += 4; 243 break; 244 case 'WE': 245 $ASyncDay += 8; 246 break; 247 case 'TH': 248 $ASyncDay += 16; 249 break; 250 case 'FR': 251 $ASyncDay += 32; 252 break; 253 case 'SA': 254 $ASyncDay += 64; 255 break; 256 case 'SU': 257 $ASyncDay += 1; 258 break; 259 } 260 } 261 return $ASyncDay; 262 } 263 264 public static function getTimeZoneForClient() { 265 266 if (!isset(\GO::session()->values['activesync_timezone'])) { 267 $old = date_default_timezone_get(); 268 date_default_timezone_set(\GO::user()->timezone); 269 270 $tz = new DateTimeZone(\GO::user()->timezone); 271 $transitions = $tz->getTransitions(); 272 $start_of_year = mktime(0, 0, 0, 1, 1); 273 274 for ($i = 0, $max = count($transitions); $i < $max; $i++) { 275 if ($transitions[$i]['ts'] > $start_of_year) { 276 $dst_end = $transitions[$i]; 277 $dst_start = $transitions[$i + 1]; 278 break; 279 } 280 } 281 282 if (!isset($dst_end)) { 283 $astz['format'] = "la64vvvvvvvv" . "la64vvvvvvvv" . "l"; 284 $astz['bias'] = 0; 285 $astz['stdname'] = $tz->getName(); 286 $astz['stdyear'] = 0; 287 $astz['stdmonth'] = 0; 288 $astz['stdday'] = 0; 289 290 $astz['stdweek'] = 0; 291 $astz['stdhour'] = 0; 292 $astz['stdminute'] = 0; 293 $astz['stdmillis'] = 0; 294 $astz['stdsecond'] = 0; 295 $astz['stdbias'] = 0; 296 297 $astz['dstname'] = ""; 298 $astz['dstyear'] = 0; 299 $astz['dstmonth'] = 0; 300 $astz['dstday'] = 0; 301 $astz['dstweek'] = 0; 302 $astz['dsthour'] = 0; 303 $astz['dstminute'] = 0; 304 $astz['dstsecond'] = 0; 305 $astz['dstdmillis'] = 0; 306 $astz['dstbias'] = 0; 307 } else { 308 $astz['format'] = "la64vvvvvvvv" . "la64vvvvvvvv" . "l"; 309 $astz['bias'] = $dst_start['offset'] / -60; 310 $astz['stdname'] = $tz->getName(); 311 $astz['stdyear'] = 0; 312 $astz['stdmonth'] = date('n', $dst_start['ts']); 313 $astz['stdday'] = date('w', $dst_start['ts']); 314 $stdweek = \GO\Base\Util\Date::get_occurring_number_of_day_in_month($dst_start['ts']); 315 if ($stdweek == 4) { 316 $stdweek = 5; 317 } 318 319 $astz['stdweek'] = $stdweek; 320 $astz['stdhour'] = date('G', $dst_start['ts']); 321 $astz['stdminute'] = intval(date('i', $dst_start['ts'])); 322 $astz['stdmillis'] = 0; 323 $astz['stdsecond'] = 0; 324 $astz['stdbias'] = 0; 325 326 $astz['dstname'] = ""; 327 $astz['dstyear'] = 0; 328 $astz['dstmonth'] = date('n', $dst_end['ts']); 329 $astz['dstday'] = date('w', $dst_end['ts']); 330 $dstweek = \GO\Base\Util\Date::get_occurring_number_of_day_in_month($dst_end['ts']); 331 if ($dstweek == 4) { 332 $dstweek = 5; 333 } 334 $astz['dstweek'] = $dstweek; 335 $astz['dsthour'] = date('G', $dst_end['ts']); 336 $astz['dstminute'] = intval(date('i', $dst_end['ts'])); 337 $astz['dstsecond'] = 0; 338 $astz['dstdmillis'] = 0; 339 $astz['dstbias'] = ($dst_end['offset'] / -60) - $astz['bias']; 340 } 341 date_default_timezone_set($old); 342 \GO::session()->values['activesync_timezone'] = base64_encode(call_user_func_array('pack', $astz)); 343 } 344 345 /* $timezone = base64_encode( 346 pack("la64vvvvvvvv" . "la64vvvvvvvv" . "l", 347 -60, //bias, the standard timezone UTC offset in minutes, in this case +2 hour 348 349 "Europe/Amsterdam", //stdname, we could give this timezone a name, like EET 350 0, //stdyear, the year off the timezone, 0 means every year 351 10, //stdmonth, the month the dst ends, 10 equals october 352 0, //stdday, the day the dst ends, 0 equeals sunday 353 5, //stdweek, weeknumber in the month the dst ends, where 1 will give the first dstendday of dstendmonth, 5 is the last dstendday of dstendmonth 354 2, //stdhour, the hour the dst ends 355 0, //stdminute 356 0, //stdsecond 357 0, //stdmillis 358 0, //stdbias, the difference between timezone and std in minutes usually 0 359 360 "", //dstname, name of dst version, like EEST 361 0, //dstyear, the year off the timezone, 0 means every year 362 3, //dstmonth, the month the dst start, 3 equals march 363 0, //dstday, the day the dst starts, 0 equeals sunday 364 5, //dstweek, weeknumber in the month the dst starts, where 1 will give the first dstendday of dstendmonth, 5 is the last dstendday of dstendmonth 365 3, //dsthour, the hour the dst starts 366 0, //dstminute 367 0, //dstsecond 368 0, //dstmillis 369 -60 //dstbias, the difference between timezone and dst in minutes usually -60 370 )); 371 return $timezone; */ 372 373 //test n900 374 //return 'xP///0UAdQByAG8AcABlAC8AQQBtAHMAdABlAHIAZABhAG0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAIAAAAAAAAAAAAAAEUAdQByAG8AcABlAC8AQQBtAHMAdABlAHIAZABhAG0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAFAAMAAAAAAAAAxP///w=='; 375 //GMT 376 /* return base64_encode( 377 pack("la64vvvvvvvv" . "la64vvvvvvvv" . "l", 378 0, "", 0, 0, 0, 0, 0, 0, 0, 0, 379 0, "", 0, 0, 0, 0, 0, 0, 0, 0, 380 0 381 )); */ 382 383 return \GO::session()->values['activesync_timezone']; 384 } 385 386 /* Translates rrule field, repeat_end_time field, and start_time field from 387 * the calendar events table to a format understandable for ActiveSync. 388 */ 389 390 public static function exportRecurrence($model) { 391 392 $old = date_default_timezone_get(); 393 date_default_timezone_set($model->timezone ?? \GO::user()->timezone); 394 395 if ($model instanceof \GO\Tasks\Model\Task) 396 $recur = new SyncTaskRecurrence(); 397 else 398 $recur = new SyncRecurrence(); 399 400 $rrule = new \GO\Base\Util\Icalendar\Rrule(); 401 $rrule->readIcalendarRruleString($model->start_time, $model->rrule, false); 402 403 $recur->interval = $rrule->interval; 404 if ($model->repeat_end_time > 0) { 405 $recur->until = $rrule->until; //\GO\Base\Util\Date::date_add($model->repeat_end_time,1)-1; // add one day (minus 1 sec) to the end time to make sure the last occurrence is covered 406 } 407 408 if(!empty($rrule->count)) { 409 $recur->occurrences = $rrule->count; 410 } 411 switch ($rrule->freq) { 412 case 'DAILY': 413 $recur->type = 0; 414 break; 415 case 'WEEKLY': 416 $recur->type = 1; 417 $recur->dayofweek = self::weekday2ASync($rrule->byday); 418 break; 419 case 'MONTHLY': 420 if (isset($rrule->byday[0])) { 421 $recur->type = 3; 422 $recur->weekofmonth = $rrule->bysetpos; 423 $recur->dayofweek = self::weekday2ASync($rrule->byday); 424 } else { 425 $recur->dayofmonth = date('j', $model->start_time); 426 $recur->type = 2; 427 } 428 break; 429 case 'YEARLY': 430 $recur->type = 5; 431 $recur->monthofyear = date('n', $model->start_time); 432 $recur->dayofmonth = date('j', $model->start_time); 433 break; 434 } 435 436 date_default_timezone_set($old); 437 438 return $recur; 439 } 440 441} 442