| Total Complexity | 463 |
| Total Lines | 2194 |
| Duplicated Lines | 0 % |
| Changes | 0 | ||
Complex classes like mail_zpush often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use mail_zpush, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 23 | class mail_zpush implements activesync_plugin_write, activesync_plugin_sendmail, activesync_plugin_meeting_response, activesync_plugin_search_mailbox |
||
| 24 | { |
||
| 25 | /** |
||
| 26 | * var activesync_backend |
||
| 27 | */ |
||
| 28 | private $backend; |
||
| 29 | |||
| 30 | /** |
||
| 31 | * Instance of Mail |
||
| 32 | * |
||
| 33 | * @var Mail |
||
| 34 | */ |
||
| 35 | private $mail; |
||
| 36 | |||
| 37 | /** |
||
| 38 | * Provides the ability to change the line ending |
||
| 39 | * @var string |
||
| 40 | */ |
||
| 41 | public static $LE = "\n"; |
||
| 42 | |||
| 43 | /** |
||
| 44 | * Integer id of trash folder |
||
| 45 | * |
||
| 46 | * @var mixed |
||
| 47 | */ |
||
| 48 | private $_wasteID = false; |
||
| 49 | |||
| 50 | /** |
||
| 51 | * Integer id of sent folder |
||
| 52 | * |
||
| 53 | * @var mixed |
||
| 54 | */ |
||
| 55 | private $_sentID = false; |
||
| 56 | |||
| 57 | /** |
||
| 58 | * Integer id of current mail account / connection |
||
| 59 | * |
||
| 60 | * @var int |
||
| 61 | */ |
||
| 62 | private $account; |
||
| 63 | |||
| 64 | private $folders; |
||
| 65 | |||
| 66 | private $messages; |
||
| 67 | |||
| 68 | static $profileID; |
||
| 69 | |||
| 70 | // to control how deep one may dive into the past |
||
| 71 | const PAST_LIMIT = 178; |
||
| 72 | |||
| 73 | /** |
||
| 74 | * debugLevel - enables more debug |
||
| 75 | * |
||
| 76 | * @var int |
||
| 77 | */ |
||
| 78 | private $debugLevel = 0; |
||
| 79 | |||
| 80 | /** |
||
| 81 | * Constructor |
||
| 82 | * |
||
| 83 | * @param activesync_backend $backend |
||
| 84 | */ |
||
| 85 | public function __construct(activesync_backend $backend) |
||
| 86 | { |
||
| 87 | if ($GLOBALS['egw_setup']) return; |
||
| 88 | |||
| 89 | //$this->debugLevel=2; |
||
| 90 | $this->backend = $backend; |
||
| 91 | if (!isset($GLOBALS['egw_info']['user']['preferences']['activesync']['mail-ActiveSyncProfileID'])) |
||
| 92 | { |
||
| 93 | if ($this->debugLevel>1) error_log(__METHOD__.__LINE__.' Noprefs set: using 0 as default'); |
||
| 94 | // globals preferences add appname varname value |
||
| 95 | $GLOBALS['egw']->preferences->add('activesync','mail-ActiveSyncProfileID',0,'user'); |
||
| 96 | // save prefs |
||
| 97 | $GLOBALS['egw']->preferences->save_repository(true); |
||
| 98 | } |
||
| 99 | if ($this->debugLevel>1) error_log(__METHOD__.__LINE__.' ActiveProfileID:'.array2string(self::$profileID)); |
||
| 100 | |||
| 101 | if (is_null(self::$profileID)) |
||
| 102 | { |
||
| 103 | if ($this->debugLevel>1) error_log(__METHOD__.__LINE__.' self::ProfileID isNUll:'.array2string(self::$profileID)); |
||
| 104 | self::$profileID =& Api\Cache::getSession('mail','activeSyncProfileID'); |
||
| 105 | if ($this->debugLevel>1) error_log(__METHOD__.__LINE__.' ActiveProfileID (after reading Cache):'.array2string(self::$profileID)); |
||
| 106 | } |
||
| 107 | if (isset($GLOBALS['egw_info']['user']['preferences']['activesync']['mail-ActiveSyncProfileID'])) |
||
| 108 | { |
||
| 109 | if ($this->debugLevel>1) error_log(__METHOD__.__LINE__.' Pref for ProfileID:'.array2string($GLOBALS['egw_info']['user']['preferences']['activesync']['mail-ActiveSyncProfileID'])); |
||
| 110 | if ($GLOBALS['egw_info']['user']['preferences']['activesync']['mail-ActiveSyncProfileID'] == 'G') |
||
| 111 | { |
||
| 112 | self::$profileID = 'G'; // this should trigger the fetch of the first negative profile (or if no negative profile is available the firstb there is) |
||
| 113 | } |
||
| 114 | else |
||
| 115 | { |
||
| 116 | self::$profileID = (int)$GLOBALS['egw_info']['user']['preferences']['activesync']['mail-ActiveSyncProfileID']; |
||
| 117 | } |
||
| 118 | } |
||
| 119 | if ($this->debugLevel>1) error_log(__METHOD__.__LINE__.' Profile Selected (after reading Prefs):'.array2string(self::$profileID)); |
||
| 120 | |||
| 121 | // verify we are on an existing profile, if not running in setup (settings can not be static according to interface!) |
||
| 122 | if (!isset($GLOBALS['egw_setup'])) |
||
| 123 | { |
||
| 124 | try { |
||
| 125 | Mail\Account::read(self::$profileID); |
||
| 126 | } |
||
| 127 | catch(Exception $e) { |
||
| 128 | unset($e); |
||
| 129 | self::$profileID = Mail\Account::get_default_acc_id(); |
||
| 130 | } |
||
| 131 | } |
||
| 132 | if ($this->debugLevel>0) error_log(__METHOD__.'::'.__LINE__.' ProfileSelected:'.self::$profileID); |
||
| 133 | //$this->debugLevel=0; |
||
| 134 | } |
||
| 135 | |||
| 136 | /** |
||
| 137 | * Populates $settings for the preferences |
||
| 138 | * |
||
| 139 | * @param array|string $hook_data |
||
| 140 | * @return array |
||
| 141 | */ |
||
| 142 | function egw_settings($hook_data) |
||
| 143 | { |
||
| 144 | //error_log(__METHOD__.__LINE__.array2string($hook_data)); |
||
| 145 | $identities = array(); |
||
| 146 | if (!isset($hook_data['setup']) && in_array($hook_data['type'], array('user', 'group'))) |
||
| 147 | { |
||
| 148 | $identities = iterator_to_array(Mail\Account::search((int)$hook_data['account_id'])); |
||
| 149 | } |
||
| 150 | $identities += array( |
||
| 151 | 'G' => lang('Primary Profile'), |
||
| 152 | ); |
||
| 153 | |||
| 154 | $settings['mail-ActiveSyncProfileID'] = array( |
||
| 155 | 'type' => 'select', |
||
| 156 | 'label' => 'eMail Account to sync', |
||
| 157 | 'name' => 'mail-ActiveSyncProfileID', |
||
| 158 | 'help' => 'eMail Account to sync ', |
||
| 159 | 'values' => $identities, |
||
| 160 | 'default'=> 'G', |
||
| 161 | 'xmlrpc' => True, |
||
| 162 | 'admin' => False, |
||
| 163 | ); |
||
| 164 | $settings['mail-allowSendingInvitations'] = array( |
||
| 165 | 'type' => 'select', |
||
| 166 | 'label' => 'allow sending of calendar invitations using this profile?', |
||
| 167 | 'name' => 'mail-allowSendingInvitations', |
||
| 168 | 'help' => 'control the sending of calendar invitations while using this profile', |
||
| 169 | 'values' => array( |
||
| 170 | 'sendifnocalnotif'=>'only send if there is no notification in calendar', |
||
| 171 | 'send'=>'yes, always send', |
||
| 172 | 'nosend'=>'no, do not send', |
||
| 173 | ), |
||
| 174 | 'xmlrpc' => True, |
||
| 175 | 'default' => 'sendifnocalnotif', |
||
| 176 | 'admin' => False, |
||
| 177 | ); |
||
| 178 | $settings['mail-maximumSyncRange'] = array( |
||
| 179 | 'type' => 'integer', |
||
| 180 | 'label' => lang('How many days to sync in the past when client does not specify a date-range (default %1)', self::PAST_LIMIT), |
||
| 181 | 'name' => 'mail-maximumSyncRange', |
||
| 182 | 'help' => 'if the client sets no sync range, you may override the setting (preventing client crash that may be caused by too many mails/too much data). If you want to sync way-back into the past: set a large number', |
||
| 183 | 'xmlrpc' => True, |
||
| 184 | 'admin' => False, |
||
| 185 | ); |
||
| 186 | |||
| 187 | /* |
||
| 188 | $sigOptions = array( |
||
| 189 | 'send'=>'yes, always add EGroupware signatures to outgoing mails', |
||
| 190 | 'nosend'=>'no, never add EGroupware signatures to outgoing mails', |
||
| 191 | ); |
||
| 192 | if (!isset($hook_data['setup']) && in_array($hook_data['type'], array('user', 'group'))&&$hook_data['account_id']) |
||
| 193 | { |
||
| 194 | $pID=self::$profileID; |
||
| 195 | if ($GLOBALS['egw_info']['user']['preferences']['activesync']['mail-ActiveSyncProfileID']=='G') |
||
| 196 | { |
||
| 197 | $pID=Mail\Account::get_default_acc_id(); |
||
| 198 | } |
||
| 199 | $acc = Mail\Account::read($pID); |
||
| 200 | error_log(__METHOD__.__LINE__.':'.$pID.'->'.array2string($acc)); |
||
| 201 | $Identities = Mail\Account::identities($pID); |
||
| 202 | foreach($Identities as &$identity) |
||
| 203 | { |
||
| 204 | $Identity = self::identity_name($identity); |
||
| 205 | } |
||
| 206 | error_log(__METHOD__.__LINE__.array2string($Identities)); |
||
| 207 | } |
||
| 208 | $settings['mail-useSignature'] = array( |
||
| 209 | 'type' => 'select', |
||
| 210 | 'label' => 'control if and which available signature is added to outgoing mails', |
||
| 211 | 'name' => 'mail-useSignature', |
||
| 212 | 'help' => 'control the use of signatures', |
||
| 213 | 'values' => $sigOptions, |
||
| 214 | 'xmlrpc' => True, |
||
| 215 | 'default' => 'nosend', |
||
| 216 | 'admin' => False, |
||
| 217 | ); |
||
| 218 | */ |
||
| 219 | return $settings; |
||
| 220 | } |
||
| 221 | |||
| 222 | /** |
||
| 223 | * Verify preferences |
||
| 224 | * |
||
| 225 | * @param array|string $hook_data |
||
| 226 | * @return array with error-messages from all plugins |
||
| 227 | */ |
||
| 228 | function verify_settings($hook_data) |
||
| 261 | } |
||
| 262 | |||
| 263 | /** |
||
| 264 | * Open IMAP connection |
||
| 265 | * |
||
| 266 | * @param int $account integer id of account to use |
||
| 267 | * @todo support different accounts |
||
| 268 | */ |
||
| 269 | private function _connect($account=0) |
||
| 270 | { |
||
| 271 | if (!$account) $account = self::$profileID ? self::$profileID : 0; |
||
| 272 | if ($this->mail && $this->account != $account) $this->_disconnect(); |
||
| 273 | |||
| 274 | $this->_wasteID = false; |
||
| 275 | $this->_sentID = false; |
||
| 276 | |||
| 277 | if (!$this->mail) |
||
| 278 | { |
||
| 279 | $this->account = $account; |
||
| 280 | // todo: tell mail which account to use |
||
| 281 | //error_log(__METHOD__.__LINE__.' create object with ProfileID:'.array2string(self::$profileID)); |
||
| 282 | $this->mail = Mail::getInstance(false,self::$profileID,true,false,true); |
||
| 283 | if (self::$profileID == 0 && isset($this->mail->icServer->ImapServerId) && !empty($this->mail->icServer->ImapServerId)) self::$profileID = $this->mail->icServer->ImapServerId; |
||
| 284 | } |
||
| 285 | else |
||
| 286 | { |
||
| 287 | //error_log(__METHOD__.__LINE__." connect with profileID: ".self::$profileID); |
||
| 288 | if (self::$profileID == 0 && isset($this->mail->icServer->ImapServerId) && !empty($this->mail->icServer->ImapServerId)) self::$profileID = $this->mail->icServer->ImapServerId; |
||
| 289 | } |
||
| 290 | $this->mail->openConnection(self::$profileID,false); |
||
| 291 | |||
| 292 | $this->_wasteID = $this->mail->getTrashFolder(false); |
||
| 293 | //error_log(__METHOD__.__LINE__.' TrashFolder:'.$this->_wasteID); |
||
| 294 | $this->_sentID = $this->mail->getSentFolder(false); |
||
| 295 | $this->mail->getOutboxFolder(true); |
||
| 296 | //error_log(__METHOD__.__LINE__.' SentFolder:'.$this->_sentID); |
||
| 297 | //error_log(__METHOD__.__LINE__.' Connection Status for ProfileID:'.self::$profileID.'->'.$this->mail->icServer->_connected); |
||
| 298 | } |
||
| 299 | |||
| 300 | /** |
||
| 301 | * Close IMAP connection |
||
| 302 | */ |
||
| 303 | private function _disconnect() |
||
| 304 | { |
||
| 305 | if ($this->debugLevel>0) ZLog::Write(LOGLEVEL_DEBUG,__METHOD__); |
||
| 306 | if ($this->mail) $this->mail->closeConnection(); |
||
| 307 | |||
| 308 | unset($this->mail); |
||
| 309 | unset($this->account); |
||
| 310 | unset($this->folders); |
||
| 311 | } |
||
| 312 | |||
| 313 | /** |
||
| 314 | * GetFolderList |
||
| 315 | * |
||
| 316 | * @ToDo loop over available email accounts |
||
| 317 | */ |
||
| 318 | public function GetFolderList() |
||
| 319 | { |
||
| 320 | $folderlist = array(); |
||
| 321 | if ($this->debugLevel>0) ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__); |
||
| 322 | /*foreach($available_accounts as $account)*/ $account = 0; |
||
| 323 | { |
||
| 324 | $this->_connect($account); |
||
| 325 | if (!isset($this->folders)) $this->folders = $this->mail->getFolderObjects(true,false,$_alwaysGetDefaultFolders=true); |
||
| 326 | if ($this->debugLevel>1) ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__.array2string($this->folders)); |
||
| 327 | |||
| 328 | foreach ($this->folders as $folder => $folderObj) { |
||
| 329 | if ($this->debugLevel>1) ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__.' folder='.$folder); |
||
| 330 | $folderlist[] = $f = array( |
||
| 331 | 'id' => $this->createID($account,$folder), |
||
| 332 | 'mod' => $folderObj->shortDisplayName, |
||
| 333 | 'parent' => $this->getParentID($account,$folder), |
||
| 334 | ); |
||
| 335 | if ($this->debugLevel>1) ZLog::Write(LOGLEVEL_DEBUG,__METHOD__."() returning ".array2string($f)); |
||
| 336 | } |
||
| 337 | } |
||
| 338 | if ($this->debugLevel>0) ZLog::Write(LOGLEVEL_DEBUG,__METHOD__."() returning ".array2string($folderlist)); |
||
| 339 | |||
| 340 | return $folderlist; |
||
| 341 | } |
||
| 342 | |||
| 343 | /** |
||
| 344 | * Sends a message which is passed as rfc822. You basically can do two things |
||
| 345 | * 1) Send the message to an SMTP server as-is |
||
| 346 | * 2) Parse the message yourself, and send it some other way |
||
| 347 | * It is up to you whether you want to put the message in the sent items folder. If you |
||
| 348 | * want it in 'sent items', then the next sync on the 'sent items' folder should return |
||
| 349 | * the new message as any other new message in a folder. |
||
| 350 | * |
||
| 351 | * @param array $smartdata = IMAP-SendMail: SyncSendMail ( |
||
| 352 | * (S) clientid => SendMail-30722448149304 |
||
| 353 | * (S) saveinsent => empty |
||
| 354 | * (S) replacemime => null |
||
| 355 | * (S) accountid => null |
||
| 356 | * (S) source => SyncSendMailSource ( |
||
| 357 | * (S) folderid => 101000000000 |
||
| 358 | * (S) itemid => 33776 |
||
| 359 | * (S) longid => null |
||
| 360 | * (S) instanceid => null |
||
| 361 | * unsetVars(Array) size: 0 |
||
| 362 | * flags => false |
||
| 363 | * content => null |
||
| 364 | * ) |
||
| 365 | * (S) mime => Date: Tue, 23 Jun 2015 14:13:23 +0200 |
||
| 366 | *Subject: AW: Blauer himmel |
||
| 367 | *.... |
||
| 368 | * (S) replyflag => true |
||
| 369 | * (S) forwardflag => null |
||
| 370 | * unsetVars(Array) size: 0 |
||
| 371 | * flags => false |
||
| 372 | * content => null |
||
| 373 | *) |
||
| 374 | * |
||
| 375 | * @return boolean true on success, false on error |
||
| 376 | * |
||
| 377 | * @see eg. BackendIMAP::SendMail() |
||
| 378 | * @todo implement either here or in mail backend |
||
| 379 | * (maybe sending here and storing to sent folder in plugin, as sending is supposed to always work in EGroupware) |
||
| 380 | */ |
||
| 381 | public function SendMail($smartdata) |
||
| 856 | } |
||
| 857 | } |
||
| 858 | |||
| 859 | /** |
||
| 860 | * For meeting requests (iCal attachments with method='request') we call calendar plugin with iCal to get SyncMeetingRequest object, |
||
| 861 | * and do NOT return the attachment itself! |
||
| 862 | * |
||
| 863 | * @param string $folderid |
||
| 864 | * @param string $id |
||
| 865 | * @param ContentParameters $contentparameters parameters of the requested message (truncation, mimesupport etc) |
||
| 866 | * object with attributes foldertype, truncation, rtftruncation, conflict, filtertype, bodypref, deletesasmoves, filtertype, contentclass, mimesupport, conversationmode |
||
| 867 | * bodypref object with attributes: ]truncationsize, allornone, preview |
||
| 868 | * @return $messageobject|boolean false on error |
||
| 869 | */ |
||
| 870 | public function GetMessage($folderid, $id, $contentparameters) |
||
| 1192 | } |
||
| 1193 | |||
| 1194 | /** |
||
| 1195 | * Process response to meeting request |
||
| 1196 | * |
||
| 1197 | * mail plugin only extracts the iCal attachment and let's calendar plugin deal with adding it |
||
| 1198 | * |
||
| 1199 | * @see BackendDiff::MeetingResponse() |
||
| 1200 | * @param string $folderid folder of meeting request mail |
||
| 1201 | * @param int|string $requestid uid of mail with meeting request |
||
| 1202 | * @param int $response 1=accepted, 2=tentative, 3=decline |
||
| 1203 | * @return int|boolean id of calendar item, false on error |
||
| 1204 | */ |
||
| 1205 | function MeetingResponse($folderid, $requestid, $response) |
||
| 1206 | { |
||
| 1207 | if (!class_exists('calendar_zpush')) |
||
| 1208 | { |
||
| 1209 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__."(...) no EGroupware calendar installed!"); |
||
| 1210 | return null; |
||
| 1211 | } |
||
| 1212 | if (!($stat = $this->StatMessage($folderid, $requestid))) |
||
| 1213 | { |
||
| 1214 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__."($requestid, '$folderid', $response) returning FALSE (can NOT stat message)"); |
||
| 1215 | return false; |
||
| 1216 | } |
||
| 1217 | $ret = false; |
||
| 1218 | foreach($this->mail->getMessageAttachments($requestid, $_partID='', $_structure=null, $fetchEmbeddedImages=true, $fetchTextCalendar=true) as $key => $attach) |
||
| 1219 | { |
||
| 1220 | if (strtolower($attach['mimeType']) == 'text/calendar' && strtolower($attach['method']) == 'request' && |
||
| 1221 | ($attachment = $this->mail->getAttachment($requestid, $attach['partID'],0,false))) |
||
| 1222 | { |
||
| 1223 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__."($requestid, '$folderid', $response) iCal found, calling now backend->MeetingResponse('$attachment[attachment]')"); |
||
| 1224 | |||
| 1225 | // calling backend again with iCal attachment, to let calendar add the event |
||
| 1226 | $ret = $this->backend->MeetingResponse($attachment['attachment'], |
||
| 1227 | $this->backend->createID('calendar',$GLOBALS['egw_info']['user']['account_id']), |
||
| 1228 | $response); |
||
| 1229 | |||
| 1230 | // delete message after meeting-response is processed successful by calendar |
||
| 1231 | if ($ret) $this->DeleteMessage($folderid, $requestid, null); |
||
| 1232 | break; |
||
| 1233 | } |
||
| 1234 | } |
||
| 1235 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__."($requestid, '$folderid', $response) returning ".array2string($ret)); |
||
| 1236 | return $ret; |
||
| 1237 | } |
||
| 1238 | |||
| 1239 | /** |
||
| 1240 | * GetAttachmentData |
||
| 1241 | * Should return attachment data for the specified attachment. The passed attachment identifier is |
||
| 1242 | * the exact string that is returned in the 'AttName' property of an SyncAttachment. So, you should |
||
| 1243 | * encode any information you need to find the attachment in that 'attname' property. |
||
| 1244 | * |
||
| 1245 | * @param string $fid - id |
||
| 1246 | * @param string $attname - should contain (folder)id |
||
| 1247 | * @return SyncItemOperationsAttachment-object |
||
| 1248 | */ |
||
| 1249 | function GetAttachmentData($fid,$attname) { |
||
| 1250 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.": $fid (attname: '$attname')"); |
||
| 1251 | return $this->_GetAttachmentData($fid,$attname); |
||
| 1252 | } |
||
| 1253 | |||
| 1254 | /** |
||
| 1255 | * ItemOperationsGetAttachmentData |
||
| 1256 | * Should return attachment data for the specified attachment. The passed attachment identifier is |
||
| 1257 | * the exact string that is returned in the 'AttName' property of an SyncAttachment. So, you should |
||
| 1258 | * encode any information you need to find the attachment in that 'attname' property. |
||
| 1259 | * |
||
| 1260 | * @param string $fid - id |
||
| 1261 | * @param string $attname - should contain (folder)id |
||
| 1262 | * @return SyncItemOperationsAttachment-object |
||
| 1263 | */ |
||
| 1264 | function ItemOperationsGetAttachmentData($fid,$attname) { |
||
| 1265 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.": $fid (attname: '$attname')"); |
||
| 1266 | return $this->_GetAttachmentData($fid,$attname); |
||
| 1267 | } |
||
| 1268 | |||
| 1269 | /** |
||
| 1270 | * _GetAttachmentData implements |
||
| 1271 | * -ItemOperationsGetAttachmentData |
||
| 1272 | * -GetAttachmentData |
||
| 1273 | * |
||
| 1274 | * @param string $fid - id |
||
| 1275 | * @param string $attname - should contain (folder)id |
||
| 1276 | * @return SyncItemOperationsAttachment-object |
||
| 1277 | */ |
||
| 1278 | private function _GetAttachmentData($fid,$attname) |
||
| 1279 | { |
||
| 1280 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.": $fid (attname: '$attname')".function_backtrace()); |
||
| 1281 | //error_log(__METHOD__.__LINE__." Fid: $fid (attname: '$attname')"); |
||
| 1282 | list($folderid, $id, $part) = explode(":", $attname); |
||
| 1283 | |||
| 1284 | $this->splitID($folderid, $account, $folder); |
||
| 1285 | |||
| 1286 | if (!isset($this->mail)) $this->mail = Mail::getInstance(false,self::$profileID,true,false,true); |
||
| 1287 | |||
| 1288 | $this->mail->reopen($folder); |
||
| 1289 | $attachment = $this->mail->getAttachment($id,$part,0,false,true,$folder); |
||
| 1290 | $SIOattachment = new SyncItemOperationsAttachment(); |
||
| 1291 | fseek($attachment['attachment'], 0, SEEK_SET); // z-push requires stream seeked to start |
||
| 1292 | $SIOattachment->data = $attachment['attachment']; |
||
| 1293 | //ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.": $fid (attname: '$attname') Data:".$attachment['attachment']); |
||
| 1294 | if (isset($attachment['type']) ) |
||
| 1295 | $SIOattachment->contenttype = $attachment['type']; |
||
| 1296 | |||
| 1297 | unset($attachment); |
||
| 1298 | |||
| 1299 | return $SIOattachment; |
||
| 1300 | } |
||
| 1301 | |||
| 1302 | /** |
||
| 1303 | * StatMessage should return message stats, analogous to the folder stats (StatFolder). Entries are: |
||
| 1304 | * |
||
| 1305 | * 'id' => Server unique identifier for the message. Again, try to keep this short (under 20 chars) |
||
| 1306 | * 'flags' => simply '0' for unread, '1' for read |
||
| 1307 | * 'mod' => modification signature. As soon as this signature changes, the item is assumed to be completely |
||
| 1308 | * changed, and will be sent to the PDA as a whole. Normally you can use something like the modification |
||
| 1309 | * time for this field, which will change as soon as the contents have changed. |
||
| 1310 | * |
||
| 1311 | * @param string $folderid |
||
| 1312 | * @param int $id id (uid) of message |
||
| 1313 | * @return array |
||
| 1314 | */ |
||
| 1315 | public function StatMessage($folderid, $id) |
||
| 1316 | { |
||
| 1317 | $messages = $this->fetchMessages($folderid, NULL, $id); |
||
| 1318 | //ZLog::Write(LOGLEVEL_DEBUG, __METHOD__."('$folderid','$id') returning ".array2string($messages[$id])); |
||
| 1319 | return $messages[$id]; |
||
| 1320 | } |
||
| 1321 | |||
| 1322 | /** |
||
| 1323 | * Called when a message has been changed on the mobile. |
||
| 1324 | * Added support for FollowUp flag |
||
| 1325 | * |
||
| 1326 | * @param string $folderid id of the folder |
||
| 1327 | * @param string $id id of the message |
||
| 1328 | * @param SyncXXX $message the SyncObject containing a message |
||
| 1329 | * @param ContentParameters $contentParameters |
||
| 1330 | * |
||
| 1331 | * @access public |
||
| 1332 | * @return array same return value as StatMessage() |
||
| 1333 | * @throws StatusException could throw specific SYNC_STATUS_* exceptions |
||
| 1334 | */ |
||
| 1335 | function ChangeMessage($folderid, $id, $message, $contentParameters) |
||
| 1336 | { |
||
| 1337 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__." $folderid, $id,".array2string($message).",".array2string($contentParameters)); |
||
| 1338 | //unset($folderid, $id, $message, $contentParameters); |
||
| 1339 | $account = $folder = null; |
||
| 1340 | $this->splitID($folderid, $account, $folder); |
||
| 1341 | if (isset($message->flag)) { |
||
| 1342 | if (isset($message->flag->flagstatus) && $message->flag->flagstatus == 2) { |
||
| 1343 | $rv = $this->mail->flagMessages((($message->flag->flagstatus == 2) ? "flagged" : "unflagged"), $id,$folder); |
||
| 1344 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__." -> set ".array2string($id).' in Folder '.$folder." as " . (($message->flag->flagstatus == 2) ? "flagged" : "unflagged") . "-->". $rv); |
||
| 1345 | } else { |
||
| 1346 | $rv = $this->mail->flagMessages("unflagged", $id,$folder); |
||
| 1347 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__." -> set ".array2string($id).' in Folder '.$folder." as " . "unflagged" . "-->". $rv); |
||
| 1348 | } |
||
| 1349 | } |
||
| 1350 | return $this->StatMessage($folderid, $id); |
||
| 1351 | } |
||
| 1352 | |||
| 1353 | /** |
||
| 1354 | * This function is called when the user moves an item on the PDA. You should do whatever is needed |
||
| 1355 | * to move the message on disk. After this call, StatMessage() and GetMessageList() should show the items |
||
| 1356 | * to have a new parent. This means that it will disappear from GetMessageList() will not return the item |
||
| 1357 | * at all on the source folder, and the destination folder will show the new message |
||
| 1358 | * |
||
| 1359 | * @param string $folderid id of the source folder |
||
| 1360 | * @param string $id id of the message |
||
| 1361 | * @param string $newfolderid id of the destination folder |
||
| 1362 | * @param ContentParameters $contentParameters |
||
| 1363 | * |
||
| 1364 | * @return boolean status of the operation |
||
| 1365 | * @throws StatusException could throw specific SYNC_MOVEITEMSSTATUS_* exceptions |
||
| 1366 | */ |
||
| 1367 | public function MoveMessage($folderid, $id, $newfolderid, $contentParameters) |
||
| 1368 | { |
||
| 1369 | unset($contentParameters); // not used, but required by function signature |
||
| 1370 | ZLog::Write(LOGLEVEL_DEBUG, "IMAP-MoveMessage: (sfid: '$folderid' id: '$id' dfid: '$newfolderid' )"); |
||
| 1371 | $account = $srcFolder = $destFolder = null; |
||
| 1372 | $this->splitID($folderid, $account, $srcFolder); |
||
| 1373 | $this->splitID($newfolderid, $account, $destFolder); |
||
| 1374 | ZLog::Write(LOGLEVEL_DEBUG, "IMAP-MoveMessage: (SourceFolder: '$srcFolder' id: '$id' DestFolder: '$destFolder' )"); |
||
| 1375 | if (!isset($this->mail)) $this->mail = Mail::getInstance(false,self::$profileID,true,false,true); |
||
| 1376 | $this->mail->reopen($destFolder); |
||
| 1377 | $status = $this->mail->getFolderStatus($destFolder); |
||
| 1378 | $uidNext = $status['uidnext']; |
||
| 1379 | $this->mail->reopen($srcFolder); |
||
| 1380 | |||
| 1381 | // move message |
||
| 1382 | $rv = $this->mail->moveMessages($destFolder,(array)$id,true,$srcFolder,true); |
||
| 1383 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__.": New Status of $destFolder :".array2string($status).", ReturnValOf moveMessage".array2string($rv)); // this may be true, so try using the nextUID value by examine |
||
| 1384 | // return the new id "as string" |
||
| 1385 | return ($rv===true ? $uidNext : $rv[$id]) . ""; |
||
| 1386 | } |
||
| 1387 | |||
| 1388 | /** |
||
| 1389 | * Get all messages of a folder with optional cutoffdate |
||
| 1390 | * |
||
| 1391 | * @param int $cutoffdate =null timestamp with cutoffdate, default 12 weeks |
||
| 1392 | */ |
||
| 1393 | public function GetMessageList($folderid, $cutoffdate=NULL) |
||
| 1394 | { |
||
| 1395 | if ($cutoffdate > 0) |
||
| 1396 | { |
||
| 1397 | ZLog::Write(LOGLEVEL_DEBUG, __METHOD__.' for Folder:'.$folderid.' SINCE:'.$cutoffdate.'/'.date("d-M-Y", $cutoffdate)); |
||
| 1398 | } |
||
| 1399 | else |
||
| 1400 | { |
||
| 1401 | $maximumSyncRangeInDays = self::PAST_LIMIT; // corresponds to our default value |
||
| 1402 | if (isset($GLOBALS['egw_info']['user']['preferences']['activesync']['mail-maximumSyncRange'])) |
||
| 1403 | { |
||
| 1404 | $maximumSyncRangeInDays = $GLOBALS['egw_info']['user']['preferences']['activesync']['mail-maximumSyncRange']; |
||
| 1405 | } |
||
| 1406 | $cutoffdate = (is_numeric($maximumSyncRangeInDays) ? Api\DateTime::to('now','ts')-(3600*24*$maximumSyncRangeInDays):null); |
||
| 1407 | if (is_numeric($maximumSyncRangeInDays)) ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.' Client set no truncationdate. Using '.$maximumSyncRangeInDays.' days.'.date("d-M-Y", $cutoffdate)); |
||
| 1408 | } |
||
| 1409 | try { |
||
| 1410 | return $this->fetchMessages($folderid, $cutoffdate); |
||
| 1411 | } catch (Exception $e) |
||
| 1412 | { |
||
| 1413 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__.' failed for '.$e->getMessage().($e->details?$e->details:'')); |
||
| 1414 | return array(); |
||
| 1415 | } |
||
| 1416 | } |
||
| 1417 | |||
| 1418 | /** |
||
| 1419 | * Fetch headers for one or all mail of a folder using optional cutoffdate |
||
| 1420 | * |
||
| 1421 | * Headers of last fetchMessage call of complate folder are cached in static $headers, |
||
| 1422 | * to allow to use them without fetching them again. |
||
| 1423 | * Next call clears cache |
||
| 1424 | * |
||
| 1425 | * @param int $folderid |
||
| 1426 | * @param int $cutoffdate timestamp with cutoffdate |
||
| 1427 | * @param string $_id =null uid of single message to fetch |
||
| 1428 | * @param boolean $return_all_headers =false true: additinal contain all headers eg. "subject" |
||
| 1429 | * @return array uid => array StatMessage($folderid, $_id) |
||
| 1430 | */ |
||
| 1431 | private function fetchMessages($folderid, $cutoffdate=NULL, $_id=NULL, $return_all_headers=false) |
||
| 1432 | { |
||
| 1433 | static $headers = array(); |
||
| 1434 | |||
| 1435 | if ($this->debugLevel>1) $gstarttime = microtime (true); |
||
| 1436 | //ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__); |
||
| 1437 | $rv_messages = array(); |
||
| 1438 | // if the message is still available within the class, we use it instead of fetching it again |
||
| 1439 | if ($_id && isset($headers[$_id]) && is_array($headers[$_id])) |
||
| 1440 | { |
||
| 1441 | //ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__." the message ".$_id[0]." is still available within the class, we use it instead of fetching it again"); |
||
| 1442 | $rv_messages = array('header'=>array($headers[$_id])); |
||
| 1443 | } |
||
| 1444 | else |
||
| 1445 | { |
||
| 1446 | $headers = array(); // clear cache to not use too much memory |
||
| 1447 | |||
| 1448 | if ($this->debugLevel>1) $starttime = microtime (true); |
||
| 1449 | $this->_connect($this->account); |
||
| 1450 | if ($this->debugLevel>1) |
||
| 1451 | { |
||
| 1452 | $endtime = microtime(true) - $starttime; |
||
| 1453 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__. " connect took : ".$endtime.' for account:'.$this->account); |
||
| 1454 | } |
||
| 1455 | $messagelist = $_filter = array(); |
||
| 1456 | // if not connected, any further action must fail |
||
| 1457 | if (!empty($cutoffdate)) $_filter = array('status'=>array('UNDELETED'),'range'=>"SINCE",'date'=> date("d-M-Y", $cutoffdate)); |
||
| 1458 | if ($this->debugLevel>1) $starttime = microtime (true); |
||
| 1459 | $account = $_folderName = $id = null; |
||
| 1460 | $this->splitID($folderid,$account,$_folderName,$id); |
||
| 1461 | if ($this->debugLevel>1) |
||
| 1462 | { |
||
| 1463 | $endtime = microtime(true) - $starttime; |
||
| 1464 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__. " splitID took : ".$endtime.' for FolderID:'.$folderid); |
||
| 1465 | } |
||
| 1466 | if ($this->debugLevel>1) ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.' for Folder:'.$_folderName.' Filter:'.array2string($_filter).' Ids:'.array2string($_id).'/'.$id); |
||
| 1467 | if ($this->debugLevel>1) $starttime = microtime (true); |
||
| 1468 | $_numberOfMessages = (empty($cutoffdate)?250:99999); |
||
| 1469 | $rv_messages = $this->mail->getHeaders($_folderName, $_startMessage=1, $_numberOfMessages, $_sort=0, $_reverse=false, $_filter, $_id); |
||
| 1470 | if ($this->debugLevel>1) |
||
| 1471 | { |
||
| 1472 | $endtime = microtime(true) - $starttime; |
||
| 1473 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__. " getHeaders call took : ".$endtime.' for FolderID:'.$_folderName); |
||
| 1474 | } |
||
| 1475 | } |
||
| 1476 | if ($_id == NULL && $this->debugLevel>1) ZLog::Write(LOGLEVEL_DEBUG,__METHOD__." found :". count($rv_messages['header'])); |
||
| 1477 | //ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__.' Result:'.array2string($rv_messages)); |
||
| 1478 | $messagelist = array(); |
||
| 1479 | if (!isset($rv_messages['header'])||empty($rv_messages['header'])) return $messagelist; |
||
| 1480 | //if ($_returnModHash) $messageFolderHash = array(); |
||
| 1481 | foreach ((array)$rv_messages['header'] as $k => $vars) |
||
| 1482 | { |
||
| 1483 | if ($this->debugLevel>3) ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__.' ID to process:'.$vars['uid'].' Subject:'.$vars['subject']); |
||
| 1484 | $headers[$vars['uid']] = $vars; |
||
| 1485 | if ($this->debugLevel>3) ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__.' MailID:'.$k.'->'.array2string($vars)); |
||
| 1486 | if (!empty($vars['deleted'])) continue; // cut of deleted messages |
||
| 1487 | if ($cutoffdate && $vars['date'] < $cutoffdate) continue; // message is out of range for cutoffdate, ignore it |
||
| 1488 | if ($this->debugLevel>0) ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__.' ID to report:'.$vars['uid'].' Subject:'.$vars['subject']); |
||
| 1489 | $mess = $return_all_headers ? $vars : array(); |
||
| 1490 | $mess["mod"] = self::doFlagsMod($vars).$vars['date']; |
||
| 1491 | $mess["id"] = $vars['uid']; |
||
| 1492 | // 'seen' aka 'read' is the only flag we want to know about |
||
| 1493 | $mess["flags"] = 0; |
||
| 1494 | // outlook supports additional flags, set them to 0 |
||
| 1495 | if($vars["seen"]) $mess["flags"] = 1; |
||
| 1496 | if ($this->debugLevel>3) ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__.array2string($mess)); |
||
| 1497 | $messagelist[$vars['uid']] = $mess; |
||
| 1498 | unset($mess); |
||
| 1499 | } |
||
| 1500 | if ($this->debugLevel>1) |
||
| 1501 | { |
||
| 1502 | $endtime = microtime(true) - $gstarttime; |
||
| 1503 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__. " total time used : ".$endtime.' for Folder:'.$_folderName.' Filter:'.array2string($_filter).' Ids:'.array2string($_id).'/'.$id); |
||
| 1504 | } |
||
| 1505 | return $messagelist; |
||
| 1506 | } |
||
| 1507 | |||
| 1508 | /** |
||
| 1509 | * Prepare headeinfo on a message to return some standardized string to tell which flags are set for a message |
||
| 1510 | * |
||
| 1511 | * AS currently only supports flagged, answered/replied and forwarded flags. |
||
| 1512 | * Seen/read is in under flags key of stat! |
||
| 1513 | * |
||
| 1514 | * @param array $headerFlags - array to process, a full return array from getHeaders |
||
| 1515 | * @link https://sourceforge.net/p/zimbrabackend/code/HEAD/tree/zimbra-backend/branches/z-push-2/zimbra.php#l11652 |
||
| 1516 | * @return string string of a representation of supported flags |
||
| 1517 | */ |
||
| 1518 | static function doFlagsMod($headerFlags) |
||
| 1519 | { |
||
| 1520 | $flags = 'nnn'; |
||
| 1521 | if ($headerFlags['flagged']) $flags[0] = 'f'; |
||
| 1522 | if ($headerFlags['answered']) $flags[1] = 'a'; |
||
| 1523 | if ($headerFlags['forwarded']) $flags[2] = 'f'; |
||
| 1524 | //ZLog::Write(LOGLEVEL_DEBUG, __METHOD__.'('.array2string($headerFlags).') returning '.array2string($flags)); |
||
| 1525 | return $flags; |
||
| 1526 | } |
||
| 1527 | |||
| 1528 | /** |
||
| 1529 | * Search mailbox for a given pattern |
||
| 1530 | * |
||
| 1531 | * @param object $_searchquery holds information specifying the query with GetDataArray it holds |
||
| 1532 | * [searchname] => MAILBOX |
||
| 1533 | * [searchfolderid] => 101000000000 |
||
| 1534 | * [searchfreetext] => somesearchtexgt |
||
| 1535 | * [searchdatereceivedgreater] => 1 |
||
| 1536 | * [searchvaluegreater] => 2015-07-06T22:00:00.000Z |
||
| 1537 | * [searchdatereceivedless] => 1 |
||
| 1538 | * [searchvalueless] => 2015-07-14T15:11:00.000Z |
||
| 1539 | * [searchrebuildresults] => 1 |
||
| 1540 | * [searchrange] => 0-99 |
||
| 1541 | * [bodypref] => Array([1] => BodyPreference Object([unsetdata:protected] => Array([truncationsize] => [allornone] => [preview] => )[SO_internalid:StateObject:private] => [data:protected] => |
||
| 1542 | * Array([truncationsize] => 2147483647)[changed:protected] => 1)) |
||
| 1543 | * [mimesupport] => 2) |
||
| 1544 | * @return array(["range"] = $_searchquery->GetSearchRange(), ['searchtotal'] = count of results, |
||
| 1545 | * array("class" => "Email", |
||
| 1546 | * "longid" => folderid.':'.uid', |
||
| 1547 | * "folderid" => folderid, |
||
| 1548 | * ), .... |
||
| 1549 | * ) |
||
| 1550 | */ |
||
| 1551 | public function getSearchResultsMailbox($_searchquery) |
||
| 1552 | { |
||
| 1553 | //$this->debugLevel=1; |
||
| 1554 | $searchquery=$_searchquery->GetDataArray(); |
||
| 1555 | if (!is_array($searchquery)) return array(); |
||
| 1556 | if ($this->debugLevel>0) ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__.array2string($searchquery)); |
||
| 1557 | |||
| 1558 | if (isset($searchquery['searchrebuildresults'])) { |
||
| 1559 | $rebuildresults = $searchquery['searchrebuildresults']; |
||
| 1560 | } else { |
||
| 1561 | $rebuildresults = false; |
||
| 1562 | } |
||
| 1563 | if ($this->debugLevel>0) ZLog::Write(LOGLEVEL_DEBUG, 'RebuildResults ['.$rebuildresults.']' ); |
||
| 1564 | |||
| 1565 | if (isset($searchquery['deeptraversal'])) { |
||
| 1566 | $deeptraversal = $searchquery['deeptraversal']; |
||
| 1567 | } else { |
||
| 1568 | $deeptraversal = false; |
||
| 1569 | } |
||
| 1570 | if ($this->debugLevel>0) ZLog::Write(LOGLEVEL_DEBUG, 'DeepTraversal ['.$deeptraversal.']' ); |
||
| 1571 | |||
| 1572 | if (isset($searchquery['searchrange'])) { |
||
| 1573 | $range = explode("-",$_searchquery->GetSearchRange()); |
||
| 1574 | $start =$range[0] + 1; |
||
| 1575 | $limit = $range[1] - $range[0] + 1; |
||
| 1576 | } else { |
||
| 1577 | $range = false; |
||
| 1578 | } |
||
| 1579 | if ($this->debugLevel>0) ZLog::Write(LOGLEVEL_DEBUG, 'Range ['.print_r($range, true).']' ); |
||
| 1580 | |||
| 1581 | //foreach($searchquery['query'] as $k => $value) { |
||
| 1582 | // $query = $value; |
||
| 1583 | //} |
||
| 1584 | if (isset($searchquery['searchfolderid'])) |
||
| 1585 | { |
||
| 1586 | $folderid = $searchquery['searchfolderid']; |
||
| 1587 | } |
||
| 1588 | /* |
||
| 1589 | // other types may be possible - we support quicksearch first (freeText in subject and from (or TO in Sent Folder)) |
||
| 1590 | if (is_null(Mail::$supportsORinQuery) || !isset(Mail::$supportsORinQuery[self::$profileID])) |
||
| 1591 | { |
||
| 1592 | Mail::$supportsORinQuery = Api\Cache::getCache(Api\Cache::INSTANCE,'email','supportsORinQuery'.trim($GLOBALS['egw_info']['user']['account_id']),$callback=null,$callback_params=array(),$expiration=60*60*10); |
||
| 1593 | if (!isset(Mail::$supportsORinQuery[self::$profileID])) Mail::$supportsORinQuery[self::$profileID]=true; |
||
| 1594 | } |
||
| 1595 | */ |
||
| 1596 | if (isset($searchquery['searchfreetext'])) |
||
| 1597 | { |
||
| 1598 | $searchText = $searchquery['searchfreetext']; |
||
| 1599 | } |
||
| 1600 | if (!$folderid) |
||
| 1601 | { |
||
| 1602 | $_folderName = ($this->mail->sessionData['mailbox']?$this->mail->sessionData['mailbox']:'INBOX'); |
||
| 1603 | $folderid = $this->createID($account=0,$_folderName); |
||
| 1604 | } |
||
| 1605 | $rv = $this->splitID($folderid,$account,$_folderName,$id); |
||
| 1606 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__.' ProfileID:'.self::$profileID.' FolderID:'.$folderid.' Foldername:'.$_folderName); |
||
| 1607 | $this->_connect($account); |
||
| 1608 | // this should not be needed ??? |
||
| 1609 | Mail::$supportsORinQuery[self::$profileID]=true; // trigger quicksearch (if possible) |
||
| 1610 | $_filter = array('type'=> (Mail::$supportsORinQuery[self::$profileID]?'quick':'subject'), |
||
| 1611 | 'string'=> $searchText, |
||
| 1612 | 'status'=>'any' |
||
| 1613 | ); |
||
| 1614 | |||
| 1615 | if (isset($searchquery['searchdatereceivedgreater']) || isset($searchquery['searchdatereceivedless'])) |
||
| 1616 | { |
||
| 1617 | /* |
||
| 1618 | * We respect only the DATEPART of the RANGE specified |
||
| 1619 | * [searchdatereceivedgreater] => 1 |
||
| 1620 | * [searchvaluegreater] => 2015-07-06T22:00:00.000Z , SINCE |
||
| 1621 | * [searchdatereceivedless] => 1 |
||
| 1622 | * [searchvalueless] => 2015-07-14T15:11:00.000Z , BEFORE |
||
| 1623 | */ |
||
| 1624 | $_filter['range'] = "BETWEEN"; |
||
| 1625 | list($sincedate,$crap) = explode('T',$searchquery['searchvaluegreater']); |
||
| 1626 | list($beforedate,$crap) = explode('T',$searchquery['searchvalueless']); |
||
| 1627 | $_filter['before'] = date("d-M-Y", Api\DateTime::to($beforedate,'ts')); |
||
| 1628 | $_filter['since'] = date("d-M-Y", Api\DateTime::to($sincedate,'ts')); |
||
| 1629 | } |
||
| 1630 | //$_filter[] = array('type'=>"SINCE",'string'=> date("d-M-Y", $cutoffdate)); |
||
| 1631 | if ($this->debugLevel>1) ZLog::Write(LOGLEVEL_DEBUG, __METHOD__.' for Folder:'.$_folderName.' Filter:'.array2string($_filter)); |
||
| 1632 | $rv_messages = $this->mail->getHeaders($_folderName, $_startMessage=($range?$start:1), $_numberOfMessages=($limit?$limit:9999999), $_sort=0, $_reverse=false, $_filter, $_id=NULL); |
||
| 1633 | //ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__.array2string($rv_messages)); |
||
| 1634 | $list=array(); |
||
| 1635 | |||
| 1636 | $cnt = count($rv_messages['header']); |
||
| 1637 | //$list['status'] = 1; |
||
| 1638 | $list['searchtotal'] = $cnt; |
||
| 1639 | $list["range"] = $_searchquery->GetSearchRange(); |
||
| 1640 | foreach((array)$rv_messages['header'] as $i => $vars) |
||
| 1641 | { |
||
| 1642 | $list[] = array( |
||
| 1643 | "class" => "Email", |
||
| 1644 | "longid" => $folderid.':'.$vars['uid'], |
||
| 1645 | "folderid" => $folderid, |
||
| 1646 | ); |
||
| 1647 | } |
||
| 1648 | //error_log(__METHOD__.__LINE__.array2string($list)); |
||
| 1649 | //ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__.array2string($list)); |
||
| 1650 | return $list; |
||
| 1651 | } |
||
| 1652 | |||
| 1653 | /** |
||
| 1654 | * Get ID of parent Folder or '0' for folders in root |
||
| 1655 | * |
||
| 1656 | * @param int $account |
||
| 1657 | * @param string $folder |
||
| 1658 | * @return string |
||
| 1659 | */ |
||
| 1660 | private function getParentID($account,$folder) |
||
| 1661 | { |
||
| 1662 | $this->_connect($account); |
||
| 1663 | if (!isset($this->folders)) $this->folders = $this->mail->getFolderObjects(true,false); |
||
| 1664 | |||
| 1665 | $mailFolder = $this->folders[$folder]; |
||
| 1666 | if (!isset($mailFolder)) return false; |
||
| 1667 | $delimiter = (isset($mailFolder->delimiter)?$mailFolder->delimiter:$this->mail->getHierarchyDelimiter()); |
||
| 1668 | $parent = explode($delimiter,$folder); |
||
| 1669 | array_pop($parent); |
||
| 1670 | $parent = implode($delimiter,$parent); |
||
| 1671 | |||
| 1672 | $id = $parent && $this->folders[$parent] ? $this->createID($account, $parent) : '0'; |
||
| 1673 | if ($this->debugLevel>1) ZLog::Write(LOGLEVEL_DEBUG,__METHOD__."('$folder') --> parent=$parent --> $id"); |
||
| 1674 | return $id; |
||
| 1675 | } |
||
| 1676 | |||
| 1677 | /** |
||
| 1678 | * Get Information about a folder |
||
| 1679 | * |
||
| 1680 | * @param string $id |
||
| 1681 | * @return SyncFolder|boolean false on error |
||
| 1682 | */ |
||
| 1683 | public function GetFolder($id) |
||
| 1684 | { |
||
| 1685 | static $last_id = null; |
||
| 1686 | static $folderObj = null; |
||
| 1687 | if (isset($last_id) && $last_id === $id) return $folderObj; |
||
| 1688 | |||
| 1689 | try { |
||
| 1690 | $account = $folder = null; |
||
| 1691 | $this->splitID($id, $account, $folder); |
||
| 1692 | } |
||
| 1693 | catch(Exception $e) { |
||
| 1694 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__.' failed for '.$e->getMessage()); |
||
| 1695 | return $folderObj=false; |
||
| 1696 | } |
||
| 1697 | $this->_connect($account); |
||
| 1698 | if (!isset($this->folders)) $this->folders = $this->mail->getFolderObjects(true,false); |
||
| 1699 | |||
| 1700 | $mailFolder = $this->folders[$folder]; |
||
| 1701 | if (!isset($mailFolder)) return $folderObj=false; |
||
| 1702 | |||
| 1703 | $folderObj = new SyncFolder(); |
||
| 1704 | $folderObj->serverid = $id; |
||
| 1705 | $folderObj->parentid = $this->getParentID($account,$folder); |
||
| 1706 | $folderObj->displayname = $mailFolder->shortDisplayName; |
||
| 1707 | if ($this->debugLevel>1) ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__." ID: $id, Account:$account, Folder:$folder"); |
||
| 1708 | // get folder-type |
||
| 1709 | foreach($this->folders as $inbox => $mailFolder) break; |
||
| 1710 | if ($folder == $inbox) |
||
| 1711 | { |
||
| 1712 | $folderObj->type = SYNC_FOLDER_TYPE_INBOX; |
||
| 1713 | } |
||
| 1714 | elseif($this->mail->isDraftFolder($folder, false, true)) |
||
| 1715 | { |
||
| 1716 | //ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.' isDraft'); |
||
| 1717 | $folderObj->type = SYNC_FOLDER_TYPE_DRAFTS; |
||
| 1718 | $folderObj->parentid = 0; // required by devices |
||
| 1719 | } |
||
| 1720 | elseif($this->mail->isTrashFolder($folder, false, true)) |
||
| 1721 | { |
||
| 1722 | $folderObj->type = SYNC_FOLDER_TYPE_WASTEBASKET; |
||
| 1723 | $this->_wasteID = $folder; |
||
| 1724 | //error_log(__METHOD__.__LINE__.' TrashFolder:'.$this->_wasteID); |
||
| 1725 | $folderObj->parentid = 0; // required by devices |
||
| 1726 | } |
||
| 1727 | elseif($this->mail->isSentFolder($folder, false, true)) |
||
| 1728 | { |
||
| 1729 | $folderObj->type = SYNC_FOLDER_TYPE_SENTMAIL; |
||
| 1730 | $folderObj->parentid = 0; // required by devices |
||
| 1731 | $this->_sentID = $folder; |
||
| 1732 | //error_log(__METHOD__.__LINE__.' SentFolder:'.$this->_sentID); |
||
| 1733 | } |
||
| 1734 | elseif($this->mail->isOutbox($folder, false, true)) |
||
| 1735 | { |
||
| 1736 | //ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.' isOutbox'); |
||
| 1737 | $folderObj->type = SYNC_FOLDER_TYPE_OUTBOX; |
||
| 1738 | $folderObj->parentid = 0; // required by devices |
||
| 1739 | } |
||
| 1740 | else |
||
| 1741 | { |
||
| 1742 | //ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.' isOther Folder'.$folder); |
||
| 1743 | $folderObj->type = SYNC_FOLDER_TYPE_USER_MAIL; |
||
| 1744 | } |
||
| 1745 | |||
| 1746 | if ($this->debugLevel>1) ZLog::Write(LOGLEVEL_DEBUG,__METHOD__."($id) --> $folder --> type=$folderObj->type, parentID=$folderObj->parentid, displayname=$folderObj->displayname"); |
||
| 1747 | return $folderObj; |
||
| 1748 | } |
||
| 1749 | |||
| 1750 | /** |
||
| 1751 | * Return folder stats. This means you must return an associative array with the |
||
| 1752 | * following properties: |
||
| 1753 | * |
||
| 1754 | * "id" => The server ID that will be used to identify the folder. It must be unique, and not too long |
||
| 1755 | * How long exactly is not known, but try keeping it under 20 chars or so. It must be a string. |
||
| 1756 | * "parent" => The server ID of the parent of the folder. Same restrictions as 'id' apply. |
||
| 1757 | * "mod" => This is the modification signature. It is any arbitrary string which is constant as long as |
||
| 1758 | * the folder has not changed. In practice this means that 'mod' can be equal to the folder name |
||
| 1759 | * as this is the only thing that ever changes in folders. (the type is normally constant) |
||
| 1760 | * |
||
| 1761 | * @return array with values for keys 'id', 'mod' and 'parent' |
||
| 1762 | */ |
||
| 1763 | public function StatFolder($id) |
||
| 1764 | { |
||
| 1765 | $folder = $this->GetFolder($id); |
||
| 1766 | |||
| 1767 | $stat = array( |
||
| 1768 | 'id' => $id, |
||
| 1769 | 'mod' => $folder->displayname, |
||
| 1770 | 'parent' => $folder->parentid, |
||
| 1771 | ); |
||
| 1772 | |||
| 1773 | return $stat; |
||
| 1774 | } |
||
| 1775 | |||
| 1776 | |||
| 1777 | /** |
||
| 1778 | * Return a changes array |
||
| 1779 | * |
||
| 1780 | * if changes occurr default diff engine computes the actual changes |
||
| 1781 | * |
||
| 1782 | * @param string $folderid |
||
| 1783 | * @param string &$syncstate on call old syncstate, on return new syncstate |
||
| 1784 | * @return array|boolean false if $folderid not found, array() if no changes or array(array("type" => "fakeChange")) |
||
| 1785 | */ |
||
| 1786 | function AlterPingChanges($folderid, &$syncstate) |
||
| 1787 | { |
||
| 1788 | $account = $folder = null; |
||
| 1789 | $this->splitID($folderid, $account, $folder); |
||
| 1790 | if (is_numeric($account)) $type = 'mail'; |
||
| 1791 | |||
| 1792 | if ($type != 'mail') return false; |
||
| 1793 | |||
| 1794 | if (!isset($this->mail)) $this->mail = Mail::getInstance(false,self::$profileID,true,false,true); |
||
| 1795 | if (!$this->mail->folderIsSelectable($folder)) |
||
| 1796 | { |
||
| 1797 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.": could not select folder $folder returning fake state"); |
||
| 1798 | $syncstate = "M:".'0'."-R:".'0'."-U:".'0'."-NUID:".'0'."-UIDV:".'0'; |
||
| 1799 | return array(); |
||
| 1800 | } |
||
| 1801 | |||
| 1802 | $this->mail->reopen($folder); |
||
| 1803 | |||
| 1804 | if (!($status = $this->mail->getFolderStatus($folder,$ignoreStatusCache=true))) |
||
| 1805 | { |
||
| 1806 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.": could not stat folder $folder "); |
||
| 1807 | return false; |
||
| 1808 | } |
||
| 1809 | $syncstate = "M:". $status['messages'] ."-R:". $status['recent'] ."-U:". $status['unseen']."-NUID:".$status['uidnext']."-UIDV:".$status['uidvalidity']; |
||
| 1810 | |||
| 1811 | if ($this->debugLevel) ZLog::Write(LOGLEVEL_DEBUG,__METHOD__."($folderid, ...) $folder ($account) returning ".array2string($syncstate)); |
||
| 1812 | return array(); |
||
| 1813 | } |
||
| 1814 | |||
| 1815 | /** |
||
| 1816 | * Should return a wastebasket folder if there is one. This is used when deleting |
||
| 1817 | * items; if this function returns a valid folder ID, then all deletes are handled |
||
| 1818 | * as moves and are sent to your backend as a move. If it returns FALSE, then deletes |
||
| 1819 | * are always handled as real deletes and will be sent to your importer as a DELETE |
||
| 1820 | */ |
||
| 1821 | function GetWasteBasket() |
||
| 1822 | { |
||
| 1823 | $this->_connect($this->account); |
||
| 1824 | $id = $this->createID($account=0, $this->_wasteID); |
||
| 1825 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__."() account=$this->account returned $id for folder $this->_wasteID"); |
||
| 1826 | return $id; |
||
| 1827 | } |
||
| 1828 | |||
| 1829 | /** |
||
| 1830 | * Called when the user has requested to delete (really delete) a message. Usually |
||
| 1831 | * this means just unlinking the file its in or somesuch. After this call has succeeded, a call to |
||
| 1832 | * GetMessageList() should no longer list the message. If it does, the message will be re-sent to the mobile |
||
| 1833 | * as it will be seen as a 'new' item. This means that if this method is not implemented, it's possible to |
||
| 1834 | * delete messages on the PDA, but as soon as a sync is done, the item will be resynched to the mobile |
||
| 1835 | * |
||
| 1836 | * @param string $folderid id of the folder |
||
| 1837 | * @param string $id id of the message |
||
| 1838 | * @param ContentParameters $contentParameters |
||
| 1839 | * |
||
| 1840 | * @access public |
||
| 1841 | * @return boolean status of the operation |
||
| 1842 | * @throws StatusException could throw specific SYNC_STATUS_* exceptions |
||
| 1843 | */ |
||
| 1844 | public function DeleteMessage($folderid, $id, $contentParameters) |
||
| 1845 | { |
||
| 1846 | unset($contentParameters); // not used, but required by function signature |
||
| 1847 | ZLog::Write(LOGLEVEL_DEBUG, "IMAP-DeleteMessage: (fid: '$folderid' id: '$id' )"); |
||
| 1848 | /* |
||
| 1849 | $this->imap_reopenFolder($folderid); |
||
| 1850 | $s1 = @imap_delete ($this->_mbox, $id, FT_UID); |
||
| 1851 | $s11 = @imap_setflag_full($this->_mbox, $id, "\\Deleted", FT_UID); |
||
| 1852 | $s2 = @imap_expunge($this->_mbox); |
||
| 1853 | */ |
||
| 1854 | // we may have to split folderid |
||
| 1855 | $account = $folder = null; |
||
| 1856 | $this->splitID($folderid, $account, $folder); |
||
| 1857 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__.' '.$folderid.'->'.$folder); |
||
| 1858 | $_messageUID = (array)$id; |
||
| 1859 | |||
| 1860 | $this->_connect($this->account); |
||
| 1861 | $this->mail->reopen($folder); |
||
| 1862 | try |
||
| 1863 | { |
||
| 1864 | $rv = $this->mail->deleteMessages($_messageUID, $folder); |
||
| 1865 | } |
||
| 1866 | catch (Api\Exception $e) |
||
| 1867 | { |
||
| 1868 | $error = $e->getMessage(); |
||
| 1869 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.__LINE__." $_messageUID, $folder ->".$error); |
||
| 1870 | // if the server thinks the message does not exist report deletion as success |
||
| 1871 | if (stripos($error,'[NONEXISTENT]')!==false) return true; |
||
| 1872 | return false; |
||
| 1873 | } |
||
| 1874 | |||
| 1875 | // this may be a bit rude, it may be sufficient that GetMessageList does not list messages flagged as deleted |
||
| 1876 | if ($this->mail->mailPreferences['deleteOptions'] == 'mark_as_deleted') |
||
| 1877 | { |
||
| 1878 | // ignore mark as deleted -> Expunge! |
||
| 1879 | //$this->mail->icServer->expunge(); // do not expunge as GetMessageList does not List messages flagged as deleted |
||
| 1880 | } |
||
| 1881 | ZLog::Write(LOGLEVEL_DEBUG, "IMAP-DeleteMessage: $rv"); |
||
| 1882 | |||
| 1883 | return $rv; |
||
| 1884 | } |
||
| 1885 | |||
| 1886 | /** |
||
| 1887 | * Changes the 'read' flag of a message on disk. The $flags |
||
| 1888 | * parameter can only be '1' (read) or '0' (unread). After a call to |
||
| 1889 | * SetReadFlag(), GetMessageList() should return the message with the |
||
| 1890 | * new 'flags' but should not modify the 'mod' parameter. If you do |
||
| 1891 | * change 'mod', simply setting the message to 'read' on the mobile will trigger |
||
| 1892 | * a full resync of the item from the server. |
||
| 1893 | * |
||
| 1894 | * @param string $folderid id of the folder |
||
| 1895 | * @param string $id id of the message |
||
| 1896 | * @param int $flags read flag of the message |
||
| 1897 | * @param ContentParameters $contentParameters |
||
| 1898 | * |
||
| 1899 | * @access public |
||
| 1900 | * @return boolean status of the operation |
||
| 1901 | * @throws StatusException could throw specific SYNC_STATUS_* exceptions |
||
| 1902 | */ |
||
| 1903 | public function SetReadFlag($folderid, $id, $flags, $contentParameters) |
||
| 1904 | { |
||
| 1905 | unset($contentParameters); // not used, but required by function signature |
||
| 1906 | // ZLog::Write(LOGLEVEL_DEBUG, "IMAP-SetReadFlag: (fid: '$folderid' id: '$id' flags: '$flags' )"); |
||
| 1907 | $account = $folder = null; |
||
| 1908 | $this->splitID($folderid, $account, $folder); |
||
| 1909 | |||
| 1910 | $_messageUID = (array)$id; |
||
| 1911 | $this->_connect($this->account); |
||
| 1912 | $rv = $this->mail->flagMessages((($flags) ? "read" : "unread"), $_messageUID,$folder); |
||
| 1913 | ZLog::Write(LOGLEVEL_DEBUG, "IMAP-SetReadFlag -> set ".array2string($_messageUID).' in Folder '.$folder." as " . (($flags) ? "read" : "unread") . "-->". $rv); |
||
| 1914 | |||
| 1915 | return $rv; |
||
| 1916 | } |
||
| 1917 | |||
| 1918 | /** |
||
| 1919 | * Creates or modifies a folder |
||
| 1920 | * |
||
| 1921 | * @param string $id of the parent folder |
||
| 1922 | * @param string $oldid => if empty -> new folder created, else folder is to be renamed |
||
| 1923 | * @param string $displayname => new folder name (to be created, or to be renamed to) |
||
| 1924 | * @param string $type folder type, ignored in IMAP |
||
| 1925 | * |
||
| 1926 | * @throws StatusException could throw specific SYNC_FSSTATUS_* exceptions |
||
| 1927 | * @return array|boolean stat array or false on error |
||
| 1928 | */ |
||
| 1929 | public function ChangeFolder($id, $oldid, $displayname, $type) |
||
| 1930 | { |
||
| 1931 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__."('$id', '$oldid', '$displayname', $type)"); |
||
| 1932 | $account = $parent_id = null; |
||
| 1933 | $this->splitID($id, $account, $parentFolder, $app); |
||
| 1934 | |||
| 1935 | $parent_id = $this->folder2hash($account, $parentFolder); |
||
| 1936 | $old_hash = $oldFolder = null; |
||
| 1937 | |||
| 1938 | if (empty($oldid)) |
||
| 1939 | { |
||
| 1940 | $action = 'create'; |
||
| 1941 | } |
||
| 1942 | else |
||
| 1943 | { |
||
| 1944 | $action = 'rename'; |
||
| 1945 | $this->splitID($oldid, $account, $oldFolder, $app); |
||
| 1946 | $old_hash = $this->folder2hash($account, $oldFolder); |
||
| 1947 | } |
||
| 1948 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__.":{$action}Folder('$id'=>($parentFolder ($parent_id)), '$oldid'".($oldid?"=>($oldFolder ($old_hash))":'').", '$displayname', $type)"); |
||
| 1949 | $this->_connect($this->account); |
||
| 1950 | try |
||
| 1951 | { |
||
| 1952 | if ($action=='rename') |
||
| 1953 | { |
||
| 1954 | $newFolderName = $this->mail->renameFolder($oldFolder, $parentFolder, $displayname); |
||
| 1955 | } |
||
| 1956 | elseif ($action=='create') |
||
| 1957 | { |
||
| 1958 | $error=null; |
||
| 1959 | $newFolderName = $this->mail->createFolder($parentFolder, $displayname, $error); |
||
| 1960 | } |
||
| 1961 | } |
||
| 1962 | catch (\Exception $e) |
||
| 1963 | { |
||
| 1964 | //throw new Exception(__METHOD__." $action failed for $oldFolder ($action: $displayname) with error:".$e->getMessage()); |
||
| 1965 | return false; |
||
| 1966 | } |
||
| 1967 | $newHash = $this->rename_folder_hash($account, $old_hash, $newFolderName); |
||
| 1968 | $newID = $this->createID($account, $newHash); |
||
| 1969 | $this->folders = $this->mail->getFolderObjects(true,false,$_alwaysGetDefaultFolders=true,false); |
||
| 1970 | ZLog::Write(LOGLEVEL_DEBUG,":{$action}Folder('$id'=>($parentFolder), '$oldid'".($oldid?"=>($oldFolder)":'').", '$displayname' => $newFolderName (ID:$newID))"); |
||
| 1971 | return $this->StatFolder($newID); |
||
| 1972 | } |
||
| 1973 | |||
| 1974 | /** |
||
| 1975 | * Deletes (really delete) a Folder |
||
| 1976 | * |
||
| 1977 | * @param string $id of the folder to delete |
||
| 1978 | * @param string $parentid (=false) of the folder to delete, may be false/not set |
||
| 1979 | * |
||
| 1980 | * @throws StatusException could throw specific SYNC_FSSTATUS_* exceptions |
||
| 1981 | * @return boolean true or false on error |
||
| 1982 | */ |
||
| 1983 | public function DeleteFolder($id, $parentid=false) |
||
| 1984 | { |
||
| 1985 | $account = $parent_id = $app = null; |
||
| 1986 | $this->splitID($id, $account, $folder, $app); |
||
| 1987 | $old_hash = $this->folder2hash($account, $folder); |
||
| 1988 | if ($parentid) $this->splitID($parentid, $account, $parentfolder, $app); |
||
| 1989 | ZLog::Write(LOGLEVEL_DEBUG,__METHOD__."( '$id (-> $folder)','$parentid ".($parentid?'(->'.$parentfolder.')':'')."') called!"); |
||
| 1990 | $ret = $this->mail->deleteFolder($folder); |
||
| 1991 | if ($ret) $newHash = $this->rename_folder_hash($account, $old_hash, "##Dele#edFolder#$folder##"); |
||
| 1992 | $this->folders = $this->mail->getFolderObjects(true,false,$_alwaysGetDefaultFolders=true,false); |
||
| 1993 | return $ret; |
||
| 1994 | } |
||
| 1995 | |||
| 1996 | /** |
||
| 1997 | * modify olflags (outlook style) flag of a message |
||
| 1998 | * |
||
| 1999 | * @param $folderid |
||
| 2000 | * @param $id |
||
| 2001 | * @param $flags |
||
| 2002 | * |
||
| 2003 | * |
||
| 2004 | * @DESC The $flags parameter must contains the poommailflag Object |
||
| 2005 | */ |
||
| 2006 | function ChangeMessageFlag($folderid, $id, $flags) |
||
| 2007 | { |
||
| 2008 | $_messageUID = (array)$id; |
||
| 2009 | $this->_connect($this->account); |
||
| 2010 | $account = $folder = null; |
||
| 2011 | $this->splitID($folderid, $account, $folder); |
||
| 2012 | $rv = $this->mail->flagMessages((($flags->flagstatus == 2) ? "flagged" : "unflagged"), $_messageUID,$folder); |
||
| 2013 | ZLog::Write(LOGLEVEL_DEBUG, "IMAP-SetFlaggedFlag -> set ".array2string($_messageUID).' in Folder '.$folder." as " . (($flags->flagstatus == 2) ? "flagged" : "unflagged") . "-->". $rv); |
||
| 2014 | |||
| 2015 | return $rv; |
||
| 2016 | } |
||
| 2017 | |||
| 2018 | /** |
||
| 2019 | * Create a max. 32 hex letter ID, current 20 chars are used |
||
| 2020 | * |
||
| 2021 | * @param int $account mail account id |
||
| 2022 | * @param string $folder |
||
| 2023 | * @param int $id =0 |
||
| 2024 | * @return string |
||
| 2025 | * @throws Api\Exception\WrongParameter |
||
| 2026 | */ |
||
| 2027 | private function createID($account,$folder,$id=0) |
||
| 2040 | } |
||
| 2041 | |||
| 2042 | /** |
||
| 2043 | * Split an ID string into $app, $account $folder and $appid |
||
| 2044 | * |
||
| 2045 | * @param string $str |
||
| 2046 | * @param int &$account mail account id |
||
| 2047 | * @param string &$folder |
||
| 2048 | * @param int &$appid=null (for mail=mail is to be expected) |
||
| 2049 | * @throws Api\Exception\WrongParameter |
||
| 2050 | */ |
||
| 2051 | private function splitID($str,&$account,&$folder,&$appid=null) |
||
| 2052 | { |
||
| 2053 | $this->backend->splitID($str, $account, $folder, $appid); |
||
| 2054 | |||
| 2055 | // convert numeric folder-id back to folder name |
||
| 2056 | $folder = $this->hash2folder($account,$f=$folder); |
||
| 2057 | |||
| 2058 | if ($this->debugLevel>1) ZLog::Write(LOGLEVEL_DEBUG,__METHOD__."('$str','$account','$folder',$appid)"); |
||
| 2059 | } |
||
| 2060 | |||
| 2061 | /** |
||
| 2062 | * Methods to convert (hierarchical) folder names to nummerical id's |
||
| 2063 | * |
||
| 2064 | * This is currently done by storing a serialized array in the device specific |
||
| 2065 | * state directory. |
||
| 2066 | */ |
||
| 2067 | |||
| 2068 | /** |
||
| 2069 | * Convert folder string to nummeric hash |
||
| 2070 | * |
||
| 2071 | * @param int $account |
||
| 2072 | * @param string $folder |
||
| 2073 | * @return int |
||
| 2074 | */ |
||
| 2075 | private function folder2hash($account,$folder) |
||
| 2089 | } |
||
| 2090 | |||
| 2091 | /** |
||
| 2092 | * Convert numeric hash to folder string |
||
| 2093 | * |
||
| 2094 | * @param int $account |
||
| 2095 | * @param int $index |
||
| 2096 | * @return string NULL if not used so far |
||
| 2097 | */ |
||
| 2098 | private function hash2folder($account,$index) |
||
| 2099 | { |
||
| 2100 | if(!isset($this->folderHashes)) $this->readFolderHashes(); |
||
| 2101 | |||
| 2102 | return isset($this->folderHashes[$account]) ? $this->folderHashes[$account][$index] : null; |
||
| 2103 | } |
||
| 2104 | |||
| 2105 | /** |
||
| 2106 | * Rename or create a folder in hash table |
||
| 2107 | * |
||
| 2108 | * @param int $account |
||
| 2109 | * @param int $index or null to create |
||
| 2110 | * @param string $new_name |
||
| 2111 | * @return int $index or new hash if $index is not found |
||
| 2112 | */ |
||
| 2113 | private function rename_folder_hash($account, $index, $new_name) |
||
| 2114 | { |
||
| 2115 | if ((string)$index === '' || !$this->hash2folder($account, $index)) |
||
| 2116 | { |
||
| 2117 | return $this->folder2hash($account, $new_name); |
||
| 2118 | } |
||
| 2119 | $this->folderHashes[$account][$index] = $new_name; |
||
| 2120 | $this->storeFolderHashes(); |
||
| 2121 | return $index; |
||
| 2122 | } |
||
| 2123 | |||
| 2124 | private $folderHashes; |
||
| 2125 | |||
| 2126 | /** |
||
| 2127 | * Statemaschine instance used to store folders |
||
| 2128 | * |
||
| 2129 | * @var activesync_statemaschine |
||
| 2130 | */ |
||
| 2131 | private $fh_state_maschine; |
||
| 2132 | |||
| 2133 | /** |
||
| 2134 | * state_type (and _key) used to store folder hashes |
||
| 2135 | */ |
||
| 2136 | const FOLDER_STATE_TYPE = 'folder_hashes'; |
||
| 2137 | |||
| 2138 | /** |
||
| 2139 | * Read hashfile from state dir |
||
| 2140 | */ |
||
| 2141 | private function readFolderHashes() |
||
| 2142 | { |
||
| 2143 | if (!isset($this->fh_state_maschine)) |
||
| 2144 | { |
||
| 2145 | $this->fh_state_maschine = new activesync_statemachine($this->backend); |
||
| 2146 | } |
||
| 2147 | try { |
||
| 2148 | $this->folderHashes = $this->fh_state_maschine->getState(Request::GetDeviceID(), |
||
| 2149 | self::FOLDER_STATE_TYPE, self::FOLDER_STATE_TYPE, 0); |
||
| 2150 | } |
||
| 2151 | catch (Exception $e) { |
||
| 2152 | unset($e); |
||
| 2153 | if ((file_exists($file = $this->hashFile()) || file_exists($file = $this->hashFile(true))) && |
||
| 2154 | ($hashes = file_get_contents($file))) |
||
| 2155 | { |
||
| 2156 | $this->folderHashes = json_decode($hashes,true); |
||
| 2157 | // fallback in case hashes have been serialized instead of being json-encoded |
||
| 2158 | if (json_last_error()!=JSON_ERROR_NONE) |
||
| 2159 | { |
||
| 2160 | //error_log(__METHOD__.__LINE__." error decoding with json"); |
||
| 2161 | $this->folderHashes = unserialize($hashes); |
||
| 2162 | } |
||
| 2163 | // store folder-hashes to state |
||
| 2164 | $this->storeFolderHashes(); |
||
| 2165 | } |
||
| 2166 | else |
||
| 2167 | { |
||
| 2168 | $this->folderHashes = array(); |
||
| 2169 | } |
||
| 2170 | } |
||
| 2171 | } |
||
| 2172 | |||
| 2173 | /** |
||
| 2174 | * Store hashfile via state-maschine |
||
| 2175 | * |
||
| 2176 | * return int|boolean false on error |
||
| 2177 | */ |
||
| 2178 | private function storeFolderHashes() |
||
| 2193 | } |
||
| 2194 | |||
| 2195 | /** |
||
| 2196 | * Get name of hashfile in state dir |
||
| 2197 | * |
||
| 2198 | * New z-push 2 directory is in activesync_statemachine::getDeviceDirectory. |
||
| 2199 | * On request this function also returns, but never creates (!), old z-push 1 directory. |
||
| 2200 | * |
||
| 2201 | * @param boolean $old =false true: return old / pre-15 hash-file |
||
| 2202 | * @throws Api\Exception\AssertionFailed |
||
| 2203 | */ |
||
| 2204 | private function hashFile($old=false) |
||
| 2205 | { |
||
| 2217 | } |
||
| 2218 | } |
||
| 2219 |
Let?s assume that you have a directory layout like this:
. |-- OtherDir | |-- Bar.php | `-- Foo.php `-- SomeDir `-- Foo.phpand let?s assume the following content of
Bar.php:If both files
OtherDir/Foo.phpandSomeDir/Foo.phpare loaded in the same runtime, you will see a PHP error such as the following:PHP Fatal error: Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.phpHowever, as
OtherDir/Foo.phpdoes not necessarily have to be loaded and the error is only triggered if it is loaded beforeOtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias: