/** * Initializes the importer * * @param string $state * @param int $flags * * @access public * @return boolean * @throws StatusException */ public function Config($state, $flags = 0) { $this->flags = $flags; // this should never happen if ($this->importer === false) { throw new StatusException("ImportChangesICS->Config(): Error, importer not available", SYNC_FSSTATUS_CODEUNKNOWN, null, LOGLEVEL_ERROR); } // Put the state information in a stream that can be used by ICS $stream = mapi_stream_create(); if (strlen($state) == 0) { $state = hex2bin("0000000000000000"); } ZLog::Write(LOGLEVEL_DEBUG, sprintf("ImportChangesICS->Config(): initializing importer with state: 0x%s", bin2hex($state))); mapi_stream_write($stream, $state); $this->statestream = $stream; if ($this->folderid !== false) { // possible conflicting messages will be cached here $this->memChanges = new ChangesMemoryWrapper(); $stat = mapi_importcontentschanges_config($this->importer, $stream, $flags); } else { $stat = mapi_importhierarchychanges_config($this->importer, $stream, $flags); } if (!$stat) { throw new StatusException(sprintf("ImportChangesICS->Config(): Error, mapi_import_*_changes_config() failed: 0x%X", mapi_last_hresult()), SYNC_FSSTATUS_CODEUNKNOWN, null, LOGLEVEL_WARN); } return $stat; }
function Config(&$importer, $mclass, $restrict, $syncstate, $flags, $truncation) { // Because we're using ICS, we need to wrap the given importer to make it suitable to pass // to ICS. We do this in two steps: first, wrap the importer with our own PHP importer class // which removes all MAPI dependency, and then wrap that class with a C++ wrapper so we can // pass it to ICS $exporterflags = 0; if ($this->_folderid) { // PHP wrapper $phpimportproxy = new PHPContentsImportProxy($this->_session, $this->_store, $this->_folderid, $importer, $truncation); // ICS c++ wrapper $mapiimporter = mapi_wrap_importcontentschanges($phpimportproxy); $exporterflags |= SYNC_NORMAL | SYNC_READ_STATE; // Initial sync, we don't want deleted items. If the initial sync is chunked // we check the change ID of the syncstate (0 at initial sync) // On subsequent syncs, we do want to receive delete events. if (strlen($syncstate) == 0 || bin2hex(substr($syncstate, 4, 4)) == "00000000") { debugLog("synching inital data"); $exporterflags |= SYNC_NO_SOFT_DELETIONS | SYNC_NO_DELETIONS; } } else { $phpimportproxy = new PHPHierarchyImportProxy($this->_store, $importer); $mapiimporter = mapi_wrap_importhierarchychanges($phpimportproxy); } if ($flags & BACKEND_DISCARD_DATA) { $exporterflags |= SYNC_CATCHUP; } // Put the state information in a stream that can be used by ICS $stream = mapi_stream_create(); if (strlen($syncstate) > 0) { mapi_stream_write($stream, $syncstate); } else { mapi_stream_write($stream, hex2bin("0000000000000000")); } $this->statestream = $stream; // only set a restriction if the device has set a filtertype, except for Zarafa versions before 7 - see Mantis #368 switch ($mclass) { case "Email": $restriction = $restrict || !checkMapiExtVersion('7') ? $this->_getEmailRestriction($this->_getCutOffDate($restrict)) : false; break; case "Calendar": $restriction = $restrict || !checkMapiExtVersion('7') ? $this->_getCalendarRestriction($this->_getCutOffDate($restrict)) : false; break; default: case "Contacts": case "Tasks": $restriction = false; break; } if ($this->_folderid) { $includeprops = false; } else { $includeprops = array(PR_SOURCE_KEY, PR_DISPLAY_NAME); } if ($this->exporter === false) { debugLog("ExportChangesICS->Config failed. Exporter not available."); return false; } $ret = mapi_exportchanges_config($this->exporter, $stream, $exporterflags, $mapiimporter, $restriction, $includeprops, false, 1); if ($ret) { $changes = mapi_exportchanges_getchangecount($this->exporter); if ($changes || !($flags & BACKEND_DISCARD_DATA)) { debugLog("Exporter configured successfully. " . $changes . " changes ready to sync."); } } else { debugLog("Exporter could not be configured: result: " . sprintf("%X", mapi_last_hresult())); } return $ret; }
function buildEMLAttachment($attach) { $msgembedded = mapi_attach_openobj($attach); $msgprops = mapi_getprops($msgembedded, array(PR_MESSAGE_CLASS, PR_CLIENT_SUBMIT_TIME, PR_DISPLAY_TO, PR_SUBJECT, PR_SENT_REPRESENTING_NAME, PR_SENT_REPRESENTING_EMAIL_ADDRESS)); $msgembeddedrcpttable = mapi_message_getrecipienttable($msgembedded); $msgto = $msgprops[PR_DISPLAY_TO]; if ($msgembeddedrcpttable) { $msgembeddedrecipients = mapi_table_queryrows($msgembeddedrcpttable, array(PR_ADDRTYPE, PR_ENTRYID, PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_SMTP_ADDRESS, PR_RECIPIENT_TYPE, PR_RECIPIENT_FLAGS, PR_PROPOSEDNEWTIME, PR_PROPOSENEWTIME_START, PR_PROPOSENEWTIME_END, PR_RECIPIENT_TRACKSTATUS), 0, 99999999); foreach ($msgembeddedrecipients as $rcpt) { if ($rcpt[PR_DISPLAY_NAME] == $msgprops[PR_DISPLAY_TO]) { $msgto = $rcpt[PR_DISPLAY_NAME]; if (isset($rcpt[PR_EMAIL_ADDRESS]) && $rcpt[PR_EMAIL_ADDRESS] != $msgprops[PR_DISPLAY_TO]) { $msgto .= " <" . $rcpt[PR_EMAIL_ADDRESS] . ">"; } break; } } } $msgsubject = $msgprops[PR_SUBJECT]; $msgfrom = $msgprops[PR_SENT_REPRESENTING_NAME]; if (isset($msgprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS]) && $msgprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS] != $msgprops[PR_SENT_REPRESENTING_NAME]) { $msgfrom .= " <" . $msgprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS] . ">"; } $msgtime = $msgprops[PR_CLIENT_SUBMIT_TIME]; $msgembeddedbody = eml_ReadMessage($msgembedded); $msgembeddedattachtable = mapi_message_getattachmenttable($msgembedded); $msgembeddedattachtablerows = mapi_table_queryallrows($msgembeddedattachtable, array(PR_ATTACH_NUM, PR_ATTACH_METHOD)); if ($msgembeddedattachtablerows) { $boundary = '=_zpush_static'; $headercontenttype = "multipart/mixed"; $msgembeddedbody['body'] = "Unfortunately your mobile is not able to handle MIME Messages\n" . "--" . $boundary . "\n" . "Content-Type: " . $msgembeddedbody['content'] . "; charset=utf-8\n" . "Content-Transfer-Encoding: quoted-printable\n\n" . $msgembeddedbody['body'] . "\n"; foreach ($msgembeddedattachtablerows as $msgembeddedattachtablerow) { $msgembeddedattach = mapi_message_openattach($msgembedded, $msgembeddedattachtablerow[PR_ATTACH_NUM]); if (!$msgembeddedattach) { debugLog("Unable to open attachment number {$attachnum}"); } else { $msgembeddedattachprops = mapi_getprops($msgembeddedattach, array(PR_ATTACH_MIME_TAG, PR_ATTACH_LONG_FILENAME, PR_ATTACH_FILENAME, PR_DISPLAY_NAME)); if (isset($msgembeddedattachprops[PR_ATTACH_LONG_FILENAME])) { $attachfilename = w2u($msgembeddedattachprops[PR_ATTACH_LONG_FILENAME]); } else { if (isset($msgembeddedattachprops[PR_ATTACH_FILENAME])) { $attachfilename = w2u($msgembeddedattachprops[PR_ATTACH_FILENAME]); } else { if (isset($msgembeddedattachprops[PR_DISPLAY_NAME])) { $attachfilename = w2u($msgembeddedattachprops[PR_DISPLAY_NAME]); } else { $attachfilename = w2u("untitled"); } } } if ($msgembeddedattachtablerow[PR_ATTACH_METHOD] == ATTACH_EMBEDDED_MSG) { $attachfilename .= w2u(".eml"); } $msgembeddedbody['body'] .= "--" . $boundary . "\n" . "Content-Type: " . $msgembeddedattachprops[PR_ATTACH_MIME_TAG] . ";\n" . " name=\"" . $attachfilename . "\"\n" . "Content-Transfer-Encoding: base64\n" . "Content-Disposition: attachment;\n" . " filename=\"" . $attachfilename . "\"\n\n"; $msgembeddedattachstream = mapi_openpropertytostream($msgembeddedattach, PR_ATTACH_DATA_BIN); $msgembeddedattachment = ""; while (1) { $msgembeddedattachdata = mapi_stream_read($msgembeddedattachstream, 4096); if (byte_strlen($msgembeddedattachdata) == 0) { break; } $msgembeddedattachment .= $msgembeddedattachdata; } $msgembeddedbody['body'] .= chunk_split(base64_encode($msgembeddedattachment)) . "\n"; unset($msgembeddedattachment); } } $msgembeddedbody['body'] .= "--" . $boundary . "--\n"; } else { $headercontenttype = $msgembeddedbody['content'] . "; charset=utf-8"; $boundary = ''; } $msgembeddedheader = "Subject: " . $msgsubject . "\n" . "From: " . $msgfrom . "\n" . "To: " . $msgto . "\n" . "Date: " . gmstrftime("%a, %d %b %Y %T +0000", $msgprops[PR_CLIENT_SUBMIT_TIME]) . "\n" . "MIME-Version: 1.0\n" . "Content-Type: " . $headercontenttype . ";\n" . ($boundary ? " boundary=\"" . $boundary . "\"\n" : "") . "\n"; $stream = mapi_stream_create(); mapi_stream_setsize($stream, byte_strlen($msgembeddedheader . $msgembeddedbody['body'])); mapi_stream_write($stream, $msgembeddedheader . $msgembeddedbody['body']); mapi_stream_seek($stream, 0, STREAM_SEEK_SET); return $stream; }
/** * Configures the exporter * * @param string $state * @param int $flags * * @access public * @return boolean * @throws StatusException */ public function Config($state, $flags = 0) { $this->exporterflags = 0; $this->flags = $flags; // this should never happen if ($this->exporter === false || is_array($state)) { throw new StatusException("ExportChangesICS->Config(): Error, exporter not available", SYNC_FSSTATUS_CODEUNKNOWN, null, LOGLEVEL_ERROR); } // change exporterflags if we are doing a ContentExport if ($this->folderid) { $this->exporterflags |= SYNC_NORMAL | SYNC_READ_STATE; // Initial sync, we don't want deleted items. If the initial sync is chunked // we check the change ID of the syncstate (0 at initial sync) // On subsequent syncs, we do want to receive delete events. if (strlen($state) == 0 || bin2hex(substr($state, 4, 4)) == "00000000") { if (!($this->flags & BACKEND_DISCARD_DATA)) { ZLog::Write(LOGLEVEL_DEBUG, "ExportChangesICS->Config(): synching inital data"); } $this->exporterflags |= SYNC_NO_SOFT_DELETIONS | SYNC_NO_DELETIONS; } } if ($this->flags & BACKEND_DISCARD_DATA) { $this->exporterflags |= SYNC_CATCHUP; } // Put the state information in a stream that can be used by ICS $stream = mapi_stream_create(); if (strlen($state) == 0) { $state = hex2bin("0000000000000000"); } if (!($this->flags & BACKEND_DISCARD_DATA)) { ZLog::Write(LOGLEVEL_DEBUG, sprintf("ExportChangesICS->Config() initialized with state: 0x%s", bin2hex($state))); } mapi_stream_write($stream, $state); $this->statestream = $stream; }
function Config(&$importer, $mclass, $restrict, $syncstate, $flags, $truncation, $bodypreference, $optionbodypreference, $mimesupport = 0) { // Because we're using ICS, we need to wrap the given importer to make it suitable to pass // to ICS. We do this in two steps: first, wrap the importer with our own PHP importer class // which removes all MAPI dependency, and then wrap that class with a C++ wrapper so we can // pass it to ICS $exporterflags = 0; // debugLog("Importer: ".$importer. " mclass: ".$mclass." restrict: ".$restrict." syncstate: ".bin2hex($syncstate)." flags: ".$flags." truncation: ".$truncation. " bodypreference: ".$bodypreference); if ($this->_folderid) { // PHP wrapper // CHANGED dw2412 Support Protocol Version 12 (added bodypreference) // debugLog("Config: mclass=".$mclass); $phpimportproxy = new PHPContentsImportProxy($this->_session, $this->_store, $this->_folderid, $importer, $truncation, $bodypreference, $optionbodypreference, $mimesupport, $mclass); // ICS c++ wrapper $mapiimporter = mapi_wrap_importcontentschanges($phpimportproxy); $exporterflags |= SYNC_NORMAL | SYNC_READ_STATE; // Initial sync, we don't want deleted items. If the initial sync is chunked // we check the change ID of the syncstate (0 at initial sync) // On subsequent syncs, we do want to receive delete events. if (strlen($syncstate) == 0 || bin2hex(substr($syncstate, 4, 4)) == "00000000") { // debugLog("syncing inital data"); $exporterflags |= SYNC_NO_SOFT_DELETIONS | SYNC_NO_DELETIONS; } $msgstore_props = mapi_getprops($this->_store, array(PR_IPM_OUTBOX_ENTRYID)); $folder_entryid = mapi_msgstore_entryidfromsourcekey($this->_store, $this->_folderid); if ($folder_entryid == $msgstore_props[PR_IPM_OUTBOX_ENTRYID]) { if (strlen($syncstate) != 0 && bin2hex(substr($syncstate, 4, 4)) != "00000000") { debugLog("ExportICS->Config: Ignoring deletions in Outbox."); $exporterflags |= SYNC_NO_SOFT_DELETIONS | SYNC_NO_DELETIONS; $this->_smsoutboxinitialsync = false; } else { $this->_smsoutboxinitialsync = true; } $this->_smsoutboxsync = true; } else { $this->_smsoutboxsync = false; } } else { $phpimportproxy = new PHPHierarchyImportProxy($this->_store, $importer); $mapiimporter = mapi_wrap_importhierarchychanges($phpimportproxy); } if ($flags & BACKEND_DISCARD_DATA) { $exporterflags |= SYNC_CATCHUP; } // Put the state information in a stream that can be used by ICS $stream = mapi_stream_create(); if (strlen($syncstate) > 0) { mapi_stream_write($stream, $syncstate); } else { mapi_stream_write($stream, hex2bin("0000000000000000")); } $this->statestream = $stream; // debugLog("ExportChangesICS->Config: ".($this->_folderid ? "Have Folder" : "No Folder"). " " . $mclass . " state: ". bin2hex($syncstate) . " restriction " . $restrict); switch ($mclass) { case "SMS": // $restriction = $this->_getSMSRestriction($this->_getCutOffDate($restrict)); // break; // $restriction = $this->_getSMSRestriction($this->_getCutOffDate($restrict)); // break; case "Email": $restriction = $this->_getEmailRestriction($this->_getCutOffDate($restrict)); break; case "Calendar": $restriction = $this->_getCalendarRestriction($this->_getCutOffDate($restrict)); break; default: case "Contacts": case "Tasks": $restriction = false; break; } if ($this->_folderid) { $includeprops = false; } else { $includeprops = array(PR_SOURCE_KEY, PR_DISPLAY_NAME); } if ($this->exporter === false) { debugLog("ExportChangesICS->Config failed. Exporter not available."); return false; } // debugLog("HEREA1"); // debugLog("Exporter: ". $this->exporter." Stream: ". $stream ." Exporterflags: ".$exporterflags." Mapiimporter: ".$mapiimporter." Restriction: ".print_r($restriction,true)." Includeprops: ". print_r($includeprops,true)); $ret = mapi_exportchanges_config($this->exporter, $stream, $exporterflags, $mapiimporter, $restriction, $includeprops, false, 1); // debugLog("HEREA2"); if ($ret) { $changes = mapi_exportchanges_getchangecount($this->exporter); if ($changes || !($flags & BACKEND_DISCARD_DATA)) { debugLog("Exporter configured successfully. " . $changes . " changes ready to sync."); } } else { debugLog("Exporter could not be configured: result: " . sprintf("%X", mapi_last_hresult())); } return $ret; }
function Config(&$importer, $mclass, $restrict, $syncstate, $flags, $truncation) { // Because we're using ICS, we need to wrap the given importer to make it suitable to pass // to ICS. We do this in two steps: first, wrap the importer with our own PHP importer class // which removes all MAPI dependency, and then wrap that class with a C++ wrapper so we can // pass it to ICS $exporterflags = 0; if ($this->_folderid) { // PHP wrapper $phpimportproxy = new PHPContentsImportProxy($this->_session, $this->_store, $this->_folderid, $importer, $truncation); // ICS c++ wrapper $mapiimporter = mapi_wrap_importcontentschanges($phpimportproxy); $exporterflags |= SYNC_NORMAL | SYNC_READ_STATE; // Initial sync, we don't want deleted items. On subsequent syncs, we do want to receive delete // events. if (strlen($syncstate) == 0) { $exporterflags |= SYNC_NO_SOFT_DELETIONS; } } else { $phpimportproxy = new PHPHierarchyImportProxy($this->_store, $importer); $mapiimporter = mapi_wrap_importhierarchychanges($phpimportproxy); } if ($flags & BACKEND_DISCARD_DATA) { $exporterflags |= SYNC_CATCHUP; } // Put the state information in a stream that can be used by ICS $stream = mapi_stream_create(); if (strlen($syncstate) > 0) { mapi_stream_write($stream, $syncstate); } else { mapi_stream_write($stream, hex2bin("0000000000000000")); } $this->statestream = $stream; switch ($mclass) { case "Email": $restriction = $this->_getEmailRestriction($this->_getCutOffDate($restrict)); break; case "Calendar": $restriction = $this->_getCalendarRestriction($this->_getCutOffDate($restrict)); break; default: case "Contacts": case "Tasks": $restriction = false; break; } $ret = mapi_exportchanges_config($this->exporter, $stream, $exporterflags, $mapiimporter, $restriction, false, false, 1); if ($ret) { debugLog("Exporter configured successfully. " . mapi_exportchanges_getchangecount($this->exporter) . " changes ready to sync."); } else { debugLog("Exporter could not be configured: result: " . mapi_last_hresult()); } return $ret; }