/** * Sets all dependent properties for an email address * * @param string $emailAddress * @param string $displayName * @param int $cnt * @param array &$props * @param array &$properties * @param array &$nremails * @param int &$abprovidertype * * @access private * @return */ private function setEmailAddress($emailAddress, $displayName, $cnt, &$props, &$properties, &$nremails, &$abprovidertype) { if (isset($emailAddress)) { $name = isset($displayName) ? $displayName : $emailAddress; $props[$properties["emailaddress{$cnt}"]] = $emailAddress; $props[$properties["emailaddressdemail{$cnt}"]] = $emailAddress; $props[$properties["emailaddressdname{$cnt}"]] = $name; $props[$properties["emailaddresstype{$cnt}"]] = "SMTP"; $props[$properties["emailaddressentryid{$cnt}"]] = mapi_createoneoff($name, "SMTP", $emailAddress); $nremails[] = $cnt - 1; $abprovidertype |= 2 ^ $cnt - 1; } }
function SendMail($rfc822, $forward = false, $reply = false, $parent = false) { if (WBXML_DEBUG == true) { debugLog("SendMail: forward: {$forward} reply: {$reply} parent: {$parent}\n" . $rfc822); } $mimeParams = array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'charset' => 'utf-8'); $mimeObject = new Mail_mimeDecode($rfc822); $message = $mimeObject->decode($mimeParams); // Open the outbox and create the message there $storeprops = mapi_getprops($this->_defaultstore, array(PR_IPM_OUTBOX_ENTRYID, PR_IPM_SENTMAIL_ENTRYID)); if (!isset($storeprops[PR_IPM_OUTBOX_ENTRYID])) { debugLog("Outbox not found to create message"); return false; } $outbox = mapi_msgstore_openentry($this->_defaultstore, $storeprops[PR_IPM_OUTBOX_ENTRYID]); if (!$outbox) { debugLog("Unable to open outbox"); return false; } $mapimessage = mapi_folder_createmessage($outbox); mapi_setprops($mapimessage, array(PR_SUBJECT => u2wi(isset($message->headers["subject"]) ? $message->headers["subject"] : ""), PR_SENTMAIL_ENTRYID => $storeprops[PR_IPM_SENTMAIL_ENTRYID], PR_MESSAGE_CLASS => "IPM.Note", PR_MESSAGE_DELIVERY_TIME => time())); if (isset($message->headers["x-priority"])) { switch ($message->headers["x-priority"]) { case 1: case 2: $priority = PRIO_URGENT; $importance = IMPORTANCE_HIGH; break; case 4: case 5: $priority = PRIO_NONURGENT; $importance = IMPORTANCE_LOW; break; case 3: default: $priority = PRIO_NORMAL; $importance = IMPORTANCE_NORMAL; break; } mapi_setprops($mapimessage, array(PR_IMPORTANCE => $importance, PR_PRIORITY => $priority)); } $addresses = array(); $toaddr = $ccaddr = $bccaddr = array(); $Mail_RFC822 = new Mail_RFC822(); 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["bcc"])) { $bccaddr = $Mail_RFC822->parseAddressList($message->headers["bcc"]); } // Add recipients $recips = array(); if (isset($toaddr)) { foreach (array(MAPI_TO => $toaddr, MAPI_CC => $ccaddr, MAPI_BCC => $bccaddr) as $type => $addrlist) { foreach ($addrlist as $addr) { $mapirecip[PR_ADDRTYPE] = "SMTP"; $mapirecip[PR_EMAIL_ADDRESS] = $addr->mailbox . "@" . $addr->host; if (isset($addr->personal) && strlen($addr->personal) > 0) { $mapirecip[PR_DISPLAY_NAME] = u2wi($addr->personal); } else { $mapirecip[PR_DISPLAY_NAME] = $mapirecip[PR_EMAIL_ADDRESS]; } $mapirecip[PR_RECIPIENT_TYPE] = $type; $mapirecip[PR_ENTRYID] = mapi_createoneoff($mapirecip[PR_DISPLAY_NAME], $mapirecip[PR_ADDRTYPE], $mapirecip[PR_EMAIL_ADDRESS]); array_push($recips, $mapirecip); } } } mapi_message_modifyrecipients($mapimessage, 0, $recips); // Loop through message subparts. $body = ""; $body_html = ""; if ($message->ctype_primary == "multipart" && ($message->ctype_secondary == "mixed" || $message->ctype_secondary == "alternative")) { $mparts = $message->parts; for ($i = 0; $i < count($mparts); $i++) { $part = $mparts[$i]; // palm pre & iPhone send forwarded messages in another subpart which are also parsed if ($part->ctype_primary == "multipart" && ($part->ctype_secondary == "mixed" || $part->ctype_secondary == "alternative" || $part->ctype_secondary == "related")) { foreach ($part->parts as $spart) { $mparts[] = $spart; } continue; } // standard body if ($part->ctype_primary == "text" && $part->ctype_secondary == "plain" && isset($part->body) && (!isset($part->disposition) || $part->disposition != "attachment")) { $body .= u2wi($part->body); // assume only one text body } elseif ($part->ctype_primary == "text" && $part->ctype_secondary == "html") { $body_html .= u2wi($part->body); } elseif ($part->ctype_primary == "ms-tnef" || $part->ctype_secondary == "ms-tnef") { $zptnef = new ZPush_tnef($this->_defaultstore); $mapiprops = array(); $zptnef->extractProps($part->body, $mapiprops); if (is_array($mapiprops) && !empty($mapiprops)) { //check if it is a recurring item $tnefrecurr = GetPropIDFromString($this->_defaultstore, "PT_BOOLEAN:{6ED8DA90-450B-101B-98DA-00AA003F1305}:0x5"); if (isset($mapiprops[$tnefrecurr])) { $this->_handleRecurringItem($mapimessage, $mapiprops); } mapi_setprops($mapimessage, $mapiprops); } else { debugLog("TNEF: Mapi props array was empty"); } } elseif ($part->ctype_primary == "text" && $part->ctype_secondary == "calendar") { $zpical = new ZPush_ical($this->_defaultstore); $mapiprops = array(); $zpical->extractProps($part->body, $mapiprops); // iPhone sends a second ICS which we ignore if we can if (!isset($mapiprops[PR_MESSAGE_CLASS]) && strlen(trim($body)) == 0) { debugLog("Secondary iPhone response is being ignored!! Mail dropped!"); return true; } if (!checkMapiExtVersion("6.30") && is_array($mapiprops) && !empty($mapiprops)) { mapi_setprops($mapimessage, $mapiprops); } else { // store ics as attachment //see icalTimezoneFix function in compat.php for more information $part->body = icalTimezoneFix($part->body); $this->_storeAttachment($mapimessage, $part); debugLog("Sending ICS file as attachment"); } } else { $this->_storeAttachment($mapimessage, $part); } } } else { if ($message->ctype_primary == "text" && $message->ctype_secondary == "html") { $body_html .= u2wi($message->body); } else { $body = u2wi($message->body); } } // some devices only transmit a html body if (strlen($body) == 0 && strlen($body_html) > 0) { debugLog("only html body sent, transformed into plain text"); $body = strip_tags($body_html); } if ($forward) { $orig = $forward; } if ($reply) { $orig = $reply; } if (isset($orig) && $orig) { // Append the original text body for reply/forward $entryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($parent), hex2bin($orig)); $fwmessage = mapi_msgstore_openentry($this->_defaultstore, $entryid); if ($fwmessage) { //update icon when forwarding or replying message if ($forward) { mapi_setprops($fwmessage, array(PR_ICON_INDEX => 262)); } elseif ($reply) { mapi_setprops($fwmessage, array(PR_ICON_INDEX => 261)); } mapi_savechanges($fwmessage); $stream = mapi_openproperty($fwmessage, PR_BODY, IID_IStream, 0, 0); $fwbody = ""; while (1) { $data = mapi_stream_read($stream, 1024); if (strlen($data) == 0) { break; } $fwbody .= $data; } $stream = mapi_openproperty($fwmessage, PR_HTML, IID_IStream, 0, 0); $fwbody_html = ""; while (1) { $data = mapi_stream_read($stream, 1024); if (strlen($data) == 0) { break; } $fwbody_html .= $data; } if ($forward) { // During a forward, we have to add the forward header ourselves. This is because // normally the forwarded message is added as an attachment. However, we don't want this // because it would be rather complicated to copy over the entire original message due // to the lack of IMessage::CopyTo .. $fwmessageprops = mapi_getprops($fwmessage, array(PR_SENT_REPRESENTING_NAME, PR_DISPLAY_TO, PR_DISPLAY_CC, PR_SUBJECT, PR_CLIENT_SUBMIT_TIME)); $fwheader = "\r\n\r\n"; $fwheader .= "-----Original Message-----\r\n"; if (isset($fwmessageprops[PR_SENT_REPRESENTING_NAME])) { $fwheader .= "From: " . $fwmessageprops[PR_SENT_REPRESENTING_NAME] . "\r\n"; } if (isset($fwmessageprops[PR_DISPLAY_TO]) && strlen($fwmessageprops[PR_DISPLAY_TO]) > 0) { $fwheader .= "To: " . $fwmessageprops[PR_DISPLAY_TO] . "\r\n"; } if (isset($fwmessageprops[PR_DISPLAY_CC]) && strlen($fwmessageprops[PR_DISPLAY_CC]) > 0) { $fwheader .= "Cc: " . $fwmessageprops[PR_DISPLAY_CC] . "\r\n"; } if (isset($fwmessageprops[PR_CLIENT_SUBMIT_TIME])) { $fwheader .= "Sent: " . strftime("%x %X", $fwmessageprops[PR_CLIENT_SUBMIT_TIME]) . "\r\n"; } if (isset($fwmessageprops[PR_SUBJECT])) { $fwheader .= "Subject: " . $fwmessageprops[PR_SUBJECT] . "\r\n"; } $fwheader .= "\r\n"; // add fwheader to body and body_html $body .= $fwheader; if (strlen($body_html) > 0) { $body_html .= str_ireplace("\r\n", "<br>", $fwheader); } } if (strlen($body) > 0) { $body .= $fwbody; } if (strlen($body_html) > 0) { $body_html .= $fwbody_html; } } else { debugLog("Unable to open item with id {$orig} for forward/reply"); } } if ($forward) { // Add attachments from the original message in a forward $entryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($parent), hex2bin($orig)); $fwmessage = mapi_msgstore_openentry($this->_defaultstore, $entryid); $attachtable = mapi_message_getattachmenttable($fwmessage); $rows = mapi_table_queryallrows($attachtable, array(PR_ATTACH_NUM)); foreach ($rows as $row) { if (isset($row[PR_ATTACH_NUM])) { $attach = mapi_message_openattach($fwmessage, $row[PR_ATTACH_NUM]); $newattach = mapi_message_createattach($mapimessage); // 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); } } } //set PR_INTERNET_CPID to 65001 (utf-8) if store supports it and to 1252 otherwise $internetcpid = 1252; if (defined('STORE_SUPPORTS_UNICODE') && STORE_SUPPORTS_UNICODE == true) { $internetcpid = 65001; } mapi_setprops($mapimessage, array(PR_BODY => $body, PR_INTERNET_CPID => $internetcpid)); if (strlen($body_html) > 0) { mapi_setprops($mapimessage, array(PR_HTML => $body_html)); } mapi_savechanges($mapimessage); mapi_message_submitmessage($mapimessage); return true; }
/** * Adds the recipients to an email message from a RFC822 message headers. * * @param MIMEMessageHeader $headers * @param MAPIMessage $mapimessage */ private function addRecipients($headers, &$mapimessage) { $toaddr = $ccaddr = $bccaddr = array(); $Mail_RFC822 = new Mail_RFC822(); if (isset($headers["to"])) { $toaddr = $Mail_RFC822->parseAddressList($headers["to"]); } if (isset($headers["cc"])) { $ccaddr = $Mail_RFC822->parseAddressList($headers["cc"]); } if (isset($headers["bcc"])) { $bccaddr = $Mail_RFC822->parseAddressList($headers["bcc"]); } if (empty($toaddr)) { throw new StatusException(sprintf("ZarafaBackend->SendMail(): 'To' address in RFC822 message not found or unparsable. To header: '%s'", isset($headers["to"]) ? $headers["to"] : ''), SYNC_COMMONSTATUS_MESSHASNORECIP); } // Add recipients $recips = array(); foreach (array(MAPI_TO => $toaddr, MAPI_CC => $ccaddr, MAPI_BCC => $bccaddr) as $type => $addrlist) { foreach ($addrlist as $addr) { $mapirecip[PR_ADDRTYPE] = "SMTP"; $mapirecip[PR_EMAIL_ADDRESS] = $addr->mailbox . "@" . $addr->host; if (isset($addr->personal) && strlen($addr->personal) > 0) { $mapirecip[PR_DISPLAY_NAME] = u2wi($addr->personal); } else { $mapirecip[PR_DISPLAY_NAME] = $mapirecip[PR_EMAIL_ADDRESS]; } $mapirecip[PR_RECIPIENT_TYPE] = $type; $mapirecip[PR_ENTRYID] = mapi_createoneoff($mapirecip[PR_DISPLAY_NAME], $mapirecip[PR_ADDRTYPE], $mapirecip[PR_EMAIL_ADDRESS]); array_push($recips, $mapirecip); } } mapi_message_modifyrecipients($mapimessage, 0, $recips); }
function SendMail($rfc822, $forward = false, $reply = false, $parent = false) { $mimeParams = array('decode_headers' => false, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $rfc822, 'crlf' => "\r\n", 'charset' => 'utf-8'); $mimeObject = new Mail_mimeDecode($mimeParams['input'], $mimeParams['crlf']); $message = $mimeObject->decode($mimeParams); // Open the outbox and create the message there $storeprops = mapi_getprops($this->_defaultstore, array(PR_IPM_OUTBOX_ENTRYID, PR_IPM_SENTMAIL_ENTRYID)); if (!isset($storeprops[PR_IPM_OUTBOX_ENTRYID])) { debugLog("Outbox not found to create message"); return false; } $outbox = mapi_msgstore_openentry($this->_defaultstore, $storeprops[PR_IPM_OUTBOX_ENTRYID]); if (!$outbox) { debugLog("Unable to open outbox"); return false; } $mapimessage = mapi_folder_createmessage($outbox); mapi_setprops($mapimessage, array(PR_SUBJECT => u2w($mimeObject->_decodeHeader($message->headers["subject"])), PR_SENTMAIL_ENTRYID => $storeprops[PR_IPM_SENTMAIL_ENTRYID], PR_MESSAGE_CLASS => "IPM.Note", PR_MESSAGE_DELIVERY_TIME => time())); if (isset($message->headers["x-priority"])) { switch ($message->headers["x-priority"]) { case 1: case 2: $priority = PRIO_URGENT; $importance = IMPORTANCE_HIGH; break; case 4: case 5: $priority = PRIO_NONURGENT; $importance = IMPORTANCE_LOW; break; case 3: default: $priority = PRIO_NORMAL; $importance = IMPORTANCE_NORMAL; break; } mapi_setprops($mapimessage, array(PR_IMPORTANCE => $importance, PR_PRIORITY => $priority)); } $addresses = array(); $toaddr = $ccaddr = $bccaddr = 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["bcc"])) { $bccaddr = Mail_RFC822::parseAddressList($message->headers["bcc"]); } // Add recipients $recips = array(); if (isset($toaddr)) { foreach (array(MAPI_TO => $toaddr, MAPI_CC => $ccaddr, MAPI_BCC => $bccaddr) as $type => $addrlist) { foreach ($addrlist as $addr) { $mapirecip[PR_ADDRTYPE] = "SMTP"; $mapirecip[PR_EMAIL_ADDRESS] = $addr->mailbox . "@" . $addr->host; if (isset($addr->personal) && strlen($addr->personal) > 0) { $mapirecip[PR_DISPLAY_NAME] = u2w($mimeObject->_decodeHeader($addr->personal)); } else { $mapirecip[PR_DISPLAY_NAME] = $mapirecip[PR_EMAIL_ADDRESS]; } $mapirecip[PR_RECIPIENT_TYPE] = $type; $mapirecip[PR_ENTRYID] = mapi_createoneoff($mapirecip[PR_DISPLAY_NAME], $mapirecip[PR_ADDRTYPE], $mapirecip[PR_EMAIL_ADDRESS]); array_push($recips, $mapirecip); } } } mapi_message_modifyrecipients($mapimessage, 0, $recips); // Loop through subparts. We currently only support real single-level // multiparts and partly multipart/related/mixed for attachments. // The PDA currently only does this because you are adding // an attachment and the type will be multipart/mixed or multipart/alternative. $body = ""; if ($message->ctype_primary == "multipart" && ($message->ctype_secondary == "mixed" || $message->ctype_secondary == "alternative")) { foreach ($message->parts as $part) { if ($part->ctype_primary == "text" && $part->ctype_secondary == "plain" && isset($part->body)) { // discard any other kind of text, like html $body .= u2w($part->body); // assume only one text body } elseif ($part->ctype_primary == "ms-tnef" || $part->ctype_secondary == "ms-tnef") { $zptnef = new ZPush_tnef($this->_defaultstore); $mapiprops = array(); $zptnef->extractProps($part->body, $mapiprops); if (is_array($mapiprops) && !empty($mapiprops)) { //check if it is a recurring item $tnefrecurr = GetPropIDFromString($this->_defaultstore, "PT_BOOLEAN:{6ED8DA90-450B-101B-98DA-00AA003F1305}:0x5"); if (isset($mapiprops[$tnefrecurr])) { $this->_handleRecurringItem($mapimessage, $mapiprops); } mapi_setprops($mapimessage, $mapiprops); } else { debugLog("TNEF: Mapi props array was empty"); } } elseif ($part->ctype_primary == "multipart" && ($part->ctype_secondary == "mixed" || $part->ctype_secondary == "related")) { if (is_array($part->parts)) { foreach ($part->parts as $part2) { if (isset($part2->disposition) && ($part2->disposition == "inline" || $part2->disposition == "attachment")) { $this->_storeAttachment($mapimessage, $part2); } } } } elseif ($part->ctype_primary == "text" && $part->ctype_secondary == "calendar") { $zpical = new ZPush_ical($this->_defaultstore); $mapiprops = array(); $zpical->extractProps($part->body, $mapiprops); if (is_array($mapiprops) && !empty($mapiprops)) { mapi_setprops($mapimessage, $mapiprops); } else { debugLog("ICAL: Mapi props array was empty"); } } else { $this->_storeAttachment($mapimessage, $part); } } } else { $body = u2w($message->body); } if ($forward) { $orig = $forward; } if ($reply) { $orig = $reply; } if (isset($orig) && $orig) { // Append the original text body for reply/forward $entryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($parent), hex2bin($orig)); $fwmessage = mapi_msgstore_openentry($this->_defaultstore, $entryid); if ($fwmessage) { //update icon when forwarding or replying message if ($forward) { mapi_setprops($fwmessage, array(PR_ICON_INDEX => 262)); } elseif ($reply) { mapi_setprops($fwmessage, array(PR_ICON_INDEX => 261)); } mapi_savechanges($fwmessage); $stream = mapi_openproperty($fwmessage, PR_BODY, IID_IStream, 0, 0); $fwbody = ""; while (1) { $data = mapi_stream_read($stream, 1024); if (strlen($data) == 0) { break; } $fwbody .= $data; } if (strlen($body) > 0) { if ($forward) { // During a forward, we have to add the forward header ourselves. This is because // normally the forwarded message is added as an attachment. However, we don't want this // because it would be rather complicated to copy over the entire original message due // to the lack of IMessage::CopyTo .. $fwmessageprops = mapi_getprops($fwmessage, array(PR_SENT_REPRESENTING_NAME, PR_DISPLAY_TO, PR_DISPLAY_CC, PR_SUBJECT, PR_CLIENT_SUBMIT_TIME)); $body .= "\r\n\r\n"; $body .= "-----Original Message-----\r\n"; if (isset($fwmessageprops[PR_SENT_REPRESENTING_NAME])) { $body .= "From: " . $fwmessageprops[PR_SENT_REPRESENTING_NAME] . "\r\n"; } if (isset($fwmessageprops[PR_DISPLAY_TO]) && strlen($fwmessageprops[PR_DISPLAY_TO]) > 0) { $body .= "To: " . $fwmessageprops[PR_DISPLAY_TO] . "\r\n"; } if (isset($fwmessageprops[PR_DISPLAY_CC]) && strlen($fwmessageprops[PR_DISPLAY_CC]) > 0) { $body .= "Cc: " . $fwmessageprops[PR_DISPLAY_CC] . "\r\n"; } if (isset($fwmessageprops[PR_CLIENT_SUBMIT_TIME])) { $body .= "Sent: " . strftime("%x %X", $fwmessageprops[PR_CLIENT_SUBMIT_TIME]) . "\r\n"; } if (isset($fwmessageprops[PR_SUBJECT])) { $body .= "Subject: " . $fwmessageprops[PR_SUBJECT] . "\r\n"; } $body .= "\r\n"; } $body .= $fwbody; } } else { debugLog("Unable to open item with id {$orig} for forward/reply"); } } if ($forward) { // Add attachments from the original message in a forward $entryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($parent), hex2bin($orig)); $fwmessage = mapi_msgstore_openentry($this->_defaultstore, $entryid); $attachtable = mapi_message_getattachmenttable($fwmessage); $rows = mapi_table_queryallrows($attachtable, array(PR_ATTACH_NUM)); foreach ($rows as $row) { if (isset($row[PR_ATTACH_NUM])) { $attach = mapi_message_openattach($fwmessage, $row[PR_ATTACH_NUM]); $newattach = mapi_message_createattach($mapimessage); // 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); } } } mapi_setprops($mapimessage, array(PR_BODY => $body)); mapi_savechanges($mapimessage); mapi_message_submitmessage($mapimessage); return true; }
function SendMail($rfc822, $smartdata = array(), $protocolversion = false) { if (WBXML_DEBUG === true && $protocolversion <= 14.0) { debugLog("SendMail: task " . $smartdata['task'] . " itemid: " . (isset($smartdata['itemid']) ? $smartdata['itemid'] : "") . " parent: " . (isset($smartdata['folderid']) ? $smartdata['folderid'] : "") . "\n" . $rfc822); } $mimeParams = array('decode_headers' => false, 'decode_bodies' => true, 'include_bodies' => true, 'charset' => 'utf-8'); $mimeObject = new Mail_mimeDecode($rfc822); $message = $mimeObject->decode($mimeParams); // Open the outbox and create the message there $storeprops = mapi_getprops($this->_defaultstore, array(PR_IPM_OUTBOX_ENTRYID, PR_IPM_SENTMAIL_ENTRYID)); if (!isset($storeprops[PR_IPM_OUTBOX_ENTRYID])) { debugLog("Outbox not found to create message"); return false; } $outbox = mapi_msgstore_openentry($this->_defaultstore, $storeprops[PR_IPM_OUTBOX_ENTRYID]); if (!$outbox) { debugLog("Unable to open outbox"); return false; } $mapimessage = mapi_folder_createmessage($outbox); mapi_setprops($mapimessage, array(PR_SUBJECT => u2w($mimeObject->_decodeHeader(isset($message->headers["subject"]) ? $message->headers["subject"] : "")), PR_SENTMAIL_ENTRYID => $storeprops[PR_IPM_SENTMAIL_ENTRYID], PR_MESSAGE_CLASS => 'IPM.Note', PR_MESSAGE_DELIVERY_TIME => time())); if (isset($message->headers["x-priority"])) { switch ($message->headers["x-priority"]) { case 1: case 2: $priority = PRIO_URGENT; $importance = IMPORTANCE_HIGH; break; case 4: case 5: $priority = PRIO_NONURGENT; $importance = IMPORTANCE_LOW; break; case 3: default: $priority = PRIO_NORMAL; $importance = IMPORTANCE_NORMAL; break; } mapi_setprops($mapimessage, array(PR_IMPORTANCE => $importance, PR_PRIORITY => $priority)); } $addresses = array(); $toaddr = $ccaddr = $bccaddr = array(); $Mail_RFC822 = new Mail_RFC822(); 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["bcc"])) { $bccaddr = $Mail_RFC822->parseAddressList($message->headers["bcc"]); } if (count($toaddr) == 0 && count($ccaddr) == 0 && count($bccaddr) == 0) { debugLog("Sendmail: Message has got no recipients (no to, no cc and no bcc!)"); return 119; } // Add recipients $recips = array(); if (isset($toaddr)) { foreach (array(MAPI_TO => $toaddr, MAPI_CC => $ccaddr, MAPI_BCC => $bccaddr) as $type => $addrlist) { foreach ($addrlist as $addr) { $mapirecip[PR_ADDRTYPE] = "SMTP"; $mapirecip[PR_EMAIL_ADDRESS] = $addr->mailbox . "@" . $addr->host; if (isset($addr->personal) && strlen($addr->personal) > 0) { $mapirecip[PR_DISPLAY_NAME] = u2w($mimeObject->_decodeHeader($addr->personal)); } else { $mapirecip[PR_DISPLAY_NAME] = $mapirecip[PR_EMAIL_ADDRESS]; } $mapirecip[PR_RECIPIENT_TYPE] = $type; $mapirecip[PR_ENTRYID] = mapi_createoneoff($mapirecip[PR_DISPLAY_NAME], $mapirecip[PR_ADDRTYPE], $mapirecip[PR_EMAIL_ADDRESS]); array_push($recips, $mapirecip); } } } mapi_message_modifyrecipients($mapimessage, 0, $recips); // Loop through message subparts. $body = ""; $body_html = ""; if ($message->ctype_primary == "multipart" && ($message->ctype_secondary == "signed" || $message->ctype_secondary == "mixed" || $message->ctype_secondary == "alternative")) { $mparts = $message->parts; for ($i = 0; $i < count($mparts); $i++) { $part = $mparts[$i]; // palm pre & iPhone send forwarded messages in another subpart which are also parsed if ($part->ctype_primary == "multipart" && ($part->ctype_secondary == "mixed" || $part->ctype_secondary == "alternative" || $part->ctype_secondary == "related")) { foreach ($part->parts as $spart) { $mparts[] = $spart; } continue; } // standard body if ($part->ctype_primary == "text" && $part->ctype_secondary == "plain" && isset($part->body) && (!isset($part->disposition) || $part->disposition != "attachment")) { $body .= u2w($part->body); // assume only one text body } elseif ($part->ctype_primary == "text" && $part->ctype_secondary == "html") { $body_html .= u2w($part->body); } elseif ($part->ctype_primary == "ms-tnef" || $part->ctype_secondary == "ms-tnef") { $zptnef = new ZPush_tnef($this->_defaultstore); $mapiprops = array(); $zptnef->extractProps($part->body, $mapiprops); if (is_array($mapiprops) && !empty($mapiprops)) { //check if it is a recurring item $tnefrecurr = GetPropIDFromString($this->_defaultstore, "PT_BOOLEAN:{6ED8DA90-450B-101B-98DA-00AA003F1305}:0x5"); if (isset($mapiprops[$tnefrecurr])) { $this->_handleRecurringItem($mapimessage, $mapiprops); } debugLog(print_r($mapiprops, true)); mapi_setprops($mapimessage, $mapiprops); } else { debugLog("TNEF: Mapi props array was empty"); } } elseif ($part->ctype_primary == "text" && $part->ctype_secondary == "calendar") { $zpical = new ZPush_ical($this->_defaultstore); $mapiprops = array(); $zpical->extractProps($part->body, $mapiprops); // iPhone sends a second ICS which we ignore if we can if (!isset($mapiprops[PR_MESSAGE_CLASS]) && strlen(trim($body)) == 0) { debugLog("Secondary iPhone response is being ignored!! Mail dropped!"); return true; } if (!checkMapiExtVersion("6.30") && is_array($mapiprops) && !empty($mapiprops)) { mapi_setprops($mapimessage, $mapiprops); } else { // store ics as attachment $this->_storeAttachment($mapimessage, $part); debugLog("Sending ICS file as attachment"); } } elseif ($part->ctype_primary == "text" && $part->ctype_secondary == "x-vCalendar") { $zpical = new ZPush_ical($this->_defaultstore); $mapiprops = array(); $zpical->extractProps($part->body, $mapiprops); if (is_array($mapiprops) && !empty($mapiprops)) { // dw2412 Nokia sends incomplete iCal calendar item, so we have to add properties like // message class and icon index if (isset($mapiprops[PR_MESSAGE_CLASS]) && $mapiprops[PR_MESSAGE_CLASS] == "IPM.Note" || !isset($mapiprops[PR_MESSAGE_CLASS])) { $mapiprops[PR_ICON_INDEX] = 0x404; $mapiprops[PR_OWNER_APPT_ID] = 0; $mapiprops[PR_MESSAGE_CLASS] = "IPM.Schedule.Meeting.Request"; } // dw2412 Nokia sends no location information field in case user did not type in some // thing in this field... $namedIntentedBusyStatus = GetPropIDFromString($this->_defaultstore, "PT_LONG:{00062002-0000-0000-C000-000000000046}:8224"); if (!isset($mapiprops[$namedIntentedBusyStatus])) { $mapiprops[$namedIntentedBusyStatus] = 0; } $namedLocation = GetPropIDFromString($this->_defaultstore, "PT_STRING8:{00062002-0000-0000-C000-000000000046}:0x8208"); if (!isset($mapiprops[$namedLocation])) { $mapiprops[$namedLocation] = ""; } $tnefLocation = GetPropIDFromString($this->_defaultstore, "PT_STRING8:{6ED8DA90-450B-101B-98DA-00AA003F1305}:0x2"); if (!isset($mapiprops[$tnefLocation])) { $mapiprops[$tnefLocation] = ""; } $useTNEF = GetPropIDFromString($this->_defaultstore, "PT_BOOLEAN:{00062008-0000-0000-C000-000000000046}:0x8582"); $mapiprops[$useTNEF] = true; } else { debugLog("ICAL: Mapi props array was empty"); } } elseif ($part->ctype_primary == 'application' && $part->ctype_secondary == 'x-pkcs7-signature') { $rfc822_p7m = $this->_rfc822tosmimep7m($rfc822); $smimepart = (object) array('ctype_primary' => 'multipart', 'ctype_secondary' => 'signed', 'body' => $rfc822_p7m); debugLog(print_r($smimepart, true)); $mapiprops = array(); $mapiprops[PR_MESSAGE_CLASS] = "IPM.Note.SMIME.MultipartSigned"; $hideattachments = GetPropIDFromString($this->_defaultstore, "PT_BOOLEAN:{00062008-0000-0000-C000-000000000046}:0x8514"); $mapiprops[$hideattachments] = true; mapi_setprops($mapimessage, $mapiprops); $this->_storeAttachment($mapimessage, $smimepart); } else { $this->_storeAttachment($mapimessage, $part); } } } else { // start dw2412 handle smime encrypted emails... if ($message->ctype_primary == "application" && $message->ctype_secondary == "x-pkcs7-mime") { $mapiprops = array(); $mapiprops[PR_MESSAGE_CLASS] = "IPM.Note.SMIME"; $hideattachments = GetPropIDFromString($this->_defaultstore, "PT_BOOLEAN:{00062008-0000-0000-C000-000000000046}:0x8514"); $mapiprops[$hideattachments] = true; $mapicontenttype = mapi_prop_tag(PT_STRING8, 0x85e8); $mapiprops[$mapicontenttype] = $message->headers['content-type']; mapi_setprops($mapimessage, $mapiprops); $this->_storeAttachment($mapimessage, $message); } // end dw2412 handle encrypted emails // start dw2412 handle windows mobile html replies... // standard body if ($message->ctype_primary == "text" && $message->ctype_secondary == "plain" && isset($message->body) && (!isset($message->disposition) || $message->disposition != "attachment")) { $body = u2w($message->body); // assume only one text body } elseif ($message->ctype_primary == "text" && $message->ctype_secondary == "html") { $body_html = u2w($message->body); } // end dw2412 handle windows mobile html replies... // $body = u2w($message->body); } // some devices only transmit a html body if (strlen($body) == 0 && strlen($body_html) > 0) { debugLog("only html body sent, transformed into plain text"); $body = strip_tags($body_html); } // START ADDED dw2412 update/create conversation index $conversationindex = false; // END ADDED dw2412 update/create conversation index if (isset($smartdata['itemid']) && $smartdata['itemid'] || isset($smartdata['longid']) && $smartdata['longid']) { // Append the original text body for reply/forward if (isset($smartdata['longid'])) { $entryid = hex2bin($smartdata['longid']); } else { $entryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($smartdata['folderid']), hex2bin($smartdata['itemid'])); } if (($fwmessage = mapi_msgstore_openentry($this->_defaultstore, $entryid)) === false) { debugLog("Sendmail: Provided EntryID cannot be opened. Return error code 150."); switch ($smartdata['task']) { case 'forward': return 150; case 'reply': return 150; } } if ($fwmessage) { // START CHANGED dw2412 LAST Verb Exec Props included //update icon when forwarding or replying message if ($smartdata['task'] == 'forward') { mapi_setprops($fwmessage, array(PR_LAST_VERB_EXECUTED => 0x68, PR_LAST_VERB_EXECUTION_TIME => time())); mapi_setprops($fwmessage, array(PR_ICON_INDEX => 262)); } elseif ($smartdata['task'] == 'reply') { // START ADDED dw2412 update/create conversation index $fwmessageprops = mapi_getprops($fwmessage, array(PR_CONVERSATION_INDEX)); if (isset($fwmessageprops[PR_CONVERSATION_INDEX])) { $conversationindex = $fwmessageprops[PR_CONVERSATION_INDEX]; } // END ADDED dw2412 update/create conversation index if (sizeof($recips) > 1) { mapi_setprops($fwmessage, array(PR_LAST_VERB_EXECUTED => 0x67, PR_LAST_VERB_EXECUTION_TIME => time())); } else { mapi_setprops($fwmessage, array(PR_LAST_VERB_EXECUTED => 0x66, PR_LAST_VERB_EXECUTION_TIME => time())); } mapi_setprops($fwmessage, array(PR_ICON_INDEX => 261)); } else { mapi_setprops($fwmessage, array(PR_LAST_VERB_EXECUTED => 0x0, PR_LAST_VERB_EXECUTION_TIME => time())); } // END CHANGED dw2412 LAST Verb Exec Props included mapi_savechanges($fwmessage); $stream = mapi_openproperty($fwmessage, PR_BODY, IID_IStream, 0, 0); $fwbody = ""; while (1) { $data = mapi_stream_read($stream, 1024); if (strlen($data) == 0) { break; } $fwbody .= $data; } $stream = mapi_openproperty($fwmessage, PR_HTML, IID_IStream, 0, 0); $fwbody_html = ""; while (1) { $data = mapi_stream_read($stream, 1024); if (strlen($data) == 0) { break; } $fwbody_html .= $data; } $stream = mapi_openproperty($fwmessage, PR_HTML, IID_IStream, 0, 0); $fwbody_html = ""; while (1) { $data = mapi_stream_read($stream, 1024); if (strlen($data) == 0) { break; } $fwbody_html .= $data; } // dw2412 Enable this only in case of AS2.5 Protocol... in AS12 this seem // being done already by winmobile client. if ($smartdata['task'] == 'forward' && $protocolversion <= 2.5) { // During a forward, we have to add the forward header ourselves. This is because // normally the forwarded message is added as an attachment. However, we don't want this // because it would be rather complicated to copy over the entire original message due // to the lack of IMessage::CopyTo .. $fwmessageprops = mapi_getprops($fwmessage, array(PR_SENT_REPRESENTING_NAME, PR_DISPLAY_TO, PR_DISPLAY_CC, PR_SUBJECT, PR_CLIENT_SUBMIT_TIME)); $fwheader = "\r\n\r\n"; $fwheader .= "-----Original Message-----\r\n"; if (isset($fwmessageprops[PR_SENT_REPRESENTING_NAME])) { $fwheader .= "From: " . $fwmessageprops[PR_SENT_REPRESENTING_NAME] . "\r\n"; } if (isset($fwmessageprops[PR_DISPLAY_TO]) && strlen($fwmessageprops[PR_DISPLAY_TO]) > 0) { $fwheader .= "To: " . $fwmessageprops[PR_DISPLAY_TO] . "\r\n"; } if (isset($fwmessageprops[PR_DISPLAY_CC]) && strlen($fwmessageprops[PR_DISPLAY_CC]) > 0) { $fwheader .= "Cc: " . $fwmessageprops[PR_DISPLAY_CC] . "\r\n"; } if (isset($fwmessageprops[PR_CLIENT_SUBMIT_TIME])) { $fwheader .= "Sent: " . strftime("%x %X", $fwmessageprops[PR_CLIENT_SUBMIT_TIME]) . "\r\n"; } if (isset($fwmessageprops[PR_SUBJECT])) { $fwheader .= "Subject: " . $fwmessageprops[PR_SUBJECT] . "\r\n"; } $fwheader .= "\r\n"; // add fwheader to body and body_html $body .= $fwheader; if (strlen($body_html) > 0) { $body_html .= str_ireplace("\r\n", "<br>", $fwheader); } } if (strlen($body) > 0) { $body .= $fwbody; } if (strlen($body_html) > 0) { $body_html .= $fwbody_html; } } else { debugLog("Unable to open item with id {$orig} for forward/reply"); } } if ($smartdata['task'] == 'forward') { // Add attachments from the original message in a forward if (isset($smartdata['longid'])) { $entryid = hex2bin($smartdata['longid']); } else { $entryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($smartdata['folderid']), hex2bin($smartdata['itemid'])); } $fwmessage = mapi_msgstore_openentry($this->_defaultstore, $entryid); $attachtable = mapi_message_getattachmenttable($fwmessage); $rows = mapi_table_queryallrows($attachtable, array(PR_ATTACH_NUM)); foreach ($rows as $row) { if (isset($row[PR_ATTACH_NUM])) { $attach = mapi_message_openattach($fwmessage, $row[PR_ATTACH_NUM]); $newattach = mapi_message_createattach($mapimessage); // 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); } } } // START ADDED dw2412 update/create conversation index if (CONVERSATIONINDEX == true) { $ci = new ConversationIndex(); if ($conversationindex) { $ci->Decode($conversationindex); $ci->Update(); } else { $ci->Create(); } mapi_setprops($mapimessage, array(PR_CONVERSATION_INDEX => $ci->Encode())); } // END ADDED dw2412 update/create conversation index //set PR_INTERNET_CPID to 65001 (utf-8) if store supports it and to 1252 otherwise $internetcpid = 1252; if (defined('STORE_SUPPORTS_UNICODE') && STORE_SUPPORTS_UNICODE == true) { $internetcpid = 65001; } mapi_setprops($mapimessage, array(PR_BODY => $body, PR_INTERNET_CPID => $internetcpid)); if (strlen($body_html) > 0) { mapi_setprops($mapimessage, array(PR_HTML => $body_html)); } if (mapi_savechanges($mapimessage) === false || mapi_message_submitmessage($mapimessage) === false) { switch ($smartdata['task']) { case 'reply': debugLog("Sendmail: Message reply failed, sending failed at all"); return 121; default: debugLog("Sendmail: Message failed to be saved/submitted, sending failed at all"); return 120; } } return true; }
/** * Convert vObject to an array of properties * @param object $vCard * @param object $properties array storing MAPI properties */ public function vObjectToProperties($vcard, &$properties) { $this->logger->info("vObjectToProperties"); ob_start(); print_r($vcard); $dump = ob_get_contents(); ob_end_clean(); $this->logger->trace("VObject :\n{$dump}"); // Common VCard properties parsing $p = $this->bridge->getExtendedProperties(); // Init properties if (CLEAR_MISSING_PROPERTIES) { $this->logger->trace("Clearing missing properties"); $properties[$p['surname']] = NULL; $properties[$p['given_name']] = NULL; $properties[$p['middle_name']] = NULL; $properties[$p['display_name_prefix']] = NULL; $properties[$p['generation']] = NULL; $properties[$p['display_name']] = NULL; $properties[$p['nickname']] = NULL; $properties[$p['title']] = NULL; $properties[$p['profession']] = NULL; $properties[$p['office_location']] = NULL; $properties[$p['company_name']] = NULL; $properties[$p['birthday']] = NULL; $properties[$p['wedding_anniversary']] = NULL; $properties[$p['home_telephone_number']] = NULL; $properties[$p['home2_telephone_number']] = NULL; $properties[$p['cellular_telephone_number']] = NULL; $properties[$p['office_telephone_number']] = NULL; $properties[$p['business2_telephone_number']] = NULL; $properties[$p['business_fax_number']] = NULL; $properties[$p['home_fax_number']] = NULL; $properties[$p['pager_telephone_number']] = NULL; $properties[$p['isdn_number']] = NULL; $properties[$p['company_telephone_number']] = NULL; $properties[$p['car_telephone_number']] = NULL; $properties[$p['assistant_telephone_number']] = NULL; $properties[$p['assistant']] = NULL; $properties[$p['manager_name']] = NULL; $properties[$p['spouse_name']] = NULL; $properties[$p['home_address_street']] = NULL; $properties[$p['home_address_city']] = NULL; $properties[$p['home_address_state']] = NULL; $properties[$p['home_address_postal_code']] = NULL; $properties[$p['home_address_country']] = NULL; $properties[$p['business_address_street']] = NULL; $properties[$p['business_address_city']] = NULL; $properties[$p['business_address_state']] = NULL; $properties[$p['business_address_postal_code']] = NULL; $properties[$p['business_address_country']] = NULL; $properties[$p['other_address_street']] = NULL; $properties[$p['other_address_city']] = NULL; $properties[$p['other_address_state']] = NULL; $properties[$p['other_address_postal_code']] = NULL; $properties[$p['other_address_country']] = NULL; $nremails = array(); $abprovidertype = 0; for ($i = 1; $i <= 3; $i++) { $properties[$p["email_address_{$i}"]] = NULL; $properties[$p["email_address_display_name_email_{$i}"]] = NULL; $properties[$p["email_address_display_name_{$i}"]] = NULL; $properties[$p["email_address_type_{$i}"]] = NULL; $properties[$p["email_address_entryid_{$i}"]] = NULL; } $properties[$p["address_book_mv"]] = NULL; $properties[$p["address_book_long"]] = NULL; $properties[$p['webpage']] = NULL; $properties[$p['im']] = NULL; $properties[$p['categories']] = NULL; $properties['ContactPicture'] = NULL; $properties[PR_HASATTACH] = false; $properties[$p['has_picture']] = false; } // Name components $sortAs = ''; if (isset($vcard->n)) { $this->logger->trace("N: " . $vcard->n); $nameInfo = VCardParser::splitCompundProperty($vcard->n->value); $dump = print_r($nameInfo, true); $this->logger->trace("Name info\n{$dump}"); $properties[$p['surname']] = isset($nameInfo[0]) ? $nameInfo[0] : ''; $properties[$p['given_name']] = isset($nameInfo[1]) ? $nameInfo[1] : ''; $properties[$p['middle_name']] = isset($nameInfo[2]) ? $nameInfo[2] : ''; $properties[$p['display_name_prefix']] = isset($nameInfo[3]) ? $nameInfo[3] : ''; $properties[$p['generation']] = isset($nameInfo[4]) ? $nameInfo[4] : ''; // Issue 3#8 if ($vcard->n->offsetExists('SORT-AS')) { $sortAs = $vcard->n->offsetGet('SORT-AS')->value; } } // Given sort-as ? /* if (isset($vcard->sort-as)) { $this->logger->debug("Using vcard SORT-AS"); $sortAs = $vcard->sort-as->value; } */ $sortAsProperty = $vcard->select("SORT-AS"); if (count($sortAsProperty) != 0) { $sortAs = current($sortAsProperty)->value; } if (isset($vcard->nickname)) { $properties[$p['nickname']] = $vcard->nickname->value; } if (isset($vcard->title)) { $properties[$p['title']] = $vcard->title->value; } if (isset($vcard->role)) { $properties[$p['profession']] = $vcard->role->value; } if (isset($vcard->office)) { $properties[$p['office_location']] = $vcard->office->value; } if (isset($vcard->org)) { $orgInfo = VCardParser::splitCompundProperty($vcard->org->value); $properties[$p['company_name']] = $orgInfo[0]; } if (isset($vcard->fn)) { $properties[$p['display_name']] = $vcard->fn->value; $properties[PR_SUBJECT] = $vcard->fn->value; } if (empty($sortAs) || SAVE_AS_OVERRIDE_SORTAS) { $this->logger->trace("Empty sort-as or SAVE_AS_OVERRIDE_SORTAS set"); $sortAs = SAVE_AS_PATTERN; // $vcard->fn->value; // Do substitutions $substitutionKeys = array('%d', '%l', '%f', '%c'); $substitutionValues = array($properties[$p['display_name']], $properties[$p['surname']], $properties[$p['given_name']], $properties[$p['company_name']]); $sortAs = str_replace($substitutionKeys, $substitutionValues, $sortAs); } // Should PR_SUBJET and display_name be equals to fileas? I think so! $this->logger->debug("Contact display name: " . $sortAs); $properties[$p['fileas']] = $sortAs; $properties[$p['display_name']] = $sortAs; $properties[PR_SUBJECT] = $sortAs; // Custom... not quite sure X-MS-STUFF renders as x_ms_stuff... will have to check that! if (isset($vcard->x_ms_assistant)) { $properties[$p['assistant']] = $vcard->x_ms_assistant->value; } if (isset($vcard->x_ms_manager)) { $properties[$p['manager_name']] = $vcard->x_ms_manager->value; } if (isset($vcard->x_ms_spouse)) { $properties[$p['spouse_name']] = $vcard->x_ms_spouse->value; } // Dates if (isset($vcard->bday)) { $time = new DateTime($vcard->bday->value); $properties[$p['birthday']] = $time->format('U'); } if (isset($vcard->anniversary)) { $time = new DateTime($vcard->anniversary->value); $properties[$p['wedding_anniversary']] = $time->format('U'); } // Telephone numbers... todo as this is a bit complicated :p $typeCount = array('HOME,VOICE' => 0, 'CELL,VOICE' => 0, 'CELL' => 0, 'WORK,VOICE' => 0, 'WORK,FAX' => 0, 'PAGER' => 0, 'ISDN' => 0, 'WORK' => 0, 'CAR' => 0, 'MAIN' => 0, 'SECR' => 0); $telephoneNumbers = $vcard->select("TEL"); foreach ($telephoneNumbers as $tel) { $type = ''; $pk = ''; // Get type $typeParam = $tel->offsetGet("TYPE"); if ($typeParam != NULL) { $type = ''; foreach ($typeParam as $tp) { if (!in_array(strtoupper($tp->value), array('PREF', 'IPHONE'))) { $type .= $type == '' ? '' : ','; $type .= strtoupper($tp->value); } } } if ($type == 'HOME,VOICE' || $type == 'HOME') { $type = 'HOME,VOICE'; // Force count key $pk = 'home_telephone_number'; if ($typeCount[$type] == 1) { $pk = 'home2_telephone_number'; } } if ($type == 'WORK,VOICE') { $pk = 'office_telephone_number'; if ($typeCount[$type] == 1) { $pk = 'business2_telephone_number'; } } if ($type == 'CELL,VOICE') { $pk = 'cellular_telephone_number'; } if ($type == 'CELL') { $pk = 'cellular_telephone_number'; } if ($type == 'IPHONE') { $pk = 'cellular_telephone_number'; } if ($type == 'WORK,FAX') { $pk = 'business_fax_number'; } if ($type == 'HOME,FAX') { $pk = 'home_fax_number'; } if ($type == 'PAGER') { $pk = 'pager_telephone_number'; } if ($type == 'ISDN') { $pk = 'isdn_number'; } if ($type == 'WORK') { $pk = 'company_telephone_number'; } if ($type == 'CAR') { $pk = 'car_telephone_number'; } if ($type == 'SECR') { $pk = 'assistant_telephone_number'; } if ($type == 'MAIN') { $pk = 'primary_telephone_number'; } if ($type == '') { $pk = DEFAULT_TELEPHONE_NUMBER_PROPERTY; } // Counting if ($pk != '') { if (!isset($typeCount[$type])) { $typeCount[$type] = 0; } $properties[$p[$pk]] = $tel->value; $typeCount[$type]++; } else { $this->logger->warn("Unknown telephone type: '{$type}'"); } } // Addresses... $addresses = $vcard->select('ADR'); foreach ($addresses as $address) { $type = strtoupper($address->offsetGet('TYPE')->value); $this->logger->debug("Found address {$type}"); switch ($type) { case 'HOME': $pStreet = 'home_address_street'; $pCity = 'home_address_city'; $pState = 'home_address_state'; $pPCode = 'home_address_postal_code'; $pCountry = 'home_address_country'; break; case 'WORK': $pStreet = 'business_address_street'; $pCity = 'business_address_city'; $pState = 'business_address_state'; $pPCode = 'business_address_postal_code'; $pCountry = 'business_address_country'; break; case 'OTHER': $pStreet = 'other_address_street'; $pCity = 'other_address_city'; $pState = 'other_address_state'; $pPCode = 'other_address_postal_code'; $pCountry = 'other_address_country'; break; default: $this->logger->debug("Unknwon address type {$type} - skipping"); continue 2; } $addressComponents = VCardParser::splitCompundProperty($address->value); $dump = print_r($addressComponents, true); $this->logger->trace("Address components:\n{$dump}"); // Set properties $properties[$p[$pStreet]] = isset($addressComponents[2]) ? $addressComponents[2] : ''; $properties[$p[$pCity]] = isset($addressComponents[3]) ? $addressComponents[3] : ''; $properties[$p[$pState]] = isset($addressComponents[4]) ? $addressComponents[4] : ''; $properties[$p[$pPCode]] = isset($addressComponents[5]) ? $addressComponents[5] : ''; $properties[$p[$pCountry]] = isset($addressComponents[6]) ? $addressComponents[6] : ''; } // emails need to handle complementary properties plus create one off entries! $nremails = array(); $abprovidertype = 0; $emails = $vcard->select("EMAIL"); $emailsDisplayName = $vcard->select("X-EMAIL-CN"); // emClient handles those $numMail = 0; if (is_array($emailsDisplayName)) { $emailsDisplayName = array_values($emailsDisplayName); } $dump = print_r($emailsDisplayName, true); $this->logger->trace("Display Names\n{$dump}"); foreach ($emails as $email) { $numMail++; $displayName = ''; if ($numMail > 3) { // Zarafa only handles 3 mails break; } $address = $email->value; if (count($emailsDisplayName) >= $numMail) { // Display name exists, use it! $displayName = $emailsDisplayName[$numMail - 1]->value; } else { $displayName = $vcard->fn->value; } // Override displayName? if ($email->offsetExists("X-CN")) { $xCn = $email->offsetGet("X-CN"); $displayName = $xCn->value; } $this->logger->debug("Found email {$numMail} : {$displayName} <{$address}>"); $properties[$p["email_address_{$numMail}"]] = $address; $properties[$p["email_address_display_name_email_{$numMail}"]] = $address; $properties[$p["email_address_display_name_{$numMail}"]] = $displayName; $properties[$p["email_address_type_{$numMail}"]] = "SMTP"; $properties[$p["email_address_entryid_{$numMail}"]] = mapi_createoneoff($displayName, "SMTP", $address); $nremails[] = $numMail - 1; $abprovidertype |= 2 ^ $numMail - 1; } if ($numMail > 0) { if (!empty($nremails)) { $properties[$p["address_book_mv"]] = $nremails; } $properties[$p["address_book_long"]] = $abprovidertype; } // URLs and instant messaging. IMPP could be multivalues, will need to check that! if (isset($vcard->url)) { $properties[$p['webpage']] = $vcard->url->value; } if (isset($vcard->impp)) { $properties[$p['im']] = $vcard->impp->value; } // Categories (multi values) if (isset($vcard->categories)) { $properties[$p['categories']] = explode(',', $vcard->categories->value); } // Contact picture if (isset($vcard->photo)) { $type = strtolower($vcard->photo->offsetGet("TYPE")->value); $encoding = $vcard->photo->offsetGet("ENCODING")->value; $content = $vcard->photo->value; $this->logger->debug("Found contact picture type {$type} encoding {$encoding}"); if ($encoding == 'b' || $encoding == '') { $content = base64_decode($content); if ($type != 'jpeg' && $type != 'image/jpeg' && $type != 'image/jpg') { $this->logger->trace("Converting to jpeg using GD"); $img = imagecreatefromstring($content); $this->logger->trace("Image loaded by GD"); if ($img === FALSE) { $this->logger->warn("Corrupted contact picture or unknown format"); $content = NULL; } else { // Capture output ob_start(); $r = imagejpeg($img); $content = ob_get_contents(); ob_end_clean(); // imagedestroy($img); $this->logger->debug("Convert done - result: " . ($r ? "OK" : "KO")); } } if ($content !== NULL) { $this->logger->info("Contact has picture!"); $properties['ContactPicture'] = $content; $properties[PR_HASATTACH] = true; $properties[$p['has_picture']] = true; } } else { $this->logger->warn("Encoding not supported: {$encoding}"); } } // Misc $properties[$p["icon_index"]] = "512"; // Zarafa specific? if (isset($vcard->note)) { $properties[$p['notes']] = $vcard->note->value; } }
function SendMail($rfc822, $forward = false, $reply = false, $parent = false) { $message = Mail_mimeDecode::decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $rfc822, 'crlf' => "\r\n", 'charset' => 'utf-8')); // Open the outbox and create the message there $storeprops = mapi_getprops($this->_defaultstore, array(PR_IPM_OUTBOX_ENTRYID, PR_IPM_SENTMAIL_ENTRYID)); if (!isset($storeprops[PR_IPM_OUTBOX_ENTRYID])) { debugLog("Outbox not found to create message"); return false; } $outbox = mapi_msgstore_openentry($this->_defaultstore, $storeprops[PR_IPM_OUTBOX_ENTRYID]); if (!$outbox) { debugLog("Unable to open outbox"); return false; } $mapimessage = mapi_folder_createmessage($outbox); mapi_setprops($mapimessage, array(PR_SUBJECT => u2w($message->headers["subject"]), PR_SENTMAIL_ENTRYID => $storeprops[PR_IPM_SENTMAIL_ENTRYID], PR_MESSAGE_CLASS => "IPM.Note", PR_MESSAGE_DELIVERY_TIME => time())); if (isset($message->headers["x-priority"])) { switch ($message->headers["x-priority"]) { case 1: case 2: $priority = PRIO_URGENT; $importance = IMPORTANCE_HIGH; break; case 4: case 5: $priority = PRIO_NONURGENT; $importance = IMPORTANCE_LOW; break; case 3: default: $priority = PRIO_NORMAL; $importance = IMPORTANCE_NORMAL; break; } mapi_setprops($mapimessage, array(PR_IMPORTANCE => $importance, PR_PRIORITY => $priority)); } $addresses = array(); $toaddr = $ccaddr = $bccaddr = 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["bcc"])) { $bccaddr = Mail_RFC822::parseAddressList($message->headers["bcc"]); } // Add recipients $recips = array(); if (isset($toaddr)) { foreach (array(MAPI_TO => $toaddr, MAPI_CC => $ccaddr, MAPI_BCC => $bccaddr) as $type => $addrlist) { foreach ($addrlist as $addr) { $mapirecip[PR_ADDRTYPE] = "SMTP"; $mapirecip[PR_EMAIL_ADDRESS] = $addr->mailbox . "@" . $addr->host; if (isset($addr->personal) && strlen($addr->personal) > 0) { $mapirecip[PR_DISPLAY_NAME] = u2w($addr->personal); } else { $mapirecip[PR_DISPLAY_NAME] = $mapirecip[PR_EMAIL_ADDRESS]; } $mapirecip[PR_RECIPIENT_TYPE] = $type; $mapirecip[PR_ENTRYID] = mapi_createoneoff($mapirecip[PR_DISPLAY_NAME], $mapirecip[PR_ADDRTYPE], $mapirecip[PR_EMAIL_ADDRESS]); array_push($recips, $mapirecip); } } } mapi_message_modifyrecipients($mapimessage, 0, $recips); // Loop through subparts. We currently only support single-level // multiparts. The PDA currently only does this because you are adding // an attachment and the type will be multipart/mixed. if ($message->ctype_primary == "multipart" && $message->ctype_secondary == "mixed") { foreach ($message->parts as $part) { if ($part->ctype_primary == "text") { $body = u2w($part->body); } else { // attachment $attach = mapi_message_createattach($mapimessage); // Filename is present in both Content-Type: name=.. and in Content-Disposition: filename= if (isset($part->ctype_parameters["name"])) { $filename = $part->ctype_parameters["name"]; } else { if (isset($part->d_parameters["name"])) { $filename = $part->d_parameters["filename"]; } else { $filename = "untitled"; } } // Set filename and attachment type mapi_setprops($attach, array(PR_ATTACH_LONG_FILENAME => u2w($filename), PR_ATTACH_METHOD => ATTACH_BY_VALUE)); // Set attachment data mapi_setprops($attach, array(PR_ATTACH_DATA_BIN => $part->body)); // Set MIME type mapi_setprops($attach, array(PR_ATTACH_MIME_TAG => $part->ctype_primary . "/" . $part->ctype_secondary)); mapi_savechanges($attach); } } } else { $body = u2w($message->body); } if ($forward) { $orig = $forward; } if ($reply) { $orig = $reply; } if (isset($orig) && $orig) { // Append the original text body for reply/forward $entryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($parent), hex2bin($orig)); $fwmessage = mapi_msgstore_openentry($this->_defaultstore, $entryid); if ($fwmessage) { $messageprops = mapi_getprops($fwmessage, array(PR_BODY)); if (isset($messageprops[PR_BODY])) { if ($forward) { // During a forward, we have to add the forward header ourselves. This is because // normally the forwarded message is added as an attachment. However, we don't want this // because it would be rather complicated to copy over the entire original message due // to the lack of IMessage::CopyTo .. $fwmessageprops = mapi_getprops($fwmessage, array(PR_SENT_REPRESENTING_NAME, PR_DISPLAY_TO, PR_DISPLAY_CC, PR_SUBJECT, PR_CLIENT_SUBMIT_TIME)); $body .= "\r\n\r\n"; $body .= "-----Original Message-----\r\n"; if (isset($fwmessageprops[PR_SENT_REPRESENTING_NAME])) { $body .= "From: " . $fwmessageprops[PR_SENT_REPRESENTING_NAME] . "\r\n"; } if (isset($fwmessageprops[PR_DISPLAY_TO]) && strlen($fwmessageprops[PR_DISPLAY_TO]) > 0) { $body .= "To: " . $fwmessageprops[PR_DISPLAY_TO] . "\r\n"; } if (isset($fwmessageprops[PR_DISPLAY_CC]) && strlen($fwmessageprops[PR_DISPLAY_CC]) > 0) { $body .= "Cc: " . $fwmessageprops[PR_DISPLAY_CC] . "\r\n"; } if (isset($fwmessageprops[PR_CLIENT_SUBMIT_TIME])) { $body .= "Sent: " . strftime("%x %X", $fwmessageprops[PR_CLIENT_SUBMIT_TIME]) . "\r\n"; } if (isset($fwmessageprops[PR_SUBJECT])) { $body .= "Subject: " . $fwmessageprops[PR_SUBJECT] . "\r\n"; } $body .= "\r\n"; } $body .= $messageprops[PR_BODY]; } } else { debugLog("Unable to open item with id {$orig} for forward/reply"); } } if ($forward) { // Add attachments from the original message in a forward $entryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($parent), hex2bin($orig)); $fwmessage = mapi_msgstore_openentry($this->_defaultstore, $entryid); $attachtable = mapi_message_getattachmenttable($fwmessage); $rows = mapi_table_queryallrows($attachtable, array(PR_ATTACH_NUM)); foreach ($rows as $row) { if (isset($row[PR_ATTACH_NUM])) { $attach = mapi_message_openattach($fwmessage, $row[PR_ATTACH_NUM]); $newattach = mapi_message_createattach($mapimessage); // 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); } } } mapi_setprops($mapimessage, array(PR_BODY => $body)); mapi_savechanges($mapimessage); mapi_message_submitmessage($mapimessage); return true; }
function setEmailAddress($emailAddress, $displayName, $cnt, &$props, $properties, &$nremails, &$abprovidertype) { if (isset($emailAddress)) { $email = to_windows1252($emailAddress); if (isset($displayName)) { $name = to_windows1252($displayName); // adding a email address requires a name } else { $name = $email; } $props[$properties["email_address_{$cnt}"]] = $email; $props[$properties["email_address_display_name_email_{$cnt}"]] = $email; $props[$properties["email_address_display_name_{$cnt}"]] = $name; $props[$properties["email_address_type_{$cnt}"]] = "SMTP"; $props[$properties["email_address_entryid_{$cnt}"]] = mapi_createoneoff($name, "SMTP", $email); $nremails[] = $cnt - 1; $abprovidertype |= 2 ^ $cnt - 1; } }