public function WBXMLEncoder($output, $multipart = false) { $this->log = defined('WBXML_DEBUG') && WBXML_DEBUG; $this->_out = $output; $this->_outLog = StringStreamWrapper::Open(""); // reverse-map the DTD foreach ($this->dtd["namespaces"] as $nsid => $nsname) { $this->_dtd["namespaces"][$nsname] = $nsid; } foreach ($this->dtd["codes"] as $cp => $value) { $this->_dtd["codes"][$cp] = array(); foreach ($this->dtd["codes"][$cp] as $tagid => $tagname) { $this->_dtd["codes"][$cp][$tagname] = $tagid; } } $this->_stack = array(); $this->multipart = $multipart; $this->bodyparts = array(); }
/** * WBXML Decode Constructor * We only handle ActiveSync WBXML, which is a subset of WBXML * * @param stream $input the incoming data stream * * @access public */ public function WBXMLDecoder($input) { $this->log = defined('WBXML_DEBUG') && WBXML_DEBUG; $this->in = $input; $this->inLog = StringStreamWrapper::Open(""); $version = $this->getByte(); if ($version != self::VERSION) { $this->inputBuffer .= chr($version); $this->isWBXML = false; return; } $publicid = $this->getMBUInt(); if ($publicid !== 1) { throw new WBXMLException("Wrong publicid : " . $publicid); } $charsetid = $this->getMBUInt(); if ($charsetid !== 106) { throw new WBXMLException("Wrong charset : " . $charsetid); } $stringtablesize = $this->getMBUInt(); if ($stringtablesize !== 0) { throw new WBXMLException("Wrong string table size : " . $stringtablesize); } }
/** * Returns the content of the named attachment as stream. The passed attachment identifier is * the exact string that is returned in the 'AttName' property of an SyncAttachment. * Any information necessary to find the attachment must be encoded in that 'attname' property. * Data is written directly (with print $data;) * * @param string $attname * * @access public * @return SyncItemOperationsAttachment * @throws StatusException */ public function GetAttachmentData($attname) { list($id, $part) = explode(":", $attname); $fn = $this->findMessage($id); if ($fn == false) { throw new StatusException(sprintf("BackendMaildir->GetAttachmentData('%s'): Error, requested message/attachment can not be found", $attname), SYNC_ITEMOPERATIONSSTATUS_INVALIDATT); } // Parse e-mail $rfc822 = file_get_contents($this->getPath() . "/{$fn}"); $message = Mail_mimeDecode::decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $rfc822, 'crlf' => "\n", 'charset' => 'utf-8')); include_once 'include/stringstreamwrapper.php'; $attachment = new SyncItemOperationsAttachment(); $attachment->data = StringStreamWrapper::Open($message->parts[$part]->body); if (isset($message->parts[$part]->ctype_primary) && isset($message->parts[$part]->ctype_secondary)) { $attachment->contenttype = $message->parts[$part]->ctype_primary . '/' . $message->parts[$part]->ctype_secondary; } return $attachment; }
/** * Returns the content of the named attachment as stream. The passed attachment identifier is * the exact string that is returned in the 'AttName' property of an SyncAttachment. * Any information necessary to find the attachment must be encoded in that 'attname' property. * Data is written directly (with print $data;) * * @param string $attname * * @access public * @return SyncItemOperationsAttachment * @throws StatusException */ public function GetAttachmentData($attname) { ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->GetAttachmentData('%s')", $attname)); list($folderid, $id, $part) = explode(":", $attname); if (!$folderid || !$id || !$part) { throw new StatusException(sprintf("BackendIMAP->GetAttachmentData('%s'): Error, attachment name key can not be parsed", $attname), SYNC_ITEMOPERATIONSSTATUS_INVALIDATT); } // convert back to work on an imap-id $folderImapid = $this->getImapIdFromFolderId($folderid); $this->imap_reopenFolder($folderImapid); $mail = @imap_fetchheader($this->mbox, $id, FT_UID) . @imap_body($this->mbox, $id, FT_PEEK | FT_UID); $mobj = new Mail_mimeDecode($mail); $message = $mobj->decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'charset' => 'utf-8')); /* BEGIN fmbiete's contribution r1528, ZP-320 */ //trying parts $mparts = $message->parts; for ($i = 0; $i < count($mparts); $i++) { $auxpart = $mparts[$i]; //recursively add parts if ($auxpart->ctype_primary == "multipart" && ($auxpart->ctype_secondary == "mixed" || $auxpart->ctype_secondary == "alternative" || $auxpart->ctype_secondary == "related")) { foreach ($auxpart->parts as $spart) { $mparts[] = $spart; } } } /* END fmbiete's contribution r1528, ZP-320 */ if (!isset($mparts[$part]->body)) { throw new StatusException(sprintf("BackendIMAP->GetAttachmentData('%s'): Error, requested part key can not be found: '%d'", $attname, $part), SYNC_ITEMOPERATIONSSTATUS_INVALIDATT); } // unset mimedecoder & mail unset($mobj); unset($mail); include_once 'include/stringstreamwrapper.php'; $attachment = new SyncItemOperationsAttachment(); /* BEGIN fmbiete's contribution r1528, ZP-320 */ $attachment->data = StringStreamWrapper::Open($mparts[$part]->body); if (isset($mparts[$part]->ctype_primary) && isset($mparts[$part]->ctype_secondary)) { $attachment->contenttype = $mparts[$part]->ctype_primary . '/' . $mparts[$part]->ctype_secondary; } unset($mparts); unset($message); ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->GetAttachmentData contenttype %s", $attachment->contenttype)); /* END fmbiete's contribution r1528, ZP-320 */ return $attachment; }
/** * Returns the actual SyncXXX object type. * * @param string $folderid id of the parent folder * @param string $id id of the message * @param ContentParameters $contentparameters parameters of the requested message (truncation, mimesupport etc) * * @access public * @return object/false false if the message could not be retrieved */ public function GetMessage($folderid, $id, $contentparameters) { $truncsize = Utils::GetTruncSize($contentparameters->GetTruncation()); $mimesupport = $contentparameters->GetMimeSupport(); $bodypreference = $contentparameters->GetBodyPreference(); /* fmbiete's contribution r1528, ZP-320 */ ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->GetMessage('%s', '%s', '%s')", $folderid, $id, implode(",", $bodypreference))); $folderImapid = $this->getImapIdFromFolderId($folderid); $is_sent_folder = strcasecmp($folderImapid, $this->create_name_folder(IMAP_FOLDER_SENT)) == 0; // Get flags, etc $stat = $this->StatMessage($folderid, $id); if ($stat) { $this->imap_reopen_folder($folderImapid); $mail_headers = @imap_fetchheader($this->mbox, $id, FT_UID); $mail = $mail_headers . @imap_body($this->mbox, $id, FT_PEEK | FT_UID); if (empty($mail)) { throw new StatusException(sprintf("BackendIMAP->GetMessage(): Error, message not found, maybe was moved"), SYNC_ITEMOPERATIONSSTATUS_INVALIDATT); } $mobj = new Mail_mimeDecode($mail); $message = $mobj->decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'rfc_822bodies' => true, 'charset' => 'utf-8')); $is_multipart = is_multipart($message); $is_smime = is_smime($message); $is_encrypted = $is_smime ? is_encrypted($message) : false; ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->GetMessage(): Message is multipart: %d, smime: %d, smime encrypted: %d", $is_multipart, $is_smime, $is_encrypted)); //Select body type preference $bpReturnType = SYNC_BODYPREFERENCE_PLAIN; if ($bodypreference !== false) { $bpReturnType = Utils::GetBodyPreferenceBestMatch($bodypreference); // changed by mku ZP-330 } ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->GetMessage(): getBodyPreferenceBestMatch: %d", $bpReturnType)); // Prefered format is MIME -OR- message is SMIME -OR- the device supports MIME (iPhone) and doesn't really understand HTML if ($bpReturnType == SYNC_BODYPREFERENCE_MIME || $is_smime || in_array(SYNC_BODYPREFERENCE_MIME, $bodypreference)) { $bpReturnType = SYNC_BODYPREFERENCE_MIME; } // We need the text body even though MIME is used, for the preview $textBody = ""; Mail_mimeDecode::getBodyRecursive($message, "html", $textBody, true); if (strlen($textBody) > 0) { if ($bpReturnType != SYNC_BODYPREFERENCE_MIME) { $bpReturnType = SYNC_BODYPREFERENCE_HTML; } } else { Mail_mimeDecode::getBodyRecursive($message, "plain", $textBody, true); if ($bpReturnType != SYNC_BODYPREFERENCE_MIME) { $bpReturnType = SYNC_BODYPREFERENCE_PLAIN; } } ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->GetMessage(): after thinking a bit we will use: %d", $bpReturnType)); $output = new SyncMail(); if (Request::GetProtocolVersion() >= 12.0) { $output->asbody = new SyncBaseBody(); $data = ""; switch ($bpReturnType) { case SYNC_BODYPREFERENCE_PLAIN: $data = $textBody; break; case SYNC_BODYPREFERENCE_HTML: $data = $textBody; break; case SYNC_BODYPREFERENCE_MIME: if ($is_smime) { if ($is_encrypted) { // #190, KD 2015-06-04 - If message body is encrypted only send the headers, as data should only be in the attachment $data = $mail_headers; } else { $data = $mail; } } else { $data = build_mime_message($message); } break; case SYNC_BODYPREFERENCE_RTF: ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->GetMessage RTF Format NOT SUPPORTED"); // TODO: this is broken. This is no RTF. $data = base64_encode($textBody); break; } // truncate body, if requested. // MIME should not be truncated, but encrypted messages are truncated always to the headers size if ($bpReturnType == SYNC_BODYPREFERENCE_MIME) { if ($is_encrypted) { $output->asbody->truncated = 1; } else { $output->asbody->truncated = 0; } } else { if (strlen($data) > $truncsize) { $data = Utils::Utf8_truncate($data, $truncsize); $output->asbody->truncated = 1; } else { $output->asbody->truncated = 0; } } $output->asbody->data = StringStreamWrapper::Open($data); $output->asbody->estimatedDataSize = strlen($data); unset($data); $output->asbody->type = $bpReturnType; if ($bpReturnType == SYNC_BODYPREFERENCE_MIME) { // NativeBodyType can be only (1 => PLAIN, 2 => HTML, 3 => RTF). MIME uses 1 $output->nativebodytype = SYNC_BODYPREFERENCE_PLAIN; } else { $output->nativebodytype = $bpReturnType; } $bpo = $contentparameters->BodyPreference($output->asbody->type); if (Request::GetProtocolVersion() >= 14.0 && $bpo->GetPreview()) { // Preview must be always plaintext $previewText = ""; Mail_mimeDecode::getBodyRecursive($message, "plain", $previewText, true); if (strlen($previewText) == 0) { Mail_mimeDecode::getBodyRecursive($message, "html", $previewText, true); $previewText = Utils::ConvertHtmlToText($previewText); } $output->asbody->preview = Utils::Utf8_truncate($previewText, $bpo->GetPreview()); } } else { // ASV_2.5 //DEPRECATED : very old devices, and incomplete code $output->bodytruncated = 0; $data = ""; if ($bpReturnType == SYNC_BODYPREFERENCE_MIME) { $data = $mail; } else { $data = $textBody; } $output->mimesize = strlen($data); if (strlen($data) > $truncsize && $bpReturnType != SYNC_BODYPREFERENCE_MIME) { $output->mimedata = StringStreamWrapper::Open(Utils::Utf8_truncate($data, $truncsize)); $output->mimetruncated = 1; } else { $output->mimetruncated = 0; $output->mimedata = StringStreamWrapper::Open($data); } unset($data); } unset($textBody); unset($mail_headers); $output->datereceived = isset($message->headers["date"]) ? $this->cleanupDate($message->headers["date"]) : null; if ($is_smime) { // #190, KD 2015-06-04 - Add Encrypted (and possibly signed) to the classifications emitted if ($is_encrypted) { $output->messageclass = "IPM.Note.SMIME"; } else { $output->messageclass = "IPM.Note.SMIME.MultipartSigned"; } } else { $output->messageclass = "IPM.Note"; } $output->subject = isset($message->headers["subject"]) ? $message->headers["subject"] : ""; $output->read = $stat["flags"]; $output->from = isset($message->headers["from"]) ? $message->headers["from"] : null; if (isset($message->headers["thread-topic"])) { $output->threadtopic = $message->headers["thread-topic"]; } else { $output->threadtopic = $output->subject; } // Language Code Page ID: http://msdn.microsoft.com/en-us/library/windows/desktop/dd317756%28v=vs.85%29.aspx $output->internetcpid = INTERNET_CPID_UTF8; if (Request::GetProtocolVersion() >= 12.0) { $output->contentclass = "urn:content-classes:message"; $output->flag = new SyncMailFlags(); if (isset($stat["star"]) && $stat["star"]) { //flagstatus 0: clear, 1: complete, 2: active $output->flag->flagstatus = SYNC_FLAGSTATUS_ACTIVE; //flagtype: for follow up $output->flag->flagtype = "FollowUp"; } else { $output->flag->flagstatus = SYNC_FLAGSTATUS_CLEAR; } } $Mail_RFC822 = new Mail_RFC822(); $toaddr = $ccaddr = $replytoaddr = array(); if (isset($message->headers["to"])) { $toaddr = $Mail_RFC822->parseAddressList($message->headers["to"]); } if (isset($message->headers["cc"])) { $ccaddr = $Mail_RFC822->parseAddressList($message->headers["cc"]); } if (isset($message->headers["reply-to"])) { $replytoaddr = $Mail_RFC822->parseAddressList($message->headers["reply-to"]); } $output->to = array(); $output->cc = array(); $output->reply_to = array(); foreach (array("to" => $toaddr, "cc" => $ccaddr, "reply_to" => $replytoaddr) as $type => $addrlist) { if ($addrlist === false) { //If we couldn't parse the addresslist we put the raw header (decoded) if ($type == "reply_to") { array_push($output->{$type}, $message->headers["reply-to"]); } else { array_push($output->{$type}, $message->headers[$type]); } } else { foreach ($addrlist as $addr) { // If the address was a group we have "groupname" and "addresses" atributes if (isset($addr->addresses)) { if (count($addr->addresses) == 0) { // readd the empty group delimiter array_push($output->{$type}, sprintf("%s:;", $addr->groupname)); if (!isset($output->displayto) && strlen($addr->groupname) > 0) { $output->displayto = $addr->groupname; } } else { foreach ($addr->addresses as $addr_group) { $name = $this->add_address_to_list($output->{$type}, $addr_group); if (!isset($output->displayto) && strlen($name) > 0) { $output->displayto = $name; } } } } else { // Not a group $name = $this->add_address_to_list($output->{$type}, $addr); if (!isset($output->displayto) && strlen($name) > 0) { $output->displayto = $name; } } } } } // convert mime-importance to AS-importance if (isset($message->headers["x-priority"])) { $mimeImportance = preg_replace("/\\D+/", "", $message->headers["x-priority"]); //MAIL 1 - most important, 3 - normal, 5 - lowest //AS 0 - low, 1 - normal, 2 - important if ($mimeImportance > 3) { $output->importance = 0; } elseif ($mimeImportance == 3) { $output->importance = 1; } elseif ($mimeImportance < 3) { $output->importance = 2; } } else { /* fmbiete's contribution r1528, ZP-320 */ $output->importance = 1; } // Attachments are also needed for MIME messages if (isset($message->parts)) { $mparts = $message->parts; for ($i = 0; $i < count($mparts); $i++) { $part = $mparts[$i]; //recursively add subparts to later processing if (isset($part->ctype_primary) && $part->ctype_primary == "multipart" && (isset($part->ctype_secondary) && ($part->ctype_secondary == "mixed" || $part->ctype_secondary == "alternative" || $part->ctype_secondary == "related"))) { if (isset($part->parts)) { foreach ($part->parts as $spart) { $mparts[] = $spart; } } // Go to the for again continue; } if (is_calendar($part)) { ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->GetMessage(): text/calendar part found, trying to convert")); $output->meetingrequest = new SyncMeetingRequest(); parse_meeting_calendar($part, $output, $is_sent_folder); } else { //add part as attachment if it's disposition indicates so or if it is not a text part if (isset($part->disposition) && ($part->disposition == "attachment" || $part->disposition == "inline") || isset($part->ctype_primary) && $part->ctype_primary != "text") { if (isset($part->d_parameters['filename'])) { $attname = $part->d_parameters['filename']; } else { if (isset($part->ctype_parameters['name'])) { $attname = $part->ctype_parameters['name']; } else { if (isset($part->headers['content-description'])) { $attname = $part->headers['content-description']; } else { $attname = "unknown attachment"; } } } /* BEGIN fmbiete's contribution r1528, ZP-320 */ if (Request::GetProtocolVersion() >= 12.0) { if (!isset($output->asattachments) || !is_array($output->asattachments)) { $output->asattachments = array(); } $attachment = new SyncBaseAttachment(); $attachment->estimatedDataSize = isset($part->d_parameters['size']) ? $part->d_parameters['size'] : isset($part->body) ? strlen($part->body) : 0; $attachment->displayname = $attname; $attachment->filereference = $folderid . ":" . $id . ":" . $i; $attachment->method = 1; //Normal attachment $attachment->contentid = isset($part->headers['content-id']) ? str_replace("<", "", str_replace(">", "", $part->headers['content-id'])) : ""; if (isset($part->disposition) && $part->disposition == "inline") { $attachment->isinline = 1; // #209 - KD 2015-06-16 If we got a filename use it, otherwise guess if (!isset($part->filename)) { // We try to fix the name for the inline file. // FIXME: This is a dirty hack as the used in the Zarafa backend, if you have a better method let me know! if (isset($part->ctype_primary) && isset($part->ctype_secondary)) { ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->GetMessage(): Guessing extension for inline attachment [primary_type %s secondary_type %s]", $part->ctype_primary, $part->ctype_secondary)); if (isset(BackendIMAP::$mimeTypes[$part->ctype_primary . '/' . $part->ctype_secondary])) { ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->GetMessage(): primary_type %s secondary_type %s", $part->ctype_primary, $part->ctype_secondary)); $attachment->displayname = "inline_" . $i . "." . BackendIMAP::$mimeTypes[$part->ctype_primary . '/' . $part->ctype_secondary]; } else { ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->GetMessage(): no extension found in '%s'!!", SYSTEM_MIME_TYPES_MAPPING)); } } else { ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->GetMessage(): no primary_type or secondary_type")); } } } else { $attachment->isinline = 0; } array_push($output->asattachments, $attachment); } else { //ASV_2.5 if (!isset($output->attachments) || !is_array($output->attachments)) { $output->attachments = array(); } $attachment = new SyncAttachment(); $attachment->attsize = isset($part->d_parameters['size']) ? $part->d_parameters['size'] : isset($part->body) ? strlen($part->body) : 0; $attachment->displayname = $attname; $attachment->attname = $folderid . ":" . $id . ":" . $i; $attachment->attmethod = 1; $attachment->attoid = isset($part->headers['content-id']) ? str_replace("<", "", str_replace(">", "", $part->headers['content-id'])) : ""; array_push($output->attachments, $attachment); } /* END fmbiete's contribution r1528, ZP-320 */ } } } } unset($message); unset($mobj); unset($mail); return $output; } return false; }
/** * Returns the content of the named attachment as stream. The passed attachment identifier is * the exact string that is returned in the 'AttName' property of an SyncAttachment. * Any information necessary to find the attachment must be encoded in that 'attname' property. * Data is written directly (with print $data;) * * @param string $attname * * @access public * @return SyncItemOperationsAttachment * @throws StatusException */ public function GetAttachmentData($attname) { ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->GetAttachmentData('%s')", $attname)); list($folderid, $id, $part) = explode(":", $attname); if (!$folderid || !$id || !$part) { throw new StatusException(sprintf("BackendIMAP->GetAttachmentData('%s'): Error, attachment name key can not be parsed", $attname), SYNC_ITEMOPERATIONSSTATUS_INVALIDATT); } // convert back to work on an imap-id $folderImapid = $this->getImapIdFromFolderId($folderid); $this->imap_reopenFolder($folderImapid); $mail = @imap_fetchheader($this->mbox, $id, FT_UID) . @imap_body($this->mbox, $id, FT_PEEK | FT_UID); $mobj = new Mail_mimeDecode($mail); $message = $mobj->decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'charset' => 'utf-8')); if (!isset($message->parts[$part]->body)) { throw new StatusException(sprintf("BackendIMAP->GetAttachmentData('%s'): Error, requested part key can not be found: '%d'", $attname, $part), SYNC_ITEMOPERATIONSSTATUS_INVALIDATT); } // unset mimedecoder & mail unset($mobj); unset($mail); include_once 'include/stringstreamwrapper.php'; $attachment = new SyncItemOperationsAttachment(); $attachment->data = StringStreamWrapper::Open($message->parts[$part]->body); if (isset($message->parts[$part]->ctype_primary) && isset($message->parts[$part]->ctype_secondary)) { $attachment->contenttype = $message->parts[$part]->ctype_primary . '/' . $message->parts[$part]->ctype_secondary; } return $attachment; }
/** * Sets the message body. * * @param MAPIMessage $mapimessage * @param ContentParameters $contentparameters * @param SyncObject $message */ private function setMessageBody($mapimessage, $contentparameters, &$message) { //get the available body preference types $bpTypes = $contentparameters->GetBodyPreference(); if ($bpTypes !== false) { ZLog::Write(LOGLEVEL_DEBUG, sprintf("BodyPreference types: %s", implode(', ', $bpTypes))); //do not send mime data if the client requests it if ($contentparameters->GetMimeSupport() == SYNC_MIMESUPPORT_NEVER && ($key = array_search(SYNC_BODYPREFERENCE_MIME, $bpTypes) !== false)) { unset($bpTypes[$key]); ZLog::Write(LOGLEVEL_DEBUG, sprintf("Remove mime body preference type because the device required no mime support. BodyPreference types: %s", implode(', ', $bpTypes))); } //get the best fitting preference type $bpReturnType = Utils::GetBodyPreferenceBestMatch($bpTypes); ZLog::Write(LOGLEVEL_DEBUG, sprintf("GetBodyPreferenceBestMatch: %d", $bpReturnType)); $bpo = $contentparameters->BodyPreference($bpReturnType); ZLog::Write(LOGLEVEL_DEBUG, sprintf("bpo: truncation size:'%d', allornone:'%d', preview:'%d'", $bpo->GetTruncationSize(), $bpo->GetAllOrNone(), $bpo->GetPreview())); $this->setMessageBodyForType($mapimessage, $bpReturnType, $message); //only set the truncation size data if device set it in request if ($bpo->GetTruncationSize() != false && $bpReturnType != SYNC_BODYPREFERENCE_MIME && $message->asbody->estimatedDataSize > $bpo->GetTruncationSize()) { // Truncated plaintext requests are used on iOS for the preview in the email list. All images and links should be removed - see https://jira.z-hub.io/browse/ZP-1025 if ($bpReturnType == SYNC_BODYPREFERENCE_PLAIN) { ZLog::Write(LOGLEVEL_DEBUG, "MAPIProvider->setMessageBody(): truncated plain-text body requested, stripping all links and images"); // Get more data because of the filtering it's most probably going down in size. It's going to be truncated to the correct size below. $plainbody = stream_get_contents($message->asbody->data, $bpo->GetTruncationSize() * 3); $message->asbody->data = StringStreamWrapper::Open(preg_replace('/<http(s){0,1}:\\/\\/.*?>/i', '', $plainbody)); } // truncate data stream ftruncate($message->asbody->data, $bpo->GetTruncationSize()); $message->asbody->truncated = 1; } // set the preview or windows phones won't show the preview of an email if (Request::GetProtocolVersion() >= 14.0 && $bpo->GetPreview()) { $message->asbody->preview = Utils::Utf8_truncate(MAPIUtils::readPropStream($mapimessage, PR_BODY), $bpo->GetPreview()); } } else { // Override 'body' for truncation $truncsize = Utils::GetTruncSize($contentparameters->GetTruncation()); $this->setMessageBodyForType($mapimessage, SYNC_BODYPREFERENCE_PLAIN, $message); if ($message->bodysize > $truncsize) { $message->body = Utils::Utf8_truncate($message->body, $truncsize); $message->bodytruncated = 1; } if (!isset($message->body) || strlen($message->body) == 0) { $message->body = " "; } if ($contentparameters->GetMimeSupport() == SYNC_MIMESUPPORT_ALWAYS) { //set the html body for iphone in AS 2.5 version $this->imtoinet($mapimessage, $message); } } }
include_once '../../src/lib/wbxml/wbxmldecoder.php'; include_once '../../src/lib/wbxml/wbxmlencoder.php'; // minimal definitions & log to stdout overwrite define('WBXML_DEBUG', true); define("LOGLEVEL_WBXML", "wbxml"); define("LOGLEVEL_DEBUG", "debug"); class ZLog { public static function Write($level, $msg, $truncate = false) { // we only care about the wbxml if ($level == "wbxml") { if (substr($msg, 0, 1) == "I") { echo substr($msg, 1) . "\n"; } else { echo $msg . "\n"; } } } } // setup $wxbml = StringStreamWrapper::Open($wbxml64); $base64filter = stream_filter_append($wxbml, 'convert.base64-decode'); $decoder = new WBXMLDecoder($wxbml); if (!$decoder->IsWBXML()) { die("input is not WBXML as base64\n\n"); } echo "\n"; // read everything and log it $decoder->readRemainingData(); echo "\n";
/** * Decodes the WBXML from a WBXMLdecoder until we reach the same depth level of WBXML. * This means that if there are multiple objects at this level, then only the first is * decoded SubOjects are auto-instantiated and decoded using the same functionality * * @param WBXMLDecoder $decoder * * @access public */ public function Decode(&$decoder) { WBXMLDecoder::ResetInWhile("decodeMain"); while (WBXMLDecoder::InWhile("decodeMain")) { $entity = $decoder->getElement(); if ($entity[EN_TYPE] == EN_TYPE_STARTTAG) { if (!($entity[EN_FLAGS] & EN_FLAGS_CONTENT)) { $map = $this->mapping[$entity[EN_TAG]]; if (isset($map[self::STREAMER_ARRAY])) { $this->{$map[self::STREAMER_VAR]} = array(); } else { if (isset($map[self::STREAMER_PROP]) && $map[self::STREAMER_PROP] == self::STREAMER_TYPE_SEND_EMPTY) { $this->{$map[self::STREAMER_VAR]} = "1"; } else { if (!isset($map[self::STREAMER_TYPE])) { $this->{$map[self::STREAMER_VAR]} = ""; } else { if ($map[self::STREAMER_TYPE] == self::STREAMER_TYPE_DATE || $map[self::STREAMER_TYPE] == self::STREAMER_TYPE_DATE_DASHES) { $this->{$map[self::STREAMER_VAR]} = ""; } } } } continue; } // Found a start tag if (!isset($this->mapping[$entity[EN_TAG]])) { // This tag shouldn't be here, abort ZLog::Write(LOGLEVEL_WBXMLSTACK, sprintf("Tag '%s' unexpected in type XML type '%s'", $entity[EN_TAG], get_class($this))); return false; } else { $map = $this->mapping[$entity[EN_TAG]]; // Handle an array if (isset($map[self::STREAMER_ARRAY])) { WBXMLDecoder::ResetInWhile("decodeArray"); while (WBXMLDecoder::InWhile("decodeArray")) { //do not get start tag for an array without a container if (!(isset($map[self::STREAMER_PROP]) && $map[self::STREAMER_PROP] == self::STREAMER_TYPE_NO_CONTAINER)) { if (!$decoder->getElementStartTag($map[self::STREAMER_ARRAY])) { break; } } if (isset($map[self::STREAMER_TYPE])) { $decoded = new $map[self::STREAMER_TYPE](); $decoded->Decode($decoder); } else { $decoded = $decoder->getElementContent(); } if (!isset($this->{$map[self::STREAMER_VAR]})) { $this->{$map[self::STREAMER_VAR]} = array($decoded); } else { array_push($this->{$map[self::STREAMER_VAR]}, $decoded); } if (!$decoder->getElementEndTag()) { //end tag of a container element return false; } if (isset($map[self::STREAMER_PROP]) && $map[self::STREAMER_PROP] == self::STREAMER_TYPE_NO_CONTAINER) { $e = $decoder->peek(); //go back to the initial while if another block of no container elements is found if ($e[EN_TYPE] == EN_TYPE_STARTTAG) { continue 2; } //break on end tag because no container elements block end is reached if ($e[EN_TYPE] == EN_TYPE_ENDTAG) { break; } if (empty($e)) { break; } } } //do not get end tag for an array without a container if (!(isset($map[self::STREAMER_PROP]) && $map[self::STREAMER_PROP] == self::STREAMER_TYPE_NO_CONTAINER)) { if (!$decoder->getElementEndTag()) { //end tag of container return false; } } } else { // Handle single value if (isset($map[self::STREAMER_TYPE])) { // Complex type, decode recursively if ($map[self::STREAMER_TYPE] == self::STREAMER_TYPE_DATE || $map[self::STREAMER_TYPE] == self::STREAMER_TYPE_DATE_DASHES) { $decoded = $this->parseDate($decoder->getElementContent()); if (!$decoder->getElementEndTag()) { return false; } } else { if ($map[self::STREAMER_TYPE] == self::STREAMER_TYPE_HEX) { $decoded = hex2bin($decoder->getElementContent()); if (!$decoder->getElementEndTag()) { return false; } } else { if ($map[self::STREAMER_TYPE] == self::STREAMER_TYPE_COMMA_SEPARATED || $map[self::STREAMER_TYPE] == self::STREAMER_TYPE_SEMICOLON_SEPARATED) { $glue = $map[self::STREAMER_TYPE] == self::STREAMER_TYPE_COMMA_SEPARATED ? ", " : "; "; $decoded = explode($glue, $decoder->getElementContent()); if (!$decoder->getElementEndTag()) { return false; } } else { if ($map[self::STREAMER_TYPE] == self::STREAMER_TYPE_STREAM_ASPLAIN) { $decoded = StringStreamWrapper::Open($decoder->getElementContent()); if (!$decoder->getElementEndTag()) { return false; } } else { $subdecoder = new $map[self::STREAMER_TYPE](); if ($subdecoder->Decode($decoder) === false) { return false; } $decoded = $subdecoder; if (!$decoder->getElementEndTag()) { ZLog::Write(LOGLEVEL_WBXMLSTACK, sprintf("No end tag for '%s'", $entity[EN_TAG])); return false; } } } } } } else { // Simple type, just get content $decoded = $decoder->getElementContent(); if ($decoded === false) { // the tag is declared to have content, but no content is available. // set an empty content $decoded = ""; } if (!$decoder->getElementEndTag()) { ZLog::Write(LOGLEVEL_WBXMLSTACK, sprintf("Unable to get end tag for '%s'", $entity[EN_TAG])); return false; } } // $decoded now contains data object (or string) $this->{$map[self::STREAMER_VAR]} = $decoded; } } } else { if ($entity[EN_TYPE] == EN_TYPE_ENDTAG) { $decoder->ungetElement($entity); break; } else { ZLog::Write(LOGLEVEL_WBXMLSTACK, "Unexpected content in type"); break; } } } }
include_once '../../src/lib/wbxml/wbxmldecoder.php'; include_once '../../src/lib/wbxml/wbxmlencoder.php'; // minimal definitions & log to stdout overwrite define('WBXML_DEBUG', true); define("LOGLEVEL_WBXML", "wbxml"); define("LOGLEVEL_DEBUG", "debug"); class ZLog { public static function Write($level, $msg, $truncate = false) { // we only care about the wbxml if ($level == "wbxml") { if (substr($msg, 0, 1) == "I") { echo substr($msg, 1) . "\n"; } else { echo $msg . "\n"; } } } } // setup $wxbml = is_file($wbxml64) ? fopen($wbxml64, 'r+') : StringStreamWrapper::Open($wbxml64); $base64filter = stream_filter_append($wxbml, 'convert.base64-decode'); $decoder = new WBXMLDecoder($wxbml); if (!$decoder->IsWBXML()) { die("input is not WBXML as base64\n\n"); } echo "\n"; // read everything and log it $decoder->readRemainingData(); echo "\n";