⚝
One Hat Cyber Team
⚝
Your IP:
216.73.216.78
Server IP:
41.128.143.86
Server:
Linux host.raqmix.cloud 6.8.0-1025-azure #30~22.04.1-Ubuntu SMP Wed Mar 12 15:28:20 UTC 2025 x86_64
Server Software:
Apache
PHP Version:
8.3.23
Buat File
|
Buat Folder
Eksekusi
Dir :
~
/
usr
/
share
/
psa-pear
/
pear
/
php
/
Horde
/
Compress
/
Tnef
/
View File Name :
Icalendar.php
* @category Horde * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 * @package Compress */ /** * Object to parse and represent iCalendar data encapsulated in a TNEF file. * * @author Michael J Rubinsky
* @category Horde * @copyright 2002-2017 Horde LLC * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 * @package Compress */ class Horde_Compress_Tnef_Icalendar extends Horde_Compress_Tnef_Object { const PART_ACTION = 'NEEDS-ACTION'; const PART_TENTATIVE = 'TENTATIVE'; const PART_DECLINE = 'DECLINE'; const PART_ACCEPTED = 'ACCEPTED'; /** * ICalendar METHOD * * @var string */ protected $_method; /** * * @var string */ protected $_summary; /** * * @var string */ protected $_location; /** * * @var string */ protected $_url; /** * * @var Horde_Date */ protected $_startUtc; /** * * @var Horde_Date */ protected $_endUtc; /** * * @var string */ protected $_duration; /** * * @var boolean */ protected $_allday; /** * * @var string */ protected $_organizer; /** * * @var string */ protected $_lastModifier; /** * The "From" attribute used by iTip responses. * * @var string */ protected $_from; /** * * @var string */ protected $_uid; /** * Recurrence data. * * @var array */ protected $_recurrence = array(); /** * * @var integer */ protected $_type; /** * * @var Horde_Date */ protected $_created; /** * * @var Horde_Date */ protected $_modified; /** * Cache of the iCalendar text. * * @var string */ protected $_content; /** * List of required attendees parsed from the MAPI object. * * @var string */ protected $_requiredAttendees; /** * The current PARTSTAT property for this meeting request. * * @var string A self::PART_* constant. */ protected $_partStat; /** * The description/body of the meeting request. * * @var string */ protected $_description; /** * RSVP property * * @var boolean */ protected $_rsvp = false; /** * MIME type. * * @var string */ public $type = 'text/calendar'; /** * Accessor * * @param string $property * @return mixed */ public function __get($property) { if ($property == 'content') { if (empty($this->_content)) { $this->_toItip(); return $this->_content; } } throw new InvalidArgumentException('Invalid property access.'); } /** * Output the data for this object in an array. * * @return array * - type: (string) The MIME type of the content. * - subtype: (string) The MIME subtype. * - name: (string) The filename. * - stream: (string) The file data. */ public function toArray() { return $this->_toItip(); } /** * Set the METHOD parameter, used to help generate the PART-STAT attribute. * * @param string $method The METHOD parameter. * @param string $class The message class. */ public function setMethod($method, $class = null) { $this->_method = $method; switch ($class) { case Horde_Compress_Tnef::IPM_MEETING_RESPONSE_TENT: $this->_partStat = self::PART_TENTATIVE; $this->_rsvp = false; break; case Horde_Compress_Tnef::IPM_MEETING_RESPONSE_NEG: $this->_partStat = self::PART_DECLINE; $this->_rsvp = false; break; case Horde_Compress_Tnef::IPM_MEETING_RESPONSE_POS: $this->_partStat = self::PART_ACCEPTED; $this->_rsvp = false; break; case Horde_Compress_Tnef::IPM_MEETING_REQUEST: $this->_partStat =self::PART_ACTION; $this->_rsvp = true; break; } } /** * Allow this object to set any TNEF attributes it needs to know about, * ignore any it doesn't care about. * * @param integer $attribute The attribute descriptor. * @param mixed $value The value from the MAPI stream. * @param integer $size The byte length of the data, as reported by * the MAPI data. */ public function setTnefAttribute($attribute, $value, $size) { switch ($attribute) { case Horde_Compress_Tnef::ABODY; $this->_description = $value; break; } } /** * 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)); } } /** * Parse recurrence properties. * * @param string $value MAPI stream * * @return Horde_Date_Recurrence * @throws Horde_Compress_Exception */ protected function _parseRecurrence($value) { $deleted = $modified = array(); // both are 0x3004 (version strings); $this->_geti($value, 16); $this->_geti($value, 16); $freq = $this->_geti($value, 16); $pattern = $this->_geti($value, 16); $calendarType = $this->_geti($value, 16); $firstDt = $this->_geti($value, 32); $period = $this->_geti($value, 32); // Only used for tasks, otherwise value must be zero. $flag = $this->_geti($value, 32); // TypeSpecific field switch ($pattern) { case Horde_Compress_Tnef::PATTERN_DAY: // Nothing here to see, move along. break; case Horde_Compress_Tnef::PATTERN_WEEK: // Bits: 0/unused, 1/Saturday, 2/Friday, 3/Thursday, 4/Wednesday, // 5/Tuesday, 6/Monday, 7/Sunday. $day = $this->_geti($value, 8); // ?? $this->_geti($value, 24); break; case Horde_Compress_Tnef::PATTERN_MONTH: case Horde_Compress_Tnef::PATTERN_MONTH_END: // Day of month on which the recurrence falls. $day = $this->_geti($value, 32); break; case Horde_Compress_Tnef::PATTERN_MONTH_NTH: // Bits: 0/unused, 1/Saturday, 2/Friday, 3/Thursday, 4/Wednesday, // 5/Tuesday, 6/Monday, 7/Sunday. // For Nth Weekday of month $day = $this->_geti($value, 8); $this->_geti($value, 24); $n = $this->_geti($value, 32); break; } $end = $this->_geti($value, 32); $count = $this->_geti($value, 32); $fdow = $this->_geti($value, 32); $deletedCount = $this->_geti($value, 32); for ($i = 0; $i < $deletedCount; $i++) { $deleted[] = $this->_geti($value, 32); } $modifiedCount = $this->_geti($value, 32); for ($i = 0; $i < $modifiedCount; $i++) { $modified[] = $this->_geti($value, 32); } // What Timezone are these in? try { $startDate = new Horde_Date(Horde_Mapi::filetimeToUnixtime($this->_geti($value, 32))); $endDate = new Horde_Date(Horde_Mapi::filetimeToUnixtime($this->_geti($value, 32))); } catch (Horde_Mapi_Exception $e) { throw new Horde_Compress_Exception($e); } catch (Horde_Date_Exception $e) { throw new Horde_Compress_Exception($e); } $rrule = new Horde_Date_Recurrence($startDate); switch ($pattern) { case Horde_Compress_Tnef::PATTERN_DAY: $rrule->setRecurType(Horde_Date_Recurrence::RECUR_DAILY); break; case Horde_Compress_Tnef::PATTERN_WEEK: $rrule->setRecurType(Horde_Date_Recurrence::RECUR_WEEKLY); break; case Horde_Compress_Tnef::PATTERN_MONTH: case Horde_Compress_Tnef::PATTERN_MONTH_END: $rrule->setRecurType(Horde_Date_Recurrence::RECUR_MONTHLY_DATE); break; case Horde_Compress_Tnef::PATTERN_MONTH_NTH: $rrule->setRecurType(Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY); break; default: if ($freq == Horde_Compress_Tnef::RECUR_YEARLY) { $rrule->setRecurType(Horde_Date_Recurrence::RECUR_YEARLY); } } switch ($end) { case Horde_Compress_Tnef::RECUR_END_N: $rrule->setRecurCount($count); break; case Horde_Compress_Tnef::RECUR_END_DATE: $rrule->setRecurEnd($endDate); break; } return $rrule; } /** * Generate an iTip from embedded TNEF MEETING data. * * @return array see @self::toArray(). */ protected function _toItip() { $iCal = new Horde_Icalendar(); // METHOD if ($this->_type) { switch ($this->_type) { case Horde_Compress_Tnef::MAPI_MEETING_INITIAL: case Horde_Compress_Tnef::MAPI_MEETING_FULL_UPDATE: $this->_method = 'REQUEST'; break; case Horde_Compress_Tnef::MAPI_MEETING_INFO: $this->_method = 'PUBLISH'; break; } } $iCal->setAttribute('METHOD', $this->_method); // VEVENT $vEvent = Horde_Icalendar::newComponent('vevent', $iCal); if (empty($this->_endUtc)) { return; } $end = clone $this->_endUtc; $end->sec++; if ($this->_allday) { $vEvent->setAttribute('DTSTART', $this->_startUtc, array('VALUE' => 'DATE')); $vEvent->setAttribute('DTEND', $end, array('VALUE' => 'DATE')); } else { $vEvent->setAttribute('DTSTART', $this->_startUtc); $vEvent->setAttribute('DTEND', $end); } $vEvent->setAttribute('DTSTAMP', $_SERVER['REQUEST_TIME']); $vEvent->setAttribute('UID', $this->_uid); if ($this->_created) { $vEvent->setAttribute('CREATED', $this->_created); } if ($this->_modified) { $vEvent->setAttribute('LAST-MODIFIED', $this->_modified); } // SUMMARY and DESCRIPTION $vEvent->setAttribute('SUMMARY', $this->_summary); if ($this->_description) { $vEvent->setAttribute('DESCRIPTION', trim($this->_description)); } // ORGANIZER if (!$this->_organizer && $this->_lastModifier) { $email = $this->_lastModifier; } else if ($this->_organizer) { $email = $this->_organizer; } if (!empty($email)) { $vEvent->setAttribute('ORGANIZER', 'mailto:' . $email); } // ATTENDEE if (empty($this->_requiredAttendees) && $this->_method == 'REPLY') { $this->_requiredAttendees = $this->_from; } if (!empty($this->_requiredAttendees)) { $list = new Horde_Mail_Rfc822_List($this->_requiredAttendees); foreach ($list as $email) { $params = array('ROLE' => 'REQ-PARTICIPANT'); if (!empty($this->_partStat)) { $params['PARTSTAT'] = $this->_partStat; } if ($this->_rsvp) { $params['RSVP'] = 'TRUE'; } $vEvent->setAttribute('ATTENDEE', $email->bare_address, $params); } } // LOCATION if ($this->_location) { $vEvent->setAttribute('LOCATION', $this->_location); } // URL if ($this->_url) { $vEvent->setAttribute('URL', $this->_url); } // RECUR if (!empty($this->_recurrence['recur'])) { $rrule = $this->_recurrence['recur']->toRRule20($iCal); $vEvent->setAttribute('RRULE', $rrule); } $iCal->addComponent($vEvent); $this->_content = $iCal->exportvCalendar(); return array( 'type' => 'text', 'subtype' => 'calendar', 'name' => $this->_summary, 'stream' => $this->_content ); } }