See http://msdn.microsoft.com/en-us/library/hh338153%28v=exchg.80%29.aspx
public static getUidFromGoid ( string $goid ) : string | ||
$goid | string | Base64 encoded Global Object Identifier. |
리턴 | string | The UID |
/** * Test parsing GOID value. */ public function testParseGlobalObjectId() { // Outlook UID $fixture = 'BAAAAIIA4AB0xbcQGoLgCAfUCRDgQMnBJoXEAQAAAAAAAAAAEAAAAAvw7UtuTulOnjnjhns3jvM='; $uid = Horde_Mapi::getUidFromGoid($fixture); $this->assertEquals('040000008200E00074C5B7101A82E00800000000E040C9C12685C4010000000000000000100000000BF0ED4B6E4EE94E9E39E3867B378EF3', $uid); // vCal $fixture = 'BAAAAIIA4AB0xbcQGoLgCAAAAAAAAAAAAAAAAAAAAAAAAAAAMwAAAHZDYWwtVWlkAQAAAHs4MTQxMkQzQy0yQTI0LTRFOUQtQjIwRS0xMUY3QkJFOTI3OTl9AA=='; $uid = Horde_Mapi::getUidFromGoid($fixture); $this->assertEquals('{81412D3C-2A24-4E9D-B20E-11F7BBE92799}', $uid); }
/** * Allow this object to set any MAPI attributes it needs to know about, * ignore any it doesn't care about. * * @param integer $type The attribute type descriptor. * @param integer $name The attribute name descriptor. */ public function setMapiAttribute($type, $name, $value, $ns = null) { if ($ns == Horde_Compress_Tnef::PSETID_COMMON) { switch ($name) { case Horde_Compress_Tnef::IPM_TASK_GUID: // Almost positive this is wrong :( $this->_guid = Horde_Mapi::getUidFromGoid(bin2hex($value)); break; case Horde_Compress_Tnef::MSG_EDITOR_FORMAT: // Map this? $this->_msgformat = $value; break; case Horde_Compress_Tnef::MAPI_TAG_BODY: // plaintext. Most likely set via the attBody TNEF attribute, // and not by the MAPI property. if (empty($this->_bodyPlain)) { $this->_bodyPlain = $value; } break; case Horde_Compress_Tnef::MAPI_TAG_HTML: // html $this->_bodyHtml = $value; break; case self::MAPI_TASK_COMMONSTART: try { $this->_start = new Horde_Date(Horde_Mapi::filetimeToUnixtime($value)); } catch (Horde_Date_Exception $e) { throw new Horde_Compress_Exception($e); } $this->_start = $this->_start->timestamp(); break; case self::MAPI_TASK_COMMONEND: try { $this->_due = new Horde_Date(Horde_Mapi::filetimeToUnixtime($value)); } catch (Horde_Mapi_Exception $e) { throw new Horde_Compress_Exception($e); } catch (Horde_Date_Exception $e) { throw new Horde_Compress_Exception($e); } $this->_due = $this->_due->timestamp(); break; } } elseif ($ns == Horde_Compress_Tnef::PSETID_TASK) { switch ($name) { case self::MAPI_TASK_OWNER: // This is the OWNER, not to be confused with the ORGANIZER. // I.e., this is the person the task has been assigned to. // The ORGANIZER is the person who created the task and has // assigned it. I.e., the person that any task updates are // sent back to by the owner. $this->_owner = str_replace(array('(', ')'), array('<', '>'), $value); break; case self::MAPI_TASK_DUEDATE: // Favor COMMONEND if (empty($this->_due)) { $this->_due = Horde_Mapi::filetimeToUnixtime($value); } break; case self::MAPI_TASK_STARTDATE: if (empty($this->_start)) { $this->_start = Horde_Mapi::filetimeToUnixtime($value); } break; case self::MAPI_TASK_DATECOMPLETED: $this->_completed = Horde_Mapi::filetimeToUnixtime($value); break; case self::MAPI_TASK_PERCENTCOMPLETE: $value = unpack('d', $value); $this->_percentComplete = $value[1] * 100; break; case self::MAPI_TASK_STATUS: switch ($value) { case self::STATUS_NOT_STARTED: case self::STATUS_WAIT: case self::STATUS_DEFERRED: $this->_percentComplete = 0; $this->_status = self::TASK_STATUS_ACTION; break; case self::STATUS_IN_PROGRESS: $this->_status = self::TASK_STATUS_IN_PROGRESS; break; case self::STATUS_COMPLETE: $this->_status = self::TASK_STATUS_COMPLETED; $this->_percentComplete = 1; break; } break; case self::MAPI_TASK_UPDATES: if (!empty($value)) { $this->_updates = true; } break; case self::MAPI_TASK_OWNERSHIP: $this->_ownership = $value; break; case self::MAPI_TASK_STATE: $this->_state = $value; break; // case self::MAPI_TASK_ASSIGNER: // // *sigh* This isn't set by Outlook/Exchange until AFTER the // // assignee receives the request. I.e., this is blank on the initial // // REQUEST so not a valid way to obtain the task creator. // //$this->_organizer = $value; // break; // case self::MAPI_TASK_LASTUSER: // // From MS-OXOTASK 2.2.2.2.25: // // Before client sends a REQUEST, it is set to the assigner. // // Before client sends an ACCEPT, it is set to the assignee. // // Before client sneds REJECT, it is set to the assigner, not assignee. // // Unfortunately, it is only the display name, not the email! // $this->_lastUser = $value; // break; } } else { // pidTag? switch ($name) { case Horde_Compress_Tnef::MAPI_SENT_REP_EMAIL_ADDR: $this->_organizer = $value; break; case Horde_Compress_Tnef::MAPI_LAST_MODIFIER_NAME: $this->_lastUser = $value; } } }
/** * Allow this object to set any MAPI attributes it needs to know about, * ignore any it doesn't care about. * * @param integer $type The attribute type descriptor. * @param integer $name The attribute name descriptor. * @param mixed $value The value to set. * * @throws Horde_Compress_Exception */ public function setMapiAttribute($type, $name, $value, $ns = null) { // First check for pidTag* properties - these will have to namespace. // @todo look at just cocantenating the GUID with the pidLid in the // constants in H6? if (empty($ns)) { switch ($name) { case Horde_Compress_Tnef::MAPI_CONVERSATION_TOPIC: $this->_summary = $value; break; case Horde_Compress_Tnef::MAPI_SENT_REP_SMTP_ADDR: $this->_from = $value; break; case Horde_Compress_Tnef::MAPI_LAST_MODIFIER_NAME: // Sender SMTP is more appropriate, but not present in all // meeting request MAPI objects (it's normally taken form the // parent MAPI mail message object) Since this class doesn't // (currently) have access to the parent MIME // part (since this isn't necessarily from an email), this is the // only hope of obtaining an ORGANIZER. $this->_lastModifier = $value; break; case Horde_Compress_Tnef::MAPI_CREATION_TIME: try { $this->_created = new Horde_Date(Horde_Mapi::filetimeToUnixtime($value), 'UTC'); } catch (Horde_Mapi_Exception $e) { throw new Horde_Compress_Exception($e); } catch (Horde_Date_Exception $e) { throw new Horde_Compress_Exception($e); } break; case Horde_Compress_Tnef::MAPI_MODIFICATION_TIME: try { $this->_modified = new Horde_Date(Horde_Mapi::filetimeToUnixtime($value), 'UTC'); } catch (Horde_Mapi_Exception $e) { throw new Horde_Compress_Exception($e); } catch (Horde_Date_Exception $e) { throw new Horde_Compress_Exception($e); } break; case Horde_Compress_Tnef::MAPI_RESPONSE_REQUESTED: $this->_rsvp = $value; break; case Horde_Compress_Tnef::MAPI_TAG_RTF_COMPRESSED: // We may already have a description from the TNEF attBODY attribute if (empty($this->_description)) { $this->_description = $value; } break; } } elseif ($ns == Horde_Compress_Tnef::PSETID_APPOINTMENT) { switch ($name) { case Horde_Compress_Tnef::MAPI_APPOINTMENT_LOCATION: $this->_location = $value; break; case Horde_Compress_Tnef::MAPI_APPOINTMENT_URL: $this->_url = $value; break; case Horde_Compress_Tnef::MAPI_APPOINTMENT_START_WHOLE: try { $this->_startUtc = new Horde_Date(Horde_Mapi::filetimeToUnixtime($value), 'UTC'); } catch (Horde_Mapi_Exception $e) { throw new Horde_Compress_Exception($e); } catch (Horde_Date_Exception $e) { throw new Horde_Compress_Exception($e); } break; case Horde_Compress_Tnef::MAPI_APPOINTMENT_END_WHOLE: try { $this->_endUtc = new Horde_Date(Horde_Mapi::filetimeToUnixtime($value), 'UTC'); } catch (Horde_Mapi_Exception $e) { throw new Horde_Compress_Exception($e); } catch (Horde_Date_Exception $e) { throw new Horde_Compress_Exception($e); } break; case Horde_Compress_Tnef::MAPI_APPOINTMENT_DURATION: $this->_duration = $value; break; case Horde_Compress_Tnef::MAPI_APPOINTMENT_SUBTYPE: $this->_allday = $value; break; case Horde_Compress_Tnef::MAPI_ORGANIZER_ALIAS: $this->_organizer = $value; break; case Horde_Compress_Tnef::MAPI_TO_ATTENDEES: // Don't even ask. Why, Microsoft, why?? $value = str_replace(array('(', ')'), array('<', '>'), $value); $this->_requiredAttendees = $value; break; case Horde_Compress_Tnef::MAPI_APPOINTMENT_RECUR: $this->_recurrence['recur'] = $this->_parseRecurrence($value); break; case Horde_Compress_Tnef::MAPI_RECURRING: // ?? Reset $this->_recurrence? break; case Horde_Compress_Tnef::MAPI_RECURRENCE_TYPE: $this->_recurrence['type'] = $value; break; case Horde_Compress_Tnef::MAPI_RESPONSE_STATUS: // Don't think we need this, it seems more geared towards writing // a TNEF. Indicates the response status of an ATTENDEE. Putting // this here for reference, see MS-OXOCAL 2.2.1.11 break; } } elseif ($ns == Horde_Compress_Tnef::PSETID_MEETING) { switch ($name) { case Horde_Compress_Tnef::MAPI_ENTRY_CLEANID: case Horde_Compress_Tnef::MAPI_ENTRY_UID: // Still not 100% sure about where a suitable UID comes from; // These attributes are all said to contain it, at various times. // The "Clean" UID is supposed to only be in appointments that // are exceptions to a recurring series, though I have a number // of examples where that is not the case. Also, in some cases // some of these attributes seem to be set here multiple times, // sometimes with non-empty and then empty values, so never set // self::$_uid if it is already set, or if $value is empty. if (empty($this->_uid) && !empty($value)) { $this->_uid = Horde_Mapi::getUidFromGoid(bin2hex($value)); } break; case Horde_Compress_Tnef::MAPI_MEETING_REQUEST_TYPE: //pset $this->_type = $value; break; } } else { $this->_logger->notice(sprintf('Unknown namespace GUID: %s', $ns)); } }
/** * TODO * * @param string $data The data string. * @param array &$attachment_data TODO */ protected function _extractMapiAttributes($data, &$attachment_data) { /* Number of attributes. */ $number = $this->_geti($data, 32); while (strlen($data) > 0 && $number--) { $have_mval = false; $num_mval = 1; $named_id = $value = null; $attr_type = $this->_geti($data, 16); $attr_name = $this->_geti($data, 16); if (($attr_type & self::MAPI_MV_FLAG) != 0) { $have_mval = true; $attr_type = $attr_type & ~self::MAPI_MV_FLAG; } if ($attr_name >= 0x8000 && $attr_name < 0xfffe) { $this->_getx($data, 16); $named_type = $this->_geti($data, 32); switch ($named_type) { case self::MAPI_NAMED_TYPE_ID: $named_id = $this->_geti($data, 32); $attr_name = $named_id; break; case self::MAPI_NAMED_TYPE_STRING: $attr_name = 0x9999; $idlen = $this->_geti($data, 32); $datalen = $idlen + (4 - $idlen % 4) % 4; $named_id = substr($this->_getx($data, $datalen), 0, $idlen); break; } } if ($have_mval) { $num_mval = $this->_geti($data, 32); } switch ($attr_type) { case self::MAPI_SHORT: $value = $this->_geti($data, 16); break; case self::MAPI_INT: case self::MAPI_BOOLEAN: for ($i = 0; $i < $num_mval; $i++) { $value = $this->_geti($data, 32); } break; case self::MAPI_FLOAT: case self::MAPI_ERROR: $value = $this->_getx($data, 4); break; case self::MAPI_DOUBLE: case self::MAPI_APPTIME: case self::MAPI_CURRENCY: case self::MAPI_INT8BYTE: case self::MAPI_SYSTIME: $value = $this->_getx($data, 8); break; case self::MAPI_STRING: case self::MAPI_UNICODE_STRING: case self::MAPI_BINARY: case self::MAPI_OBJECT: $num_vals = $have_mval ? $num_mval : $this->_geti($data, 32); for ($i = 0; $i < $num_vals; $i++) { $length = $this->_geti($data, 32); /* Pad to next 4 byte boundary. */ $datalen = $length + (4 - $length % 4) % 4; if ($attr_type == self::MAPI_STRING) { --$length; } /* Read and truncate to length. */ $value = substr($this->_getx($data, $datalen), 0, $length); } break; } /* Store any interesting attributes. */ switch ($attr_name) { case self::MAPI_ATTACH_LONG_FILENAME: /* Used in preference to AFILENAME value. */ $attachment_data[0]['name'] = preg_replace('/.*[\\/](.*)$/', '\\1', $value); $attachment_data[0]['name'] = str_replace("", '', $attachment_data[0]['name']); break; case self::MAPI_ATTACH_MIME_TAG: /* Is this ever set, and what is format? */ $attachment_data[0]['type'] = preg_replace('/^(.*)\\/.*/', '\\1', $value); $attachment_data[0]['type'] = str_replace("", '', $attachment_data[0]['type']); $attachment_data[0]['subtype'] = preg_replace('/.*\\/(.*)$/', '\\1', $value); $attachment_data[0]['subtype'] = str_replace("", '', $attachment_data[0]['subtype']); break; // MAPI properties for meeting requests/responses. // MAPI properties for meeting requests/responses. case self::MAPI_CONVERSATION_TOPIC: $this->_conversation_topic = $value; break; case self::MAPI_APPOINTMENT_LOCATION: $attachment_data[0]['location'] = $value; break; case self::MAPI_APPOINTMENT_URL: $attachment_data[0]['url'] = $value; break; case self::MAPI_APPOINTMENT_START_WHOLE: try { $attachment_data[0]['start_utc'] = new Horde_Date(Horde_Mapi::filetimeToUnixtime($value), 'UTC'); } catch (Horde_Mapi_Exception $e) { throw new Horde_Compress_Exception($e); } break; case self::MAPI_APPOINTMENT_END_WHOLE: try { $attachment_data[0]['end_utc'] = new Horde_Date(Horde_Mapi::filetimeToUnixtime($value), 'UTC'); } catch (Horde_Mapi_Exception $e) { throw new Horde_Compress_Exception($e); } break; case self::MAPI_APPOINTMENT_DURATION: $attachment_data[0]['duration'] = $value; break; case self::MAPI_APPOINTMENT_SUBTYPE: $attachment_data[0]['allday'] = $value; break; case self::MAPI_ORGANIZER_ALIAS: $attachment_data[0]['organizer'] = $value; break; case self::MAPI_LAST_MODIFIER_NAME: $this->_lastModifier = $value; break; case self::MAPI_ENTRY_UID: $attachment_data[0]['uid'] = Horde_Mapi::getUidFromGoid(bin2hex($value)); break; case self::MAPI_APPOINTMENT_RECUR: if (empty($attachment_data[0]['recurrence'])) { $attachment_data[0]['recurrence'] = array(); } $attachment_data[0]['recurrence']['recur'] = $this->_parseRecurrence($value); break; case self::MAPI_RECURRING: if (empty($attachment_data[0]['recurrence'])) { $attachment_data[0]['recurrence'] = array(); } break; case self::MAPI_RECURRENCE_TYPE: $attachment_data[0]['recurrence']['type'] = $value; break; case self::MAPI_MEETING_REQUEST_TYPE: $attachment_data[0]['type'] = $value; break; case self::MAPI_CREATION_TIME: try { $attachment_data[0]['created'] = new Horde_Date(Horde_Mapi::filetimeToUnixtime($value), 'UTC'); } catch (Horde_Mapi_Exception $e) { throw new Horde_Compress_Exception($e); } break; case self::MAPI_MODIFICATION_TIME: try { $attachment_data[0]['modified'] = new Horde_Date(Horde_Mapi::filetimeToUnixtime($value), 'UTC'); } catch (Horde_Mapi_Exception $e) { throw new Horde_Compress_Exception($e); } break; } } }