/** * A wrapper for mapi_inetmapi_imtoinet function * * @param MAPIMessage $mapimessage * @param SyncObject $message * * @access private * @return boolean */ private function imtoinet($mapimessage, &$message) { // if it is a signed message get a full attachment generated by ZCP $props = mapi_getprops($mapimessage, array(PR_MESSAGE_CLASS)); if (isset($props[PR_MESSAGE_CLASS]) && $props[PR_MESSAGE_CLASS] && strpos(strtolower($props[PR_MESSAGE_CLASS]), 'multipartsigned')) { // find the required attachment $attachtable = mapi_message_getattachmenttable($mapimessage); mapi_table_restrict($attachtable, MAPIUtils::GetSignedAttachmentRestriction()); if (mapi_table_getrowcount($attachtable) == 1) { $rows = mapi_table_queryrows($attachtable, array(PR_ATTACH_NUM, PR_ATTACH_SIZE), 0, 1); if (isset($rows[0][PR_ATTACH_NUM])) { $mapiattach = mapi_message_openattach($mapimessage, $rows[0][PR_ATTACH_NUM]); $stream = mapi_openpropertytostream($mapiattach, PR_ATTACH_DATA_BIN); $streamsize = $rows[0][PR_ATTACH_SIZE]; } } } elseif (function_exists("mapi_inetmapi_imtoinet")) { $addrbook = $this->getAddressbook(); $stream = mapi_inetmapi_imtoinet($this->session, $addrbook, $mapimessage, array('use_tnef' => -1)); $mstreamstat = mapi_stream_stat($stream); $streamsize = $mstreamstat["cb"]; } if (isset($stream) && isset($streamsize)) { if (Request::GetProtocolVersion() >= 12.0) { if (!isset($message->asbody)) { $message->asbody = new SyncBaseBody(); } //TODO data should be wrapped in a MapiStreamWrapper $message->asbody->data = mapi_stream_read($stream, $streamsize); $message->asbody->estimatedDataSize = $streamsize; $message->asbody->truncated = 0; } else { $message->mimetruncated = 0; //TODO mimedata should be a wrapped in a MapiStreamWrapper $message->mimedata = mapi_stream_read($stream, $streamsize); $message->mimesize = $streamsize; } unset($message->body, $message->bodytruncated); return true; } else { ZLog::Write(LOGLEVEL_ERROR, sprintf("Error opening attachment for imtoinet")); } return false; }
/** * Reads an email object from MAPI * * @param mixed $mapimessage * @param ContentParameters $contentparameters * * @access private * @return SyncEmail */ private function getEmail($mapimessage, $contentparameters) { $message = new SyncMail(); $this->getPropsFromMAPI($message, $mapimessage, MAPIMapping::GetEmailMapping()); $emailproperties = MAPIMapping::GetEmailProperties(); $messageprops = $this->getProps($mapimessage, $emailproperties); if (isset($messageprops[PR_SOURCE_KEY])) { $sourcekey = $messageprops[PR_SOURCE_KEY]; } else { return false; } //set the body according to contentparameters and supported AS version $this->setMessageBody($mapimessage, $contentparameters, $message); $fromname = $fromaddr = ""; if (isset($messageprops[$emailproperties["representingname"]])) { // remove encapsulating double quotes from the representingname $fromname = preg_replace('/^\\"(.*)\\"$/', "\${1}", $messageprops[$emailproperties["representingname"]]); } if (isset($messageprops[$emailproperties["representingentryid"]])) { $fromaddr = $this->getSMTPAddressFromEntryID($messageprops[$emailproperties["representingentryid"]]); } if ($fromname == $fromaddr) { $fromname = ""; } if ($fromname) { $from = "\"" . w2u($fromname) . "\" <" . w2u($fromaddr) . ">"; } else { //START CHANGED dw2412 HTC shows "error" if sender name is unknown $from = "\"" . w2u($fromaddr) . "\" <" . w2u($fromaddr) . ">"; } //END CHANGED dw2412 HTC shows "error" if sender name is unknown $message->from = $from; // process Meeting Requests if (isset($message->messageclass) && strpos($message->messageclass, "IPM.Schedule.Meeting") === 0) { $message->meetingrequest = new SyncMeetingRequest(); $this->getPropsFromMAPI($message->meetingrequest, $mapimessage, MAPIMapping::GetMeetingRequestMapping()); $meetingrequestproperties = MAPIMapping::GetMeetingRequestProperties(); $props = $this->getProps($mapimessage, $meetingrequestproperties); // Get the GOID if (isset($props[$meetingrequestproperties["goidtag"]])) { $message->meetingrequest->globalobjid = base64_encode($props[$meetingrequestproperties["goidtag"]]); } // Set Timezone if (isset($props[$meetingrequestproperties["timezonetag"]])) { $tz = $this->getTZFromMAPIBlob($props[$meetingrequestproperties["timezonetag"]]); } else { $tz = $this->getGMTTZ(); } $message->meetingrequest->timezone = base64_encode($this->getSyncBlobFromTZ($tz)); // send basedate if exception if (isset($props[$meetingrequestproperties["recReplTime"]]) || isset($props[$meetingrequestproperties["lidIsException"]]) && $props[$meetingrequestproperties["lidIsException"]] == true) { if (isset($props[$meetingrequestproperties["recReplTime"]])) { $basedate = $props[$meetingrequestproperties["recReplTime"]]; $message->meetingrequest->recurrenceid = $this->getGMTTimeByTZ($basedate, $this->getGMTTZ()); } else { if (!isset($props[$meetingrequestproperties["goidtag"]]) || !isset($props[$meetingrequestproperties["recurStartTime"]]) || !isset($props[$meetingrequestproperties["timezonetag"]])) { ZLog::Write(LOGLEVEL_WARN, "Missing property to set correct basedate for exception"); } else { $basedate = Utils::ExtractBaseDate($props[$meetingrequestproperties["goidtag"]], $props[$meetingrequestproperties["recurStartTime"]]); $message->meetingrequest->recurrenceid = $this->getGMTTimeByTZ($basedate, $tz); } } } // Organizer is the sender $message->meetingrequest->organizer = $message->from; // Process recurrence if (isset($props[$meetingrequestproperties["isrecurringtag"]]) && $props[$meetingrequestproperties["isrecurringtag"]]) { $myrec = new SyncMeetingRequestRecurrence(); // get recurrence -> put $message->meetingrequest as message so the 'alldayevent' is set correctly $this->getRecurrence($mapimessage, $props, $message->meetingrequest, $myrec, $tz); $message->meetingrequest->recurrences = array($myrec); } // Force the 'alldayevent' in the object at all times. (non-existent == 0) if (!isset($message->meetingrequest->alldayevent) || $message->meetingrequest->alldayevent == "") { $message->meetingrequest->alldayevent = 0; } // Instancetype // 0 = single appointment // 1 = master recurring appointment // 2 = single instance of recurring appointment // 3 = exception of recurring appointment $message->meetingrequest->instancetype = 0; if (isset($props[$meetingrequestproperties["isrecurringtag"]]) && $props[$meetingrequestproperties["isrecurringtag"]] == 1) { $message->meetingrequest->instancetype = 1; } else { if ((!isset($props[$meetingrequestproperties["isrecurringtag"]]) || $props[$meetingrequestproperties["isrecurringtag"]] == 0) && isset($message->meetingrequest->recurrenceid)) { if (isset($props[$meetingrequestproperties["appSeqNr"]]) && $props[$meetingrequestproperties["appSeqNr"]] == 0) { $message->meetingrequest->instancetype = 2; } else { $message->meetingrequest->instancetype = 3; } } } // Disable reminder if it is off if (!isset($props[$meetingrequestproperties["reminderset"]]) || $props[$meetingrequestproperties["reminderset"]] == false) { $message->meetingrequest->reminder = ""; } else { ///set the default reminder time to seconds if ($props[$meetingrequestproperties["remindertime"]] == 0x5ae980e1) { $message->meetingrequest->reminder = 900; } else { $message->meetingrequest->reminder = $props[$meetingrequestproperties["remindertime"]] * 60; } } // Set sensitivity to 0 if missing if (!isset($message->meetingrequest->sensitivity)) { $message->meetingrequest->sensitivity = 0; } // if a meeting request response hasn't been processed yet, // do it so that the attendee status is updated on the mobile if (!isset($messageprops[$emailproperties["processed"]])) { $req = new Meetingrequest($this->store, $mapimessage, $this->session); if ($req->isMeetingRequestResponse()) { $req->processMeetingRequestResponse(); } if ($req->isMeetingCancellation()) { $req->processMeetingCancellation(); } } } // Add attachments $attachtable = mapi_message_getattachmenttable($mapimessage); $rows = mapi_table_queryallrows($attachtable, array(PR_ATTACH_NUM)); $entryid = bin2hex($messageprops[$emailproperties["entryid"]]); foreach ($rows as $row) { if (isset($row[PR_ATTACH_NUM])) { $mapiattach = mapi_message_openattach($mapimessage, $row[PR_ATTACH_NUM]); $attachprops = mapi_getprops($mapiattach, array(PR_ATTACH_LONG_FILENAME, PR_ATTACH_FILENAME, PR_ATTACHMENT_HIDDEN, PR_ATTACH_CONTENT_ID, PR_ATTACH_CONTENT_ID_W, PR_ATTACH_MIME_TAG, PR_ATTACH_MIME_TAG_W)); $stream = mapi_openpropertytostream($mapiattach, PR_ATTACH_DATA_BIN); if ($stream) { $stat = mapi_stream_stat($stream); if (Request::GetProtocolVersion() >= 12.0) { $attach = new SyncBaseAttachment(); } else { $attach = new SyncAttachment(); } // the displayname is handled equal for all AS versions $attach->displayname = w2u(isset($attachprops[PR_ATTACH_LONG_FILENAME]) ? $attachprops[PR_ATTACH_LONG_FILENAME] : (isset($attachprops[PR_ATTACH_FILENAME]) ? $attachprops[PR_ATTACH_FILENAME] : "attachment.bin")); // fix attachment name in case of inline images if ($attach->displayname == "inline.txt" && (isset($attachprops[PR_ATTACH_MIME_TAG]) || $attachprops[PR_ATTACH_MIME_TAG_W])) { $mimetype = isset($attachprops[PR_ATTACH_MIME_TAG]) ? $attachprops[PR_ATTACH_MIME_TAG] : $attachprops[PR_ATTACH_MIME_TAG_W]; $mime = explode("/", $mimetype); if (count($mime) == 2 && $mime[0] == "image") { $attach->displayname = "inline." . $mime[1]; } } // set AS version specific parameters if (Request::GetProtocolVersion() >= 12.0) { $attach->filereference = $entryid . ":" . $row[PR_ATTACH_NUM]; $attach->method = 1; $attach->estimatedDataSize = $stat["cb"]; if (isset($attachprops[PR_ATTACH_CONTENT_ID]) && $attachprops[PR_ATTACH_CONTENT_ID]) { $attach->contentid = $attachprops[PR_ATTACH_CONTENT_ID]; } if (!isset($attach->contentid) && isset($attachprops[PR_ATTACH_CONTENT_ID_W]) && $attachprops[PR_ATTACH_CONTENT_ID_W]) { $attach->contentid = $attachprops[PR_ATTACH_CONTENT_ID_W]; } if (isset($attachprops[PR_ATTACHMENT_HIDDEN]) && $attachprops[PR_ATTACHMENT_HIDDEN]) { $attach->isinline = 1; } if (!isset($message->asattachments)) { $message->asattachments = array(); } array_push($message->asattachments, $attach); } else { $attach->attsize = $stat["cb"]; $attach->attname = $entryid . ":" . $row[PR_ATTACH_NUM]; if (!isset($message->attachments)) { $message->attachments = array(); } array_push($message->attachments, $attach); } } } } // Get To/Cc as SMTP addresses (this is different from displayto and displaycc because we are putting // in the SMTP addresses as well, while displayto and displaycc could just contain the display names $message->to = array(); $message->cc = array(); $reciptable = mapi_message_getrecipienttable($mapimessage); $rows = mapi_table_queryallrows($reciptable, array(PR_RECIPIENT_TYPE, PR_DISPLAY_NAME, PR_ADDRTYPE, PR_EMAIL_ADDRESS, PR_SMTP_ADDRESS, PR_ENTRYID)); foreach ($rows as $row) { $address = ""; $fulladdr = ""; $addrtype = isset($row[PR_ADDRTYPE]) ? $row[PR_ADDRTYPE] : ""; if (isset($row[PR_SMTP_ADDRESS])) { $address = $row[PR_SMTP_ADDRESS]; } elseif ($addrtype == "SMTP" && isset($row[PR_EMAIL_ADDRESS])) { $address = $row[PR_EMAIL_ADDRESS]; } elseif ($addrtype == "ZARAFA" && isset($row[PR_ENTRYID])) { $address = $this->getSMTPAddressFromEntryID($row[PR_ENTRYID]); } $name = isset($row[PR_DISPLAY_NAME]) ? $row[PR_DISPLAY_NAME] : ""; if ($name == "" || $name == $address) { $fulladdr = w2u($address); } else { if (substr($name, 0, 1) != '"' && substr($name, -1) != '"') { $fulladdr = "\"" . w2u($name) . "\" <" . w2u($address) . ">"; } else { $fulladdr = w2u($name) . "<" . w2u($address) . ">"; } } if ($row[PR_RECIPIENT_TYPE] == MAPI_TO) { array_push($message->to, $fulladdr); } else { if ($row[PR_RECIPIENT_TYPE] == MAPI_CC) { array_push($message->cc, $fulladdr); } } } if (is_array($message->to) && !empty($message->to)) { $message->to = implode(", ", $message->to); } if (is_array($message->cc) && !empty($message->cc)) { $message->cc = implode(", ", $message->cc); } // without importance some mobiles assume "0" (low) - Mantis #439 if (!isset($message->importance)) { $message->importance = IMPORTANCE_NORMAL; } //TODO contentclass and nativebodytype and internetcpid if (!isset($message->internetcpid)) { $message->internetcpid = defined('STORE_INTERNET_CPID') ? constant('STORE_INTERNET_CPID') : INTERNET_CPID_WINDOWS1252; } $this->setFlag($mapimessage, $message); $message->contentclass = DEFAULT_EMAIL_CONTENTCLASS; if (!isset($message->nativebodytype)) { $message->nativebodytype = $this->getNativeBodyType($messageprops); } return $message; }
/** * Function which clones current occurrence and sets appropriate properties. * The original recurring item is moved to next occurrence. *@param boolean $markComplete true if existing occurrence has to be mark complete else false. */ function regenerateTask($markComplete) { // Get all properties $taskItemProps = mapi_getprops($this->message); if (isset($this->action["subject"])) { $taskItemProps[$this->proptags["subject"]] = $this->action["subject"]; } if (isset($this->action["importance"])) { $taskItemProps[$this->proptags["importance"]] = $this->action["importance"]; } if (isset($this->action["startdate"])) { $taskItemProps[$this->proptags["startdate"]] = $this->action["startdate"]; $taskItemProps[$this->proptags["commonstart"]] = $this->action["startdate"]; } if (isset($this->action["duedate"])) { $taskItemProps[$this->proptags["duedate"]] = $this->action["duedate"]; $taskItemProps[$this->proptags["commonend"]] = $this->action["duedate"]; } $folder = mapi_msgstore_openentry($this->store, $taskItemProps[PR_PARENT_ENTRYID]); $newMessage = mapi_folder_createmessage($folder); $taskItemProps[$this->proptags["status"]] = $markComplete ? olTaskComplete : olTaskNotStarted; $taskItemProps[$this->proptags["complete"]] = $markComplete; $taskItemProps[$this->proptags["percent_complete"]] = $markComplete ? 1 : 0; // This occurrence has been marked as 'Complete' so disable reminder if ($markComplete) { $taskItemProps[$this->proptags["reset_reminder"]] = false; $taskItemProps[$this->proptags["reminder"]] = false; $taskItemProps[$this->proptags["datecompleted"]] = $this->action["datecompleted"]; unset($this->action[$this->proptags['datecompleted']]); } // Recurrence ends for this item $taskItemProps[$this->proptags["dead_occurrence"]] = true; $taskItemProps[$this->proptags["task_f_creator"]] = true; //OL props $taskItemProps[$this->proptags["side_effects"]] = 1296; $taskItemProps[$this->proptags["icon_index"]] = 1280; // Copy recipients $recipienttable = mapi_message_getrecipienttable($this->message); $recipients = mapi_table_queryallrows($recipienttable, array(PR_ENTRYID, PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_RECIPIENT_ENTRYID, PR_RECIPIENT_TYPE, PR_SEND_INTERNET_ENCODING, PR_SEND_RICH_INFO, PR_RECIPIENT_DISPLAY_NAME, PR_ADDRTYPE, PR_DISPLAY_TYPE, PR_RECIPIENT_TRACKSTATUS, PR_RECIPIENT_TRACKSTATUS_TIME, PR_RECIPIENT_FLAGS, PR_ROWID)); $copy_to_recipientTable = mapi_message_getrecipienttable($newMessage); $copy_to_recipientRows = mapi_table_queryallrows($copy_to_recipientTable, array(PR_ROWID)); foreach ($copy_to_recipientRows as $recipient) { mapi_message_modifyrecipients($newMessage, MODRECIP_REMOVE, array($recipient)); } mapi_message_modifyrecipients($newMessage, MODRECIP_ADD, $recipients); // Copy attachments $attachmentTable = mapi_message_getattachmenttable($this->message); if ($attachmentTable) { $attachments = mapi_table_queryallrows($attachmentTable, array(PR_ATTACH_NUM, PR_ATTACH_SIZE, PR_ATTACH_LONG_FILENAME, PR_ATTACHMENT_HIDDEN, PR_DISPLAY_NAME, PR_ATTACH_METHOD)); foreach ($attachments as $attach_props) { $attach_old = mapi_message_openattach($this->message, (int) $attach_props[PR_ATTACH_NUM]); $attach_newResourceMsg = mapi_message_createattach($newMessage); mapi_copyto($attach_old, array(), array(), $attach_newResourceMsg, 0); mapi_savechanges($attach_newResourceMsg); } } mapi_setprops($newMessage, $taskItemProps); mapi_savechanges($newMessage); // Update body of original message $msgbody = mapi_message_openproperty($this->message, PR_BODY); $msgbody = trim($this->windows1252_to_utf8($msgbody), ""); $separator = "------------\r\n"; if (!empty($msgbody) && strrpos($msgbody, $separator) === false) { $msgbody = $separator . $msgbody; $stream = mapi_openpropertytostream($this->message, PR_BODY, MAPI_CREATE | MAPI_MODIFY); mapi_stream_setsize($stream, strlen($msgbody)); mapi_stream_write($stream, $msgbody); mapi_stream_commit($stream); } // We need these properties to notify client return mapi_getprops($newMessage, array(PR_ENTRYID, PR_PARENT_ENTRYID, PR_STORE_ENTRYID)); }
/** * Function which replaces attachments with copy_from in copy_to. *@param resource $copy_from MAPI_message from which attachments are to be copied. *@param resource $copy_to MAPI_message to which attachment are to be copied. *@param boolean $copyExceptions if true then all exceptions should also be sent as attachments */ function replaceAttachments($copy_from, $copy_to, $copyExceptions = true) { /* remove all old attachments */ $attachmentTable = mapi_message_getattachmenttable($copy_to); if ($attachmentTable) { $attachments = mapi_table_queryallrows($attachmentTable, array(PR_ATTACH_NUM, PR_ATTACH_METHOD, PR_EXCEPTION_STARTTIME)); foreach ($attachments as $attach_props) { /* remove exceptions too? */ if (!$copyExceptions && $attach_props[PR_ATTACH_METHOD] == 5 && isset($attach_props[PR_EXCEPTION_STARTTIME])) { continue; } mapi_message_deleteattach($copy_to, $attach_props[PR_ATTACH_NUM]); } } $attachmentTable = false; /* copy new attachments */ $attachmentTable = mapi_message_getattachmenttable($copy_from); if ($attachmentTable) { $attachments = mapi_table_queryallrows($attachmentTable, array(PR_ATTACH_NUM, PR_ATTACH_METHOD, PR_EXCEPTION_STARTTIME)); foreach ($attachments as $attach_props) { if (!$copyExceptions && $attach_props[PR_ATTACH_METHOD] == 5 && isset($attach_props[PR_EXCEPTION_STARTTIME])) { continue; } $attach_old = mapi_message_openattach($copy_from, (int) $attach_props[PR_ATTACH_NUM]); $attach_newResourceMsg = mapi_message_createattach($copy_to); mapi_copyto($attach_old, array(), array(), $attach_newResourceMsg, 0); mapi_savechanges($attach_newResourceMsg); } } }
/** * Get an exception attachment based on its basedate */ function getExceptionAttachment($base_date) { // Retrieve only embedded messages $attach_res = array(RES_AND, array(array(RES_PROPERTY, array(RELOP => RELOP_EQ, ULPROPTAG => PR_ATTACH_METHOD, VALUE => array(PR_ATTACH_METHOD => 5))))); $attachments = mapi_message_getattachmenttable($this->message); $attachRows = mapi_table_queryallrows($attachments, array(PR_ATTACH_NUM), $attach_res); if (is_array($attachRows)) { foreach ($attachRows as $attachRow) { $tempattach = mapi_message_openattach($this->message, $attachRow[PR_ATTACH_NUM]); $exception = mapi_attach_openobj($tempattach); $data = mapi_message_getprops($exception, array($this->proptags["basedate"])); if (isset($data[$this->proptags["basedate"]]) && $this->isSameDay($this->fromGMT($this->tz, $data[$this->proptags["basedate"]]), $base_date)) { return $tempattach; } } } return false; }
/** * Copies attachments from one message to another. * * @param MAPIMessage $toMessage * @param MAPIMessage $fromMessage * * @return void */ private function copyAttachments(&$toMessage, $fromMessage) { $attachtable = mapi_message_getattachmenttable($fromMessage); $rows = mapi_table_queryallrows($attachtable, array(PR_ATTACH_NUM)); foreach ($rows as $row) { if (isset($row[PR_ATTACH_NUM])) { $attach = mapi_message_openattach($fromMessage, $row[PR_ATTACH_NUM]); $newattach = mapi_message_createattach($toMessage); // Copy all attachments from old to new attachment $attachprops = mapi_getprops($attach); mapi_setprops($newattach, $attachprops); if (isset($attachprops[mapi_prop_tag(PT_ERROR, mapi_prop_id(PR_ATTACH_DATA_BIN))])) { // Data is in a stream $srcstream = mapi_openpropertytostream($attach, PR_ATTACH_DATA_BIN); $dststream = mapi_openpropertytostream($newattach, PR_ATTACH_DATA_BIN, MAPI_MODIFY | MAPI_CREATE); while (1) { $data = mapi_stream_read($srcstream, 4096); if (strlen($data) == 0) { break; } mapi_stream_write($dststream, $data); } mapi_stream_commit($dststream); } mapi_savechanges($newattach); } } }
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; }
function GetAttachmentData($attname) { list($folderid, $id, $attachnum) = explode(":", $attname); if (!isset($id) || !isset($attachnum)) { return false; } $sourcekey = hex2bin($id); $foldersourcekey = hex2bin($folderid); $entryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, $foldersourcekey, $sourcekey); if (!$entryid) { debugLog("Attachment requested for non-existing item {$attname}"); return false; } $message = mapi_msgstore_openentry($this->_defaultstore, $entryid); if (!$message) { debugLog("Unable to open item for attachment data for " . bin2hex($entryid)); return false; } $attach = mapi_message_openattach($message, $attachnum); if (!$attach) { debugLog("Unable to open attachment number {$attachnum}"); return false; } $stream = mapi_openpropertytostream($attach, PR_ATTACH_DATA_BIN); if (!$stream) { debugLog("Unable to open attachment data stream"); return false; } while (1) { $data = mapi_stream_read($stream, 4096); if (strlen($data) == 0) { break; } print $data; } return true; }
function GetAttachmentData($attname) { list($folderid, $id, $attachnum) = explode(":", $attname); if (!isset($id) || !isset($attachnum)) { return false; } $sourcekey = hex2bin($id); $foldersourcekey = hex2bin($folderid); $entryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, $foldersourcekey, $sourcekey); if (!$entryid) { debugLog("Attachment requested for non-existing item {$attname}"); return false; } $message = mapi_msgstore_openentry($this->_defaultstore, $entryid); if (!$message) { debugLog("Unable to open item for attachment data for " . bin2hex($entryid)); return false; } $attach = mapi_message_openattach($message, $attachnum); if (!$attach) { debugLog("Unable to open attachment number {$attachnum}"); return false; } $attachtable = mapi_message_getattachmenttable($message); // START CHANGED dw2412 EML Attachment $rows = mapi_table_queryallrows($attachtable, array(PR_ATTACH_NUM, PR_ATTACH_METHOD)); foreach ($rows as $row) { if (isset($row[PR_ATTACH_NUM]) && $row[PR_ATTACH_NUM] == $attachnum) { if ($row[PR_ATTACH_METHOD] == ATTACH_EMBEDDED_MSG) { $stream = buildEMLAttachment($attach); } else { $stream = mapi_openpropertytostream($attach, PR_ATTACH_DATA_BIN); } } } // END CHANGED dw2412 EML Attachment if (!$stream) { debugLog("Unable to open attachment data stream"); return false; } while (1) { $data = mapi_stream_read($stream, 4096); if (strlen($data) == 0) { break; } print $data; } return true; }
function getEmbeddedTask($message) { $table = mapi_message_getattachmenttable($message); $rows = mapi_table_queryallrows($table, array(PR_ATTACH_NUM)); // Assume only one attachment if (empty($rows)) { return false; } $attach = mapi_message_openattach($message, $rows[0][PR_ATTACH_NUM]); $message = mapi_openproperty($attach, PR_ATTACH_DATA_OBJ, IID_IMessage, 0, 0); return $message; }
/** * Reads an email object from MAPI * * @param mixed $mapimessage * @param ContentParameters $contentparameters * * @access private * @return SyncEmail */ private function getEmail($mapimessage, $contentparameters) { // This workaround fixes ZP-729 and still works with Outlook. // FIXME: It should be properly fixed when refactoring. $bpReturnType = Utils::GetBodyPreferenceBestMatch($contentparameters->GetBodyPreference()); if ($contentparameters->GetMimeSupport() == SYNC_MIMESUPPORT_NEVER || ($key = array_search(SYNC_BODYPREFERENCE_MIME, $contentparameters->GetBodyPreference()) === false) || $bpReturnType != SYNC_BODYPREFERENCE_MIME) { MAPIUtils::ParseSmime($this->session, $this->store, $this->getAddressbook(), $mapimessage); } $message = new SyncMail(); $this->getPropsFromMAPI($message, $mapimessage, MAPIMapping::GetEmailMapping()); $emailproperties = MAPIMapping::GetEmailProperties(); $messageprops = $this->getProps($mapimessage, $emailproperties); if (isset($messageprops[PR_SOURCE_KEY])) { $sourcekey = $messageprops[PR_SOURCE_KEY]; } else { return false; } //set the body according to contentparameters and supported AS version $this->setMessageBody($mapimessage, $contentparameters, $message); $fromname = $fromaddr = ""; if (isset($messageprops[$emailproperties["representingname"]])) { // remove encapsulating double quotes from the representingname $fromname = preg_replace('/^\\"(.*)\\"$/', "\${1}", $messageprops[$emailproperties["representingname"]]); } if (isset($messageprops[$emailproperties["representingentryid"]])) { $fromaddr = $this->getSMTPAddressFromEntryID($messageprops[$emailproperties["representingentryid"]]); } if ($fromname == $fromaddr) { $fromname = ""; } if ($fromname) { $from = "\"" . w2u($fromname) . "\" <" . w2u($fromaddr) . ">"; } else { //START CHANGED dw2412 HTC shows "error" if sender name is unknown $from = "\"" . w2u($fromaddr) . "\" <" . w2u($fromaddr) . ">"; } //END CHANGED dw2412 HTC shows "error" if sender name is unknown $message->from = $from; // process Meeting Requests if (isset($message->messageclass) && strpos($message->messageclass, "IPM.Schedule.Meeting") === 0) { $message->meetingrequest = new SyncMeetingRequest(); $this->getPropsFromMAPI($message->meetingrequest, $mapimessage, MAPIMapping::GetMeetingRequestMapping()); $meetingrequestproperties = MAPIMapping::GetMeetingRequestProperties(); $props = $this->getProps($mapimessage, $meetingrequestproperties); // Get the GOID if (isset($props[$meetingrequestproperties["goidtag"]])) { // GlobalObjId support was removed in AS 16.0 if (Request::IsGlobalObjIdHexClient()) { $message->meetingrequest->globalobjid = strtoupper(bin2hex($props[$meetingrequestproperties["goidtag"]])); } else { $message->meetingrequest->globalobjid = base64_encode($props[$meetingrequestproperties["goidtag"]]); } } // Set Timezone if (isset($props[$meetingrequestproperties["timezonetag"]])) { $tz = $this->getTZFromMAPIBlob($props[$meetingrequestproperties["timezonetag"]]); } else { $tz = $this->getGMTTZ(); } $message->meetingrequest->timezone = base64_encode(TimezoneUtil::GetSyncBlobFromTZ($tz)); // send basedate if exception if (isset($props[$meetingrequestproperties["recReplTime"]]) || isset($props[$meetingrequestproperties["lidIsException"]]) && $props[$meetingrequestproperties["lidIsException"]] == true) { if (isset($props[$meetingrequestproperties["recReplTime"]])) { $basedate = $props[$meetingrequestproperties["recReplTime"]]; $message->meetingrequest->recurrenceid = $this->getGMTTimeByTZ($basedate, $this->getGMTTZ()); } else { if (!isset($props[$meetingrequestproperties["goidtag"]]) || !isset($props[$meetingrequestproperties["recurStartTime"]]) || !isset($props[$meetingrequestproperties["timezonetag"]])) { ZLog::Write(LOGLEVEL_WARN, "Missing property to set correct basedate for exception"); } else { $basedate = Utils::ExtractBaseDate($props[$meetingrequestproperties["goidtag"]], $props[$meetingrequestproperties["recurStartTime"]]); $message->meetingrequest->recurrenceid = $this->getGMTTimeByTZ($basedate, $tz); } } } // Organizer is the sender if (strpos($message->messageclass, "IPM.Schedule.Meeting.Resp") === 0) { $message->meetingrequest->organizer = $message->to; } else { $message->meetingrequest->organizer = $message->from; } // Process recurrence if (isset($props[$meetingrequestproperties["isrecurringtag"]]) && $props[$meetingrequestproperties["isrecurringtag"]]) { $myrec = new SyncMeetingRequestRecurrence(); // get recurrence -> put $message->meetingrequest as message so the 'alldayevent' is set correctly $this->getRecurrence($mapimessage, $props, $message->meetingrequest, $myrec, $tz); $message->meetingrequest->recurrences = array($myrec); } // Force the 'alldayevent' in the object at all times. (non-existent == 0) if (!isset($message->meetingrequest->alldayevent) || $message->meetingrequest->alldayevent == "") { $message->meetingrequest->alldayevent = 0; } // Instancetype // 0 = single appointment // 1 = master recurring appointment // 2 = single instance of recurring appointment // 3 = exception of recurring appointment $message->meetingrequest->instancetype = 0; if (isset($props[$meetingrequestproperties["isrecurringtag"]]) && $props[$meetingrequestproperties["isrecurringtag"]] == 1) { $message->meetingrequest->instancetype = 1; } else { if ((!isset($props[$meetingrequestproperties["isrecurringtag"]]) || $props[$meetingrequestproperties["isrecurringtag"]] == 0) && isset($message->meetingrequest->recurrenceid)) { if (isset($props[$meetingrequestproperties["appSeqNr"]]) && $props[$meetingrequestproperties["appSeqNr"]] == 0) { $message->meetingrequest->instancetype = 2; } else { $message->meetingrequest->instancetype = 3; } } } // Disable reminder if it is off if (!isset($props[$meetingrequestproperties["reminderset"]]) || $props[$meetingrequestproperties["reminderset"]] == false) { $message->meetingrequest->reminder = ""; } else { ///set the default reminder time to seconds if ($props[$meetingrequestproperties["remindertime"]] == 0x5ae980e1) { $message->meetingrequest->reminder = 900; } else { $message->meetingrequest->reminder = $props[$meetingrequestproperties["remindertime"]] * 60; } } // Set sensitivity to 0 if missing if (!isset($message->meetingrequest->sensitivity)) { $message->meetingrequest->sensitivity = 0; } // If the user is working from a location other than the office the busystatus should be interpreted as free. if (isset($message->meetingrequest->busystatus) && $message->meetingrequest->busystatus == fbWorkingElsewhere) { $message->meetingrequest->busystatus = fbFree; } // If the busystatus has the value of -1, we should be interpreted as tentative (1) / ZP-581 if (isset($message->meetingrequest->busystatus) && $message->meetingrequest->busystatus == -1) { $message->meetingrequest->busystatus = fbTentative; } // if a meeting request response hasn't been processed yet, // do it so that the attendee status is updated on the mobile if (!isset($messageprops[$emailproperties["processed"]])) { // check if we are not sending the MR so we can process it - ZP-581 $cuser = ZPush::GetBackend()->GetUserDetails(ZPush::GetBackend()->GetCurrentUsername()); if (isset($cuser["emailaddress"]) && $cuser["emailaddress"] != $fromaddr) { $req = new Meetingrequest($this->store, $mapimessage, $this->session); if ($req->isMeetingRequestResponse()) { $req->processMeetingRequestResponse(); } if ($req->isMeetingCancellation()) { $req->processMeetingCancellation(); } } } $message->contentclass = DEFAULT_CALENDAR_CONTENTCLASS; } // Add attachments $attachtable = mapi_message_getattachmenttable($mapimessage); $rows = mapi_table_queryallrows($attachtable, array(PR_ATTACH_NUM)); $entryid = bin2hex($messageprops[$emailproperties["entryid"]]); $parentSourcekey = bin2hex($messageprops[$emailproperties["parentsourcekey"]]); foreach ($rows as $row) { if (isset($row[PR_ATTACH_NUM])) { if (Request::GetProtocolVersion() >= 12.0) { $attach = new SyncBaseAttachment(); } else { $attach = new SyncAttachment(); } $mapiattach = mapi_message_openattach($mapimessage, $row[PR_ATTACH_NUM]); $attachprops = mapi_getprops($mapiattach, array(PR_ATTACH_LONG_FILENAME, PR_ATTACH_FILENAME, PR_ATTACHMENT_HIDDEN, PR_ATTACH_CONTENT_ID, PR_ATTACH_CONTENT_ID_W, PR_ATTACH_MIME_TAG, PR_ATTACH_MIME_TAG_W, PR_ATTACH_METHOD, PR_DISPLAY_NAME, PR_DISPLAY_NAME_W, PR_ATTACH_SIZE)); if (isset($attachprops[PR_ATTACH_MIME_TAG]) && strpos(strtolower($attachprops[PR_ATTACH_MIME_TAG]), 'signed') !== false || isset($attachprops[PR_ATTACH_MIME_TAG_W]) && strpos(strtolower($attachprops[PR_ATTACH_MIME_TAG_W]), 'signed') !== false) { continue; } // the displayname is handled equaly for all AS versions $attach->displayname = w2u(isset($attachprops[PR_ATTACH_LONG_FILENAME]) ? $attachprops[PR_ATTACH_LONG_FILENAME] : (isset($attachprops[PR_ATTACH_FILENAME]) ? $attachprops[PR_ATTACH_FILENAME] : (isset($attachprops[PR_DISPLAY_NAME]) ? $attachprops[PR_DISPLAY_NAME] : "attachment.bin"))); // fix attachment name in case of inline images if ($attach->displayname == "inline.txt" && (isset($attachprops[PR_ATTACH_MIME_TAG]) || $attachprops[PR_ATTACH_MIME_TAG_W])) { $mimetype = isset($attachprops[PR_ATTACH_MIME_TAG]) ? $attachprops[PR_ATTACH_MIME_TAG] : $attachprops[PR_ATTACH_MIME_TAG_W]; $mime = explode("/", $mimetype); if (count($mime) == 2 && $mime[0] == "image") { $attach->displayname = "inline." . $mime[1]; } } // set AS version specific parameters if (Request::GetProtocolVersion() >= 12.0) { $attach->filereference = sprintf("%s:%s:%s", $entryid, $row[PR_ATTACH_NUM], $parentSourcekey); $attach->method = isset($attachprops[PR_ATTACH_METHOD]) ? $attachprops[PR_ATTACH_METHOD] : ATTACH_BY_VALUE; // if displayname does not have the eml extension for embedde messages, android and WP devices won't open it if ($attach->method == ATTACH_EMBEDDED_MSG) { if (strtolower(substr($attach->displayname, -4)) != '.eml') { $attach->displayname .= '.eml'; } } // android devices require attachment size in order to display an attachment properly if (!isset($attachprops[PR_ATTACH_SIZE])) { $stream = mapi_openpropertytostream($mapiattach, PR_ATTACH_DATA_BIN); $stat = mapi_stream_stat($stream); $attach->estimatedDataSize = $stat['cb']; } else { $attach->estimatedDataSize = $attachprops[PR_ATTACH_SIZE]; } if (isset($attachprops[PR_ATTACH_CONTENT_ID]) && $attachprops[PR_ATTACH_CONTENT_ID]) { $attach->contentid = $attachprops[PR_ATTACH_CONTENT_ID]; } if (!isset($attach->contentid) && isset($attachprops[PR_ATTACH_CONTENT_ID_W]) && $attachprops[PR_ATTACH_CONTENT_ID_W]) { $attach->contentid = $attachprops[PR_ATTACH_CONTENT_ID_W]; } if (isset($attachprops[PR_ATTACHMENT_HIDDEN]) && $attachprops[PR_ATTACHMENT_HIDDEN]) { $attach->isinline = 1; } if (!isset($message->asattachments)) { $message->asattachments = array(); } array_push($message->asattachments, $attach); } else { $attach->attsize = $attachprops[PR_ATTACH_SIZE]; $attach->attname = sprintf("%s:%s:%s", $entryid, $row[PR_ATTACH_NUM], $parentSourcekey); if (!isset($message->attachments)) { $message->attachments = array(); } array_push($message->attachments, $attach); } } } // Get To/Cc as SMTP addresses (this is different from displayto and displaycc because we are putting // in the SMTP addresses as well, while displayto and displaycc could just contain the display names $message->to = array(); $message->cc = array(); $reciptable = mapi_message_getrecipienttable($mapimessage); $rows = mapi_table_queryallrows($reciptable, array(PR_RECIPIENT_TYPE, PR_DISPLAY_NAME, PR_ADDRTYPE, PR_EMAIL_ADDRESS, PR_SMTP_ADDRESS, PR_ENTRYID)); foreach ($rows as $row) { $address = ""; $fulladdr = ""; $addrtype = isset($row[PR_ADDRTYPE]) ? $row[PR_ADDRTYPE] : ""; if (isset($row[PR_SMTP_ADDRESS])) { $address = $row[PR_SMTP_ADDRESS]; } elseif ($addrtype == "SMTP" && isset($row[PR_EMAIL_ADDRESS])) { $address = $row[PR_EMAIL_ADDRESS]; } elseif ($addrtype == "ZARAFA" && isset($row[PR_ENTRYID])) { $address = $this->getSMTPAddressFromEntryID($row[PR_ENTRYID]); } $name = isset($row[PR_DISPLAY_NAME]) ? $row[PR_DISPLAY_NAME] : ""; if ($name == "" || $name == $address) { $fulladdr = w2u($address); } else { if (substr($name, 0, 1) != '"' && substr($name, -1) != '"') { $fulladdr = "\"" . w2u($name) . "\" <" . w2u($address) . ">"; } else { $fulladdr = w2u($name) . "<" . w2u($address) . ">"; } } if ($row[PR_RECIPIENT_TYPE] == MAPI_TO) { array_push($message->to, $fulladdr); } else { if ($row[PR_RECIPIENT_TYPE] == MAPI_CC) { array_push($message->cc, $fulladdr); } } } if (is_array($message->to) && !empty($message->to)) { $message->to = implode(", ", $message->to); } if (is_array($message->cc) && !empty($message->cc)) { $message->cc = implode(", ", $message->cc); } // without importance some mobiles assume "0" (low) - Mantis #439 if (!isset($message->importance)) { $message->importance = IMPORTANCE_NORMAL; } //TODO contentclass and nativebodytype and internetcpid if (!isset($message->internetcpid)) { $message->internetcpid = defined('STORE_INTERNET_CPID') ? constant('STORE_INTERNET_CPID') : INTERNET_CPID_WINDOWS1252; } $this->setFlag($mapimessage, $message); if (!isset($message->contentclass)) { $message->contentclass = DEFAULT_EMAIL_CONTENTCLASS; } if (!isset($message->nativebodytype)) { $message->nativebodytype = $this->getNativeBodyType($messageprops); } // reply, reply to all, forward flags if (isset($message->lastverbexecuted) && $message->lastverbexecuted) { $message->lastverbexecuted = Utils::GetLastVerbExecuted($message->lastverbexecuted); } return $message; }
/** * Convert vObject to an array of properties * @param array $properties * @param object $vCard */ public function propertiesToVObject($contact, &$vCard) { $this->logger->debug("Generating contact vCard from properties"); $p = $this->bridge->getExtendedProperties(); $contactProperties = mapi_getprops($contact); // $this->bridge->getProperties($contactId); $dump = print_r($contactProperties, true); $this->logger->trace("Contact properties:\n{$contactProperties}"); // Version check switch ($this->version) { case 2: $vCard->add('VERSION', '2.1'); break; case 3: $vCard->add('VERSION', '3.0'); break; case 4: $vCard->add('VERSION', '4.0'); break; default: $this->logger->fatal("Unrecognised VCard version: " . $this->version); return; } // Private contact ? if (isset($contactProperties[$p['private']]) && $contactProperties[$p['private']]) { $vCard->add('CLASS', 'PRIVATE'); // Not in VCARD 4.0 but keep it for compatibility } // Mandatory FN $this->setVCard($vCard, 'FN', $contactProperties, $p['display_name']); // Contact name and pro information // N property /* Special note: The structured property value corresponds, in sequence, to the Family Names (also known as surnames), Given Names, Additional Names, Honorific Prefixes, and Honorific Suffixes. The text components are separated by the SEMICOLON character (U+003B). Individual text components can include multiple text values separated by the COMMA character (U+002C). This property is based on the semantics of the X.520 individual name attributes [CCITT.X520.1988]. The property SHOULD be present in the vCard object when the name of the object the vCard represents follows the X.520 model. The SORT-AS parameter MAY be applied to this property. */ $contactInfos = array(); $contactInfos[] = isset($contactProperties[$p['surname']]) ? $contactProperties[$p['surname']] : ''; $contactInfos[] = isset($contactProperties[$p['given_name']]) ? $contactProperties[$p['given_name']] : ''; $contactInfos[] = isset($contactProperties[$p['middle_name']]) ? $contactProperties[$p['middle_name']] : ''; $contactInfos[] = isset($contactProperties[$p['display_name_prefix']]) ? $contactProperties[$p['display_name_prefix']] : ''; $contactInfos[] = isset($contactProperties[$p['generation']]) ? $contactProperties[$p['generation']] : ''; $element = new Sabre_VObject_Property("N"); $element->setValue(implode(';', $contactInfos)); // $element->offsetSet("SORT-AS", '"' . $contactProperties[$p['fileas']] . '"'); $vCard->add($element); $this->setVCard($vCard, 'SORT-AS', $contactProperties, $p['fileas']); $this->setVCard($vCard, 'NICKNAME', $contactProperties, $p['nickname']); $this->setVCard($vCard, 'TITLE', $contactProperties, $p['title']); $this->setVCard($vCard, 'ROLE', $contactProperties, $p['profession']); $this->setVCard($vCard, 'ORG', $contactProperties, $p['company_name']); $this->setVCard($vCard, 'OFFICE', $contactProperties, $p['office_location']); if ($this->version >= 4) { if (isset($contactProperties[$p['assistant']])) { if (!empty($contactProperties[$p['assistant']])) { $element = new Sabre_VObject_Property('RELATED'); $element->setValue($contactProperties[$p['assistant']]); $element->offsetSet('TYPE', 'assistant'); // Not RFC compliant $vCard->add($element); } } if (isset($contactProperties[$p['manager_name']])) { if (!empty($contactProperties[$p['manager_name']])) { $element = new Sabre_VObject_Property('RELATED'); $element->setValue($contactProperties[$p['manager_name']]); $element->offsetSet('TYPE', 'manager'); // Not RFC compliant $vCard->add($element); } } if (isset($contactProperties[$p['spouse_name']])) { if (!empty($contactProperties[$p['spouse_name']])) { $element = new Sabre_VObject_Property('RELATED'); $element->setValue($contactProperties[$p['spouse_name']]); $element->offsetSet('TYPE', 'spouse'); $vCard->add($element); } } } // older syntax - may be needed by some clients so keep it! $this->setVCard($vCard, 'X-MS-ASSISTANT', $contactProperties, $p['assistant']); $this->setVCard($vCard, 'X-MS-MANAGER', $contactProperties, $p['manager_name']); $this->setVCard($vCard, 'X-MS-SPOUSE', $contactProperties, $p['spouse_name']); // Dates if (isset($contactProperties[$p['birthday']]) && $contactProperties[$p['birthday']] > 0) { $vCard->add('BDAY', date(DATE_PATTERN, $contactProperties[$p['birthday']])); } if (isset($contactProperties[$p['wedding_anniversary']]) && $contactProperties[$p['wedding_anniversary']] > 0) { if ($this->version >= 4) { $vCard->add('ANNIVERSARY', date(DATE_PATTERN, $contactProperties[$p['wedding_anniversary']])); } else { $vCard->add('X-ANNIVERSARY', date(DATE_PATTERN, $contactProperties[$p['wedding_anniversary']])); } } // Telephone numbers // webaccess can handle 19 telephone numbers... $this->setVCard($vCard, 'TEL;TYPE=HOME,VOICE', $contactProperties, $p['home_telephone_number']); $this->setVCard($vCard, 'TEL;TYPE=HOME,VOICE', $contactProperties, $p['home2_telephone_number']); $this->setVCard($vCard, 'TEL;TYPE=CELL', $contactProperties, $p['cellular_telephone_number']); $this->setVCard($vCard, 'TEL;TYPE=WORK,VOICE', $contactProperties, $p['office_telephone_number']); $this->setVCard($vCard, 'TEL;TYPE=WORK,VOICE', $contactProperties, $p['business2_telephone_number']); $this->setVCard($vCard, 'TEL;TYPE=WORK,FAX', $contactProperties, $p['business_fax_number']); $this->setVCard($vCard, 'TEL;TYPE=HOME,FAX', $contactProperties, $p['home_fax_number']); $this->setVCard($vCard, 'TEL;TYPE=PAGER', $contactProperties, $p['pager_telephone_number']); $this->setVCard($vCard, 'TEL;TYPE=ISDN', $contactProperties, $p['isdn_number']); $this->setVCard($vCard, 'TEL;TYPE=WORK', $contactProperties, $p['company_telephone_number']); $this->setVCard($vCard, 'TEL;TYPE=CAR', $contactProperties, $p['car_telephone_number']); $this->setVCard($vCard, 'TEL;TYPE=SECR', $contactProperties, $p['assistant_telephone_number']); // There are unmatched telephone numbers in zarafa, use them! $unmatchedProperties = array("callback_telephone_number", "other_telephone_number", "primary_fax_number", "primary_telephone_number", "radio_telephone_number", "telex_telephone_number", "ttytdd_telephone_number"); if (in_array(DEFAULT_TELEPHONE_NUMBER_PROPERTY, $unmatchedProperties)) { // unmatched found a match! $this->setVCard($vCard, 'TEL', $contactProperties, $p[DEFAULT_TELEPHONE_NUMBER_PROPERTY]); } $this->setVCardAddress($vCard, 'HOME', $contactProperties, 'home'); $this->setVCardAddress($vCard, 'WORK', $contactProperties, 'business'); $this->setVCardAddress($vCard, 'OTHER', $contactProperties, 'other'); // emails for ($i = 1; $i <= 3; $i++) { if (isset($contactProperties[$p["email_address_{$i}"]])) { // Zarafa needs an email display name $emailProperty = new Sabre_VObject_Property('EMAIL', $contactProperties[$p["email_address_{$i}"]]); // Get display name $dn = isset($contactProperties[$p["email_address_display_name_{$i}"]]) ? $contactProperties[$p["email_address_display_name_{$i}"]] : $contactProperties[$p['display_name']]; $emailProperty->offsetSet("X-CN", '"' . $dn . '"'); $vCard->add($emailProperty); } } // URL and Instant Messenging (vCard 3.0 extension) $this->setVCard($vCard, 'URL', $contactProperties, $p["webpage"]); $this->setVCard($vCard, 'IMPP', $contactProperties, $p["im"]); // Categories $contactCategories = ''; if (isset($contactProperties[$p['categories']])) { if (is_array($contactProperties[$p['categories']])) { $contactCategories = implode(',', $contactProperties[$p['categories']]); } else { $contactCategories = $contactProperties[$p['categories']]; } } if ($contactCategories != '') { $vCard->add('CATEGORIES', $contactCategories); } // Contact picture? $hasattachProp = mapi_getprops($contact, array(PR_HASATTACH)); $photo = NULL; $photoMime = ''; if (isset($hasattachProp[PR_HASATTACH]) && $hasattachProp[PR_HASATTACH]) { $attachmentTable = mapi_message_getattachmenttable($contact); $attachments = mapi_table_queryallrows($attachmentTable, array(PR_ATTACH_NUM, PR_ATTACH_SIZE, PR_ATTACH_LONG_FILENAME, PR_ATTACH_FILENAME, PR_ATTACHMENT_HIDDEN, PR_DISPLAY_NAME, PR_ATTACH_METHOD, PR_ATTACH_CONTENT_ID, PR_ATTACH_MIME_TAG, PR_ATTACHMENT_CONTACTPHOTO, PR_EC_WA_ATTACHMENT_HIDDEN_OVERRIDE)); $dump = print_r($attachments, true); $this->logger->trace("Contact attachments:\n{$dump}"); foreach ($attachments as $attachmentRow) { if (isset($attachmentRow[PR_ATTACHMENT_CONTACTPHOTO]) && $attachmentRow[PR_ATTACHMENT_CONTACTPHOTO]) { $attach = mapi_message_openattach($contact, $attachmentRow[PR_ATTACH_NUM]); $photo = mapi_attach_openbin($attach, PR_ATTACH_DATA_BIN); if (isset($attachmentRow[PR_ATTACH_MIME_TAG])) { $photoMime = $attachmentRow[PR_ATTACH_MIME_TAG]; } else { $photoMime = 'image/jpeg'; } break; } } } if ($photo != NULL) { // SogoConnector does not like image/jpeg if ($photoMime == 'image/jpeg') { $photoMime = 'JPEG'; } $this->logger->trace("Adding contact picture to VCard"); $photoEncoded = base64_encode($photo); $photoProperty = new Sabre_VObject_Property('PHOTO', $photoEncoded); $photoProperty->offsetSet('TYPE', $photoMime); $photoProperty->offsetSet('ENCODING', 'b'); $vCard->add($photoProperty); } // Misc $vCard->add('UID', "urn:uuid:" . substr($contactProperties[PR_CARDDAV_URI], 0, -4)); // $this->entryIdToStr($contactProperties[PR_ENTRYID])); $this->setVCard($vCard, 'NOTE', $contactProperties, $p['notes']); $vCard->add('PRODID', VCARD_PRODUCT_ID); $vCard->add('REV', date('c', $contactProperties[$p['last_modification_time']])); }
/** * Copies attachments from one message to another. * * @param MAPIMessage $toMessage * @param MAPIMessage $fromMessage * * @return void */ private function copyAttachments(&$toMessage, $fromMessage) { $attachtable = mapi_message_getattachmenttable($fromMessage); $rows = mapi_table_queryallrows($attachtable, array(PR_ATTACH_NUM)); foreach ($rows as $row) { if (isset($row[PR_ATTACH_NUM])) { $attach = mapi_message_openattach($fromMessage, $row[PR_ATTACH_NUM]); $newattach = mapi_message_createattach($toMessage); mapi_copyto($attach, array(), array(), $newattach, 0); mapi_savechanges($newattach); } } }
/** * Get an exception attachment based on its basedate */ function getExceptionAttachment($base_date) { // Retrieve only exceptions which are stored as embedded messages $attach_res = array(RES_AND, array(array(RES_PROPERTY, array(RELOP => RELOP_EQ, ULPROPTAG => PR_ATTACH_METHOD, VALUE => array(PR_ATTACH_METHOD => ATTACH_EMBEDDED_MSG))))); $attachments = mapi_message_getattachmenttable($this->message); $attachRows = mapi_table_queryallrows($attachments, array(PR_ATTACH_NUM), $attach_res); if (is_array($attachRows)) { foreach ($attachRows as $attachRow) { $tempattach = mapi_message_openattach($this->message, $attachRow[PR_ATTACH_NUM]); $exception = mapi_attach_openobj($tempattach); $data = mapi_message_getprops($exception, array($this->proptags["basedate"])); if (!isset($data[$this->proptags["basedate"]])) { // if no basedate found then it could be embedded message so ignore it // we need proper restriction to exclude embedded messages aswell continue; } if ($this->isSameDay($this->fromGMT($this->tz, $data[$this->proptags["basedate"]]), $base_date)) { return $tempattach; } } } return false; }
/** * Function will be used to decode smime messages and convert it to normal messages. * * @param MAPISession $session * @param MAPIStore $store * @param MAPIAdressBook $addressBook * @param MAPIMessage $message smime message * * @access public * @return void */ public static function ParseSmime($session, $store, $addressBook, &$mapimessage) { $props = mapi_getprops($mapimessage, array(PR_MESSAGE_CLASS)); if (isset($props[PR_MESSAGE_CLASS]) && stripos($props[PR_MESSAGE_CLASS], 'IPM.Note.SMIME.MultipartSigned') !== false) { // this is a signed message. decode it. $attachTable = mapi_message_getattachmenttable($mapimessage); $rows = mapi_table_queryallrows($attachTable, array(PR_ATTACH_MIME_TAG, PR_ATTACH_NUM)); $attnum = false; foreach ($rows as $row) { if (isset($row[PR_ATTACH_MIME_TAG]) && $row[PR_ATTACH_MIME_TAG] == 'multipart/signed') { $attnum = $row[PR_ATTACH_NUM]; } } if ($attnum !== false) { $att = mapi_message_openattach($mapimessage, $attnum); $data = mapi_openproperty($att, PR_ATTACH_DATA_BIN); mapi_message_deleteattach($mapimessage, $attnum); mapi_inetmapi_imtomapi($session, $store, $addressBook, $mapimessage, $data, array("parse_smime_signed" => 1)); ZLog::Write(LOGLEVEL_DEBUG, "Convert a smime signed message to a normal message."); } mapi_setprops($mapimessage, array(PR_MESSAGE_CLASS => 'IPM.Note.SMIME.MultipartSigned')); } // TODO check if we need to do this for encrypted (and signed?) message as well }