function MeetingResponse($requestid, $folderid, $response, &$calendarid) { // Use standard meeting response code to process meeting request $reqentryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($folderid), hex2bin($requestid)); $mapimessage = mapi_msgstore_openentry($this->_defaultstore, $reqentryid); if (!$mapimessage) { debugLog("Unable to open request message for response"); return false; } $meetingrequest = new Meetingrequest($this->_defaultstore, $mapimessage); if (!$meetingrequest->isMeetingRequest()) { debugLog("Attempt to respond to non-meeting request"); return false; } if ($meetingrequest->isLocalOrganiser()) { debugLog("Attempt to response to meeting request that we organized"); return false; } // Process the meeting response. We don't have to send the actual meeting response // e-mail, because the device will send it itself. switch ($response) { case 1: // accept // accept default: $entryid = $meetingrequest->doAccept(false, false, false, false, false, false, true); // last true is the $userAction break; case 2: // tentative $entryid = $meetingrequest->doAccept(true, false, false, false, false, false, true); // last true is the $userAction break; case 3: // decline $meetingrequest->doDecline(false); break; } // F/B will be updated on logoff // We have to return the ID of the new calendar item, so do that here if (isset($entryid)) { $newitem = mapi_msgstore_openentry($this->_defaultstore, $entryid); $newprops = mapi_getprops($newitem, array(PR_SOURCE_KEY)); $calendarid = bin2hex($newprops[PR_SOURCE_KEY]); } // on recurring items, the MeetingRequest class responds with a wrong entryid if ($requestid == $calendarid) { debugLog("returned calender id is the same as the requestid - re-searching"); $goidprop = GetPropIDFromString($this->_defaultstore, "PT_BINARY:{6ED8DA90-450B-101B-98DA-00AA003F1305}:0x3"); $messageprops = mapi_getprops($mapimessage, array($goidprop, PR_OWNER_APPT_ID)); $goid = $messageprops[$goidprop]; if (isset($messageprops[PR_OWNER_APPT_ID])) { $apptid = $messageprops[PR_OWNER_APPT_ID]; } else { $apptid = false; } //findCalendarItems signature was changed in 6.40.8, Mantis #485 $items = checkMapiExtVersion("6.40.8") ? $meetingrequest->findCalendarItems($goid) : $meetingrequest->findCalendarItems($goid, $apptid); if (is_array($items)) { $newitem = mapi_msgstore_openentry($this->_defaultstore, $items[0]); $newprops = mapi_getprops($newitem, array(PR_SOURCE_KEY)); $calendarid = bin2hex($newprops[PR_SOURCE_KEY]); debugLog("found other calendar entryid"); } } // delete meeting request from Inbox $folderentryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($folderid)); $folder = mapi_msgstore_openentry($this->_defaultstore, $folderentryid); mapi_folder_deletemessages($folder, array($reqentryid), 0); return true; }
function _readSingleMapiProp(&$buffer, &$size, &$read, &$mapiprops) { $propTag = 0; $len = 0; $origSize = $size; $isNamedId = 0; $namedProp = 0; $count = 0; $mvProp = 0; $guid = 0; if ($size < 8) { return MAPI_E_NOT_FOUND; } $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $propTag); if ($hresult !== NOERROR) { debugLog("There was an error reading a mapi property tag from the stream."); return $hresult; } $size -= 4; //debugLog("mapi prop type:".dechex(mapi_prop_type($propTag))); //debugLog("mapi prop tag: 0x".sprintf("%04x", mapi_prop_id($propTag))); if (mapi_prop_id($propTag) >= 0x8000) { // Named property, first read GUID, then name/id if ($size < 24) { debugLog("Corrupt guid size for named property:" . dechex($propTag)); return MAPI_E_CORRUPT_DATA; } //strip GUID & name/id $hresult = $this->_readBuffer($buffer, 16, $guid); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } $size -= 16; //it is not used and is here only for eventual debugging $readableGuid = unpack("VV/v2v/n4n", $guid); $readableGuid = sprintf("{%08x-%04x-%04x-%04x-%04x%04x%04x}", $readableGuid['V'], $readableGuid['v1'], $readableGuid['v2'], $readableGuid['n1'], $readableGuid['n2'], $readableGuid['n3'], $readableGuid['n4']); //debugLog("guid:$readableGuid"); $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $isNamedId); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property checksum."); return $hresult; } $size -= 4; if ($isNamedId != 0) { // A string name follows //read length of the property $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $len); if ($hresult !== NOERROR) { debugLog("There was an error reading mapi property's length"); return $hresult; } $size -= 4; if ($size < $len) { return MAPI_E_CORRUPT_DATA; } //read the name of the property, eg Keywords $hresult = $this->_readBuffer($buffer, $len, $namedProp); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } $size -= $len; //Re-align $buffer = substr($buffer, $len & 3 ? 4 - ($len & 3) : 0); $size -= $len & 3 ? 4 - ($len & 3) : 0; } else { $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $namedProp); if ($hresult !== NOERROR) { debugLog("There was an error reading mapi property's length"); return $hresult; } //debugLog("named: 0x".sprintf("%04x", $namedProp)); $size -= 4; } if ($this->_store !== false) { $named = mapi_getidsfromnames($this->_store, array($namedProp), array(makeguid($readableGuid))); $propTag = mapi_prop_tag(mapi_prop_type($propTag), mapi_prop_id($named[0])); } else { debugLog("Store not available. It is impossible to get named properties"); } } //debugLog("mapi prop tag: 0x".sprintf("%04x", mapi_prop_id($propTag))." ".sprintf("%04x", mapi_prop_type($propTag))); if ($propTag & MV_FLAG) { if ($size < 4) { return MAPI_E_CORRUPT_DATA; } //read the number of properties $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $count); if ($hresult !== NOERROR) { debugLog("There was an error reading number of properties for:" . dechex($propTag)); return $hresult; } $size -= 4; } else { $count = 1; } for ($mvProp = 0; $mvProp < $count; $mvProp++) { switch (mapi_prop_type($propTag) & ~MV_FLAG) { case PT_I2: case PT_LONG: $hresult = $this->_readBuffer($buffer, 4, $value); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } $value = unpack("V", $value); $value = intval($value[1], 16); if ($propTag & MV_FLAG) { $mapiprops[$propTag][] = $value; } else { $mapiprops[$propTag] = $value; } $size -= 4; //debugLog("int or long propvalue:".$value); break; case PT_R4: if ($propTag & MV_FLAG) { $hresult = $this->_readBuffer($buffer, 4, $mapiprops[$propTag][]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } else { $hresult = $this->_readBuffer($buffer, 4, $mapiprops[$propTag]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } $size -= 4; //debugLog("propvalue:".$mapiprops[$propTag]); break; case PT_BOOLEAN: $hresult = $this->_readBuffer($buffer, 4, $mapiprops[$propTag]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } $size -= 4; //debugLog("propvalue:".$mapiprops[$propTag]); break; case PT_SYSTIME: if ($size < 8) { return MAPI_E_CORRUPT_DATA; } if ($propTag & MV_FLAG) { $hresult = $this->_readBuffer($buffer, 8, $mapiprops[$propTag][]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } else { $hresult = $this->_readBuffer($buffer, 8, $mapiprops[$propTag]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } //we have to convert the filetime to an unixtime timestamp $filetime = unpack("V2v", $mapiprops[$propTag]); $filetime = hexdec(sprintf("%08x%08x", $filetime['v2'], $filetime['v1'])); $filetime = ($filetime - 116444736000000000) / 10000000; $mapiprops[$propTag] = $filetime; // we have to set the start and end times separately because the standard PR_START_DATE and PR_END_DATE aren't enough if ($propTag == PR_START_DATE) { $namedStartTime = GetPropIDFromString($this->_store, "PT_SYSTIME:{00062002-0000-0000-C000-000000000046}:0x820d"); $mapiprops[$namedStartTime] = $filetime; $namedCommonStart = GetPropIDFromString($this->_store, "PT_SYSTIME:{00062008-0000-0000-C000-000000000046}:0x8516"); $mapiprops[$namedCommonStart] = $filetime; } if ($propTag == PR_END_DATE) { $namedEndTime = GetPropIDFromString($this->_store, "PT_SYSTIME:{00062002-0000-0000-C000-000000000046}:0x820e"); $mapiprops[$namedEndTime] = $filetime; $namedCommonEnd = GetPropIDFromString($this->_store, "PT_SYSTIME:{00062008-0000-0000-C000-000000000046}:0x8517"); $mapiprops[$namedCommonEnd] = $filetime; } $size -= 8; //debugLog("propvalue:".$mapiprops[$propTag]); break; case PT_DOUBLE: case PT_CURRENCY: case PT_I8: case PT_APPTIME: if ($size < 8) { return MAPI_E_CORRUPT_DATA; } if ($propTag & MV_FLAG) { $hresult = $this->_readBuffer($buffer, 8, $mapiprops[$propTag][]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } else { $hresult = $this->_readBuffer($buffer, 8, $mapiprops[$propTag]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } $size -= 8; //debugLog("propvalue:".$mapiprops[$propTag]); break; case PT_STRING8: if ($size < 8) { return MAPI_E_CORRUPT_DATA; } // Skip next 4 bytes, it's always '1' (ULONG) $buffer = substr($buffer, 4); $size -= 4; //read length of the property $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $len); if ($hresult !== NOERROR) { debugLog("There was an error reading mapi property's length"); return $hresult; } $size -= 4; if ($size < $len) { return MAPI_E_CORRUPT_DATA; } if ($propTag & MV_FLAG) { $hresult = $this->_readBuffer($buffer, $len, $mapiprops[$propTag][]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } else { $hresult = $this->_readBuffer($buffer, $len, $mapiprops[$propTag]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } //location fix. it looks like tnef uses this value for location if (mapi_prop_id($propTag) == 0x8342) { $namedLocation = GetPropIDFromString($this->_store, "PT_STRING8:{00062002-0000-0000-C000-000000000046}:0x8208"); $mapiprops[$namedLocation] = $mapiprops[$propTag]; unset($mapiprops[$propTag]); } $size -= $len; //Re-align $buffer = substr($buffer, $len & 3 ? 4 - ($len & 3) : 0); $size -= $len & 3 ? 4 - ($len & 3) : 0; //debugLog("propvalue:".$mapiprops[$propTag]); break; case PT_UNICODE: if ($size < 8) { return MAPI_E_CORRUPT_DATA; } // Skip next 4 bytes, it's always '1' (ULONG) $buffer = substr($buffer, 4); $size -= 4; //read length of the property $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $len); if ($hresult !== NOERROR) { debugLog("There was an error reading mapi property's length"); return $hresult; } $size -= 4; if ($size < $len) { return MAPI_E_CORRUPT_DATA; } //currently unicode strings are not supported bz mapi_setprops, so we'll use PT_STRING8 $propTag = mapi_prop_tag(PT_STRING8, mapi_prop_id($propTag)); if ($propTag & MV_FLAG) { $hresult = $this->_readBuffer($buffer, $len, $mapiprops[$propTag][]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } else { $hresult = $this->_readBuffer($buffer, $len, $mapiprops[$propTag]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } //location fix. it looks like tnef uses this value for location if (mapi_prop_id($propTag) == 0x8342) { $namedLocation = GetPropIDFromString($this->_store, "PT_STRING8:{00062002-0000-0000-C000-000000000046}:0x8208"); $mapiprops[$namedLocation] = $mapiprops[$propTag]; unset($mapiprops[$propTag]); $mapiprops[$namedLocation] = iconv("UCS-2", "windows-1252", $mapiprops[$namedLocation]); } //convert from unicode to windows encoding if (isset($mapiprops[$propTag])) { $mapiprops[$propTag] = iconv("UCS-2", "windows-1252", $mapiprops[$propTag]); } $size -= $len; //Re-align $buffer = substr($buffer, $len & 3 ? 4 - ($len & 3) : 0); $size -= $len & 3 ? 4 - ($len & 3) : 0; //debugLog("propvalue:".$mapiprops[$propTag]); break; case PT_OBJECT: // PST sends PT_OBJECT data. Treat as PT_BINARY // PST sends PT_OBJECT data. Treat as PT_BINARY case PT_BINARY: if ($size < ZP_BYTE) { return MAPI_E_CORRUPT_DATA; } // Skip next 4 bytes, it's always '1' (ULONG) $buffer = substr($buffer, 4); $size -= 4; //read length of the property $hresult = $this->_readFromTnefStream($buffer, ZP_DWORD, $len); if ($hresult !== NOERROR) { debugLog("There was an error reading mapi property's length"); return $hresult; } $size -= 4; if (mapi_prop_type($propTag) == PT_OBJECT) { // TODO: IMessage guid [ 0x00020307 C000 0000 0000 0000 00 00 00 46 ] $buffer = substr($buffer, 16); $size -= 16; $len -= 16; } if ($size < $len) { return MAPI_E_CORRUPT_DATA; } if ($propTag & MV_FLAG) { $hresult = $this->_readBuffer($buffer, $len, $mapiprops[$propTag][]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } else { $hresult = $this->_readBuffer($buffer, $len, $mapiprops[$propTag]); if ($hresult !== NOERROR) { debugLog("There was an error reading stream property buffer"); return $hresult; } } $size -= $len; //Re-align $buffer = substr($buffer, $len & 3 ? 4 - ($len & 3) : 0); $size -= $len & 3 ? 4 - ($len & 3) : 0; //debugLog("propvalue:".bin2hex($mapiprops[$propTag])); break; default: return MAPI_E_INVALID_PARAMETER; break; } } return NOERROR; }
function extractProps($ical, &$mapiprops) { //mapping between partstat in ical and MAPI Meeting Response classes as well as icons $aClassMap = array("ACCEPTED" => array("class" => "IPM.Schedule.Meeting.Resp.Pos", "icon" => 0x405), "DECLINED" => array("class" => "IPM.Schedule.Meeting.Resp.Neg", "icon" => 0x406), "TENTATIVE" => array("class" => "IPM.Schedule.Meeting.Resp.Tent", "icon" => 0x407)); $aical = array_map("rtrim", preg_split("/[\n]/", $ical)); $elemcount = count($aical); $i = 0; $nextline = $aical[0]; //last element is empty while ($i < $elemcount - 1) { $line = $nextline; //if a line starts with a space or a tab it belongs to the previous line $nextline = $aical[$i + 1]; if (strlen($nextline) == 0) { $i++; continue; } while ($nextline[0] == " " || $nextline[0] == "\t") { $line .= substr($nextline, 1); $nextline = $aical[++$i + 1]; } switch (strtoupper($line)) { case "BEGIN:VCALENDAR": case "BEGIN:VEVENT": case "END:VEVENT": case "END:VCALENDAR": break; default: unset($field, $data, $prop_pos, $property); if (ereg("([^:]+):(.*)", $line, $line)) { $field = $line[1]; $data = $line[2]; $property = $field; $prop_pos = strpos($property, ';'); if ($prop_pos !== false) { $property = substr($property, 0, $prop_pos); } $property = strtoupper($property); switch ($property) { case 'DTSTART': $data = $this->getTimestampFromStreamerDate($data); $namedStartTime = GetPropIDFromString($this->_store, "PT_SYSTIME:{00062002-0000-0000-C000-000000000046}:0x820d"); $mapiprops[$namedStartTime] = $data; $namedCommonStart = GetPropIDFromString($this->_store, "PT_SYSTIME:{00062008-0000-0000-C000-000000000046}:0x8516"); $mapiprops[$namedCommonStart] = $data; $clipStart = GetPropIDFromString($this->_store, "PT_SYSTIME:{00062002-0000-0000-C000-000000000046}:0x8235"); $mapiprops[$clipStart] = $data; $mapiprops[PR_START_DATE] = $data; break; case 'DTEND': $data = $this->getTimestampFromStreamerDate($data); $namedEndTime = GetPropIDFromString($this->_store, "PT_SYSTIME:{00062002-0000-0000-C000-000000000046}:0x820e"); $mapiprops[$namedEndTime] = $data; $namedCommonEnd = GetPropIDFromString($this->_store, "PT_SYSTIME:{00062008-0000-0000-C000-000000000046}:0x8517"); $mapiprops[$namedCommonEnd] = $data; $clipEnd = GetPropIDFromString($this->_store, "PT_SYSTIME:{00062002-0000-0000-C000-000000000046}:0x8236"); $mapiprops[$clipEnd] = $data; $mapiprops[PR_END_DATE] = $data; break; case 'UID': $goid = GetPropIDFromString($this->_store, "PT_BINARY:{6ED8DA90-450B-101B-98DA-00AA003F1305}:0x3"); $goid2 = GetPropIDFromString($this->_store, "PT_BINARY:{6ED8DA90-450B-101B-98DA-00AA003F1305}:0x23"); $mapiprops[$goid] = $mapiprops[$goid2] = hex2bin($data); break; case 'ATTENDEE': $fields = explode(";", $field); foreach ($fields as $field) { $prop_pos = strpos($field, '='); if ($prop_pos !== false) { switch (substr($field, 0, $prop_pos)) { case 'PARTSTAT': $partstat = substr($field, $prop_pos + 1); break; case 'CN': $cn = substr($field, $prop_pos + 1); break; case 'ROLE': $role = substr($field, $prop_pos + 1); break; case 'RSVP': $rsvp = substr($field, $prop_pos + 1); break; } } } if (isset($partstat) && isset($aClassMap[$partstat])) { $mapiprops[PR_MESSAGE_CLASS] = $aClassMap[$partstat]['class']; $mapiprops[PR_ICON_INDEX] = $aClassMap[$partstat]['icon']; } $data = str_replace("MAILTO:", "", $data); $attendee[] = array('name' => stripslashes($cn), 'email' => stripslashes($data)); break; case 'ORGANIZER': $field = str_replace("ORGANIZER;CN=", "", $field); $data = str_replace("MAILTO:", "", $data); $organizer[] = array('name' => stripslashes($field), 'email' => stripslashes($data)); break; case 'LOCATION': $data = str_replace("\\n", "<br />", $data); $data = str_replace("\\t", " ", $data); $data = str_replace("\\r", "<br />", $data); $data = stripslashes($data); $namedLocation = GetPropIDFromString($this->_store, "PT_STRING8:{00062002-0000-0000-C000-000000000046}:0x8208"); $mapiprops[$namedLocation] = $data; $tneflocation = GetPropIDFromString($this->_store, "PT_STRING8:{6ED8DA90-450B-101B-98DA-00AA003F1305}:0x2"); $mapiprops[$tneflocation] = $data; break; } } break; } $i++; } $useTNEF = GetPropIDFromString($this->_store, "PT_BOOLEAN:{00062008-0000-0000-C000-000000000046}:0x8582"); $mapiprops[$useTNEF] = true; }
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 readCertsfromContact($emailaddress) { $email1address = GetPropIDFromString($this->_defaultstore, "PT_STRING8:{00062004-0000-0000-C000-000000000046}:0x8083"); $email2address = GetPropIDFromString($this->_defaultstore, "PT_STRING8:{00062004-0000-0000-C000-000000000046}:0x8093"); $email3address = GetPropIDFromString($this->_defaultstore, "PT_STRING8:{00062004-0000-0000-C000-000000000046}:0x80A3"); $x509certs = mapi_prop_tag(PT_MV_BINARY, 0x3a70); $rows = $this->readResolveRecipientsfromContacts($emailaddress); foreach ($rows as $entry) { $res['displayname'] = w2u($entry[PR_DISPLAY_NAME]); $res['type'] = 2; if (isset($entry[$email1address]) && $entry[$email1address] == $emailaddress) { $res['emailaddress'] = $entry[$email1address]; } else { if (isset($entry[$email2address]) && $entry[$email2address] == $emailaddress) { $res['emailaddress'] = $entry[$email2address]; } else { if (isset($entry[$email3address]) && $entry[$email3address] == $emailaddress) { $res['emailaddress'] = $entry[$email3address]; } } } $entries = array(); if (isset($entry[$x509certs]) && USERX509CERTIFICATES == true) { $certs = new Userx509Certificates(isset($entry[$x509certs]) ? $entry[$x509certs] : array()); if ($der_certs = $certs->findCertificatebySubjectValue('emailAddress', $emailaddress)) { foreach ($der_certs as $der_cert) { $entries[] = base64_encode($der_cert); } } } $res['entries'] = $entries; if (count($res['entries']) > 0) { $result[$emailaddress][] = $res; } } return $result; }
function _getPropIDFromString($stringprop) { return GetPropIDFromString($this->_store, $stringprop); }