Esempio n. 1
0
/**
 * Converts a text/calendar part into SyncMeetingRequest
 * This is called on received messages, it's not called for events generated from the mobile
 *
 * @access private
 * @param $part             MIME part
 * @param $output           SyncMail object
 * @param $is_sent_folder   boolean
 */
function parse_meeting_calendar($part, &$output, $is_sent_folder)
{
    $ical = new iCalComponent();
    $ical->ParseFrom($part->body);
    ZLog::Write(LOGLEVEL_WBXML, sprintf("BackendIMAP->parse_meeting_calendar(): %s", $part->body));
    // Get UID
    $uid = false;
    $props = $ical->GetPropertiesByPath("VEVENT/UID");
    if (count($props) > 0) {
        $uid = $props[0]->Value();
    }
    $method = false;
    $props = $ical->GetPropertiesByPath("VCALENDAR/METHOD");
    if (count($props) > 0) {
        $method = strtolower($props[0]->Value());
        ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->parse_meeting_calendar(): Using method from vcalendar object: %s", $method));
    } else {
        if (isset($part->ctype_parameters["method"])) {
            $method = strtolower($part->ctype_parameters["method"]);
            ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->parse_meeting_calendar(): Using method from mime part object: %s", $method));
        }
    }
    if ($method === false) {
        ZLog::Write(LOGLEVEL_WARN, sprintf("BackendIMAP->parse_meeting_calendar() - No method header, please report it to the developers"));
        $output->messageclass = "IPM.Appointment";
    } else {
        switch ($method) {
            case "cancel":
                $output->messageclass = "IPM.Schedule.Meeting.Canceled";
                $output->meetingrequest->disallownewtimeproposal = 1;
                ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Event canceled, removing calendar object");
                delete_calendar_dav($uid);
                break;
            case "counter":
                ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Counter received");
                $output->messageclass = "IPM.Schedule.Meeting.Resp.Tent";
                $output->meetingrequest->disallownewtimeproposal = 0;
                break;
            case "reply":
                ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Reply received");
                $props = $ical->GetPropertiesByPath('VEVENT/ATTENDEE');
                for ($i = 0; $i < count($props); $i++) {
                    $mailto = $props[$i]->Value();
                    $props_params = $props[$i]->Parameters();
                    $status = strtolower($props_params["PARTSTAT"]);
                    if (!$is_sent_folder) {
                        // Only evaluate received replies, not sent
                        $res = update_calendar_attendee($uid, $mailto, $status);
                    } else {
                        $res = true;
                    }
                    if ($res) {
                        // Only set messageclass for replies changing my calendar object
                        switch ($status) {
                            case "accepted":
                                $output->messageclass = "IPM.Schedule.Meeting.Resp.Pos";
                                ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Update attendee -> accepted");
                                break;
                            case "needs-action":
                                $output->messageclass = "IPM.Schedule.Meeting.Resp.Tent";
                                ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Update attendee -> needs-action");
                                break;
                            case "tentative":
                                $output->messageclass = "IPM.Schedule.Meeting.Resp.Tent";
                                ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Update attendee -> tentative");
                                break;
                            case "declined":
                                $output->messageclass = "IPM.Schedule.Meeting.Resp.Neg";
                                ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): Update attendee -> declined");
                                break;
                            default:
                                ZLog::Write(LOGLEVEL_WARN, sprintf("BackendIMAP->parse_meeting_calendar() - Unknown reply status <%s>, please report it to the developers", $status));
                                $output->messageclass = "IPM.Appointment";
                                break;
                        }
                    }
                }
                $output->meetingrequest->disallownewtimeproposal = 1;
                break;
            case "request":
                $output->messageclass = "IPM.Schedule.Meeting.Request";
                $output->meetingrequest->disallownewtimeproposal = 0;
                ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->parse_meeting_calendar(): New request");
                // New meeting, we don't create it now, because we need to confirm it first, but if we don't create it we won't see it in the calendar
                break;
            default:
                ZLog::Write(LOGLEVEL_WARN, sprintf("BackendIMAP->parse_meeting_calendar() - Unknown method <%s>, please report it to the developers", strtolower($part->headers["method"])));
                $output->messageclass = "IPM.Appointment";
                $output->meetingrequest->disallownewtimeproposal = 0;
                break;
        }
    }
    $props = $ical->GetPropertiesByPath('VEVENT/DTSTAMP');
    if (count($props) == 1) {
        $output->meetingrequest->dtstamp = Utils::MakeUTCDate($props[0]->Value());
    }
    $props = $ical->GetPropertiesByPath('VEVENT/UID');
    if (count($props) == 1) {
        $output->meetingrequest->globalobjid = $props[0]->Value();
    }
    $props = $ical->GetPropertiesByPath('VEVENT/DTSTART');
    if (count($props) == 1) {
        $output->meetingrequest->starttime = Utils::MakeUTCDate($props[0]->Value());
        if (strlen($props[0]->Value()) == 8) {
            $output->meetingrequest->alldayevent = 1;
        }
    }
    $props = $ical->GetPropertiesByPath('VEVENT/DTEND');
    if (count($props) == 1) {
        $output->meetingrequest->endtime = Utils::MakeUTCDate($props[0]->Value());
        if (strlen($props[0]->Value()) == 8) {
            $output->meetingrequest->alldayevent = 1;
        }
    }
    $props = $ical->GetPropertiesByPath('VEVENT/ORGANIZER');
    if (count($props) == 1) {
        $output->meetingrequest->organizer = str_ireplace("MAILTO:", "", $props[0]->Value());
    }
    $props = $ical->GetPropertiesByPath('VEVENT/LOCATION');
    if (count($props) == 1) {
        $output->meetingrequest->location = $props[0]->Value();
    }
    $props = $ical->GetPropertiesByPath('VEVENT/CLASS');
    if (count($props) == 1) {
        switch ($props[0]->Value()) {
            case "PUBLIC":
                $output->meetingrequest->sensitivity = "0";
                break;
            case "PRIVATE":
                $output->meetingrequest->sensitivity = "2";
                break;
            case "CONFIDENTIAL":
                $output->meetingrequest->sensitivity = "3";
                break;
            default:
                ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->parse_meeting_calendar() - No sensitivity class. Using 2"));
                $output->meetingrequest->sensitivity = "2";
                break;
        }
    }
    // Get $tz from first timezone
    $props = $ical->GetPropertiesByPath("VTIMEZONE/TZID");
    if (count($props) > 0) {
        // TimeZones shouldn't have dots
        $tzname = str_replace(".", "", $props[0]->Value());
        $tz = TimezoneUtil::GetFullTZFromTZName($tzname);
    } else {
        $tz = TimezoneUtil::GetFullTZ();
    }
    $output->meetingrequest->timezone = base64_encode(TimezoneUtil::GetSyncBlobFromTZ($tz));
    // Fixed values
    $output->meetingrequest->instancetype = 0;
    $output->meetingrequest->responserequested = 1;
    $output->meetingrequest->busystatus = 2;
    // TODO: reminder
    $output->meetingrequest->reminder = "";
}
 /**
  * Reads an appointment object from MAPI
  *
  * @param mixed             $mapimessage
  * @param ContentParameters $contentparameters
  *
  * @access private
  * @return SyncAppointment
  */
 private function getAppointment($mapimessage, $contentparameters)
 {
     $message = new SyncAppointment();
     // Standard one-to-one mappings first
     $this->getPropsFromMAPI($message, $mapimessage, MAPIMapping::GetAppointmentMapping());
     // Appointment specific props
     $appointmentprops = MAPIMapping::GetAppointmentProperties();
     $messageprops = $this->getProps($mapimessage, $appointmentprops);
     //set the body according to contentparameters and supported AS version
     $this->setMessageBody($mapimessage, $contentparameters, $message);
     // Set reminder time if reminderset is true
     if (isset($messageprops[$appointmentprops["reminderset"]]) && $messageprops[$appointmentprops["reminderset"]] == true) {
         if ($messageprops[$appointmentprops["remindertime"]] == 0x5ae980e1) {
             $message->reminder = 15;
         } else {
             $message->reminder = $messageprops[$appointmentprops["remindertime"]];
         }
     }
     if (!isset($message->uid)) {
         $message->uid = bin2hex($messageprops[$appointmentprops["sourcekey"]]);
     } else {
         $message->uid = Utils::GetICalUidFromOLUid($message->uid);
     }
     // Always set organizer information because some devices do not work properly without it
     if (isset($messageprops[$appointmentprops["representingentryid"]]) && isset($messageprops[$appointmentprops["representingname"]])) {
         $message->organizeremail = w2u($this->getSMTPAddressFromEntryID($messageprops[$appointmentprops["representingentryid"]]));
         $message->organizername = w2u($messageprops[$appointmentprops["representingname"]]);
     }
     if (isset($messageprops[$appointmentprops["timezonetag"]])) {
         $tz = $this->getTZFromMAPIBlob($messageprops[$appointmentprops["timezonetag"]]);
     } else {
         // set server default timezone (correct timezone should be configured!)
         $tz = TimezoneUtil::GetFullTZ();
     }
     $message->timezone = base64_encode($this->getSyncBlobFromTZ($tz));
     if (isset($messageprops[$appointmentprops["isrecurring"]]) && $messageprops[$appointmentprops["isrecurring"]]) {
         // Process recurrence
         $message->recurrence = new SyncRecurrence();
         $this->getRecurrence($mapimessage, $messageprops, $message, $message->recurrence, $tz);
     }
     // Do attendees
     $reciptable = mapi_message_getrecipienttable($mapimessage);
     // Only get first 256 recipients, to prevent possible load issues.
     $rows = mapi_table_queryrows($reciptable, array(PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_SMTP_ADDRESS, PR_ADDRTYPE, PR_RECIPIENT_TRACKSTATUS, PR_RECIPIENT_TYPE), 0, 256);
     // Exception: we do not synchronize appointments with more than 250 attendees
     if (count($rows) > 250) {
         $message->id = bin2hex($messageprops[$appointmentprops["sourcekey"]]);
         $mbe = new SyncObjectBrokenException("Appointment has too many attendees");
         $mbe->SetSyncObject($message);
         throw $mbe;
     }
     if (count($rows) > 0) {
         $message->attendees = array();
     }
     foreach ($rows as $row) {
         $attendee = new SyncAttendee();
         $attendee->name = w2u($row[PR_DISPLAY_NAME]);
         //smtp address is always a proper email address
         if (isset($row[PR_SMTP_ADDRESS])) {
             $attendee->email = w2u($row[PR_SMTP_ADDRESS]);
         } elseif (isset($row[PR_ADDRTYPE]) && isset($row[PR_EMAIL_ADDRESS])) {
             //if address type is SMTP, it's also a proper email address
             if ($row[PR_ADDRTYPE] == "SMTP") {
                 $attendee->email = w2u($row[PR_EMAIL_ADDRESS]);
             } elseif ($row[PR_ADDRTYPE] == "ZARAFA") {
                 $userinfo = mapi_zarafa_getuser_by_name($this->store, $row[PR_EMAIL_ADDRESS]);
                 if (is_array($userinfo) && isset($userinfo["emailaddress"])) {
                     $attendee->email = w2u($userinfo["emailaddress"]);
                 }
             }
         }
         //set attendee's status and type if they're available
         if (isset($row[PR_RECIPIENT_TRACKSTATUS])) {
             $attendee->attendeestatus = $row[PR_RECIPIENT_TRACKSTATUS];
         }
         if (isset($row[PR_RECIPIENT_TYPE])) {
             $attendee->attendeetype = $row[PR_RECIPIENT_TYPE];
         }
         // Some attendees have no email or name (eg resources), and if you
         // don't send one of those fields, the phone will give an error ... so
         // we don't send it in that case.
         // also ignore the "attendee" if the email is equal to the organizers' email
         if (isset($attendee->name) && isset($attendee->email) && $attendee->email != "" && (!isset($message->organizeremail) || isset($message->organizeremail) && $attendee->email != $message->organizeremail)) {
             array_push($message->attendees, $attendee);
         }
     }
     // Status 0 = no meeting, status 1 = organizer, status 2/3/4/5 = tentative/accepted/declined/notresponded
     if (isset($messageprops[$appointmentprops["meetingstatus"]]) && $messageprops[$appointmentprops["meetingstatus"]] > 1) {
         // Work around iOS6 cancellation issue when there are no attendees for this meeting. Just add ourselves as the sole attendee.
         if (count($message->attendees) == 0) {
             if (!isset($message->attendees) || !is_array($message->attendees)) {
                 $message->attendees = array();
             }
             ZLog::Write(LOGLEVEL_DEBUG, sprintf("MAPIProvider->getAppointment: adding ourself as an attendee for iOS6 workaround"));
             $attendee = new SyncAttendee();
             $meinfo = mapi_zarafa_getuser_by_name($this->store, Request::GetAuthUser());
             if (is_array($meinfo)) {
                 $attendee->email = w2u($meinfo["emailaddress"]);
                 $attendee->name = w2u($meinfo["fullname"]);
                 $attendee->attendeetype = MAPI_TO;
                 array_push($message->attendees, $attendee);
             }
         }
     }
     if (!isset($message->nativebodytype)) {
         $message->nativebodytype = $this->getNativeBodyType($messageprops);
     }
     return $message;
 }
Esempio n. 3
0
 /**
  * Converts a text/calendar part into SyncMeetingRequest
  *
  * @access private
  * @param $part    MIME part
  * @param $output  SyncMail object
  */
 private function parseMeetingCalendar($part, &$output)
 {
     $ical = new iCalComponent();
     $ical->ParseFrom($part->body);
     if (isset($part->ctype_parameters["method"])) {
         switch (strtolower($part->ctype_parameters["method"])) {
             case "cancel":
                 $output->messageclass = "IPM.Schedule.Meeting.Canceled";
                 break;
             case "counter":
                 $output->messageclass = "IPM.Schedule.Meeting.Resp.Tent";
                 break;
             case "reply":
                 $props = $ical->GetPropertiesByPath('!VTIMEZONE/ATTENDEE');
                 if (count($props) == 1) {
                     $props_params = $props[0]->Parameters();
                     if (isset($props_params["PARTSTAT"])) {
                         switch (strtolower($props_params["PARTSTAT"])) {
                             case "accepted":
                                 $output->messageclass = "IPM.Schedule.Meeting.Resp.Pos";
                                 break;
                             case "needs-action":
                             case "tentative":
                                 $output->messageclass = "IPM.Schedule.Meeting.Resp.Tent";
                                 break;
                             case "declined":
                                 $output->messageclass = "IPM.Schedule.Meeting.Resp.Neg";
                                 break;
                             default:
                                 ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->parseMeetingCalendar() - Unknown reply status %s", strtolower($props_params["PARTSTAT"])));
                                 $output->messageclass = "IPM.Appointment";
                                 break;
                         }
                     } else {
                         ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->parseMeetingCalendar() - No reply status found"));
                         $output->messageclass = "IPM.Appointment";
                     }
                 } else {
                     ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->parseMeetingCalendar() - There are not attendees"));
                     $output->messageclass = "IPM.Appointment";
                 }
                 break;
             case "request":
                 $output->messageclass = "IPM.Schedule.Meeting.Request";
                 break;
             default:
                 ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->parseMeetingCalendar() - Unknown method %s", strtolower($part->headers["method"])));
                 $output->messageclass = "IPM.Appointment";
                 break;
         }
     } else {
         ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->parseMeetingCalendar() - No method header"));
         $output->messageclass = "IPM.Appointment";
     }
     $props = $ical->GetPropertiesByPath('VEVENT/DTSTAMP');
     if (count($props) == 1) {
         $output->meetingrequest->dtstamp = Utils::MakeUTCDate($props[0]->Value());
     }
     $props = $ical->GetPropertiesByPath('VEVENT/UID');
     if (count($props) == 1) {
         $output->meetingrequest->globalobjid = $props[0]->Value();
     }
     $props = $ical->GetPropertiesByPath('VEVENT/DTSTART');
     if (count($props) == 1) {
         $output->meetingrequest->starttime = Utils::MakeUTCDate($props[0]->Value());
         if (strlen($props[0]->Value()) == 8) {
             $output->meetingrequest->alldayevent = 1;
         }
     }
     $props = $ical->GetPropertiesByPath('VEVENT/DTEND');
     if (count($props) == 1) {
         $output->meetingrequest->endtime = Utils::MakeUTCDate($props[0]->Value());
         if (strlen($props[0]->Value()) == 8) {
             $output->meetingrequest->alldayevent = 1;
         }
     }
     $props = $ical->GetPropertiesByPath('VEVENT/ORGANIZER');
     if (count($props) == 1) {
         $output->meetingrequest->organizer = str_ireplace("MAILTO:", "", $props[0]->Value());
     }
     $props = $ical->GetPropertiesByPath('VEVENT/LOCATION');
     if (count($props) == 1) {
         $output->meetingrequest->location = $props[0]->Value();
     }
     $props = $ical->GetPropertiesByPath('VEVENT/CLASS');
     if (count($props) == 1) {
         switch ($props[0]->Value()) {
             case "PUBLIC":
                 $output->meetingrequest->sensitivity = "0";
                 break;
             case "PRIVATE":
                 $output->meetingrequest->sensitivity = "2";
                 break;
             case "CONFIDENTIAL":
                 $output->meetingrequest->sensitivity = "3";
                 break;
             default:
                 ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->parseMeetingCalendar() - No sensitivity class. Using 2"));
                 $output->meetingrequest->sensitivity = "2";
                 break;
         }
     }
     // Get $tz from first timezone
     $props = $ical->GetPropertiesByPath("VTIMEZONE/TZID");
     if (count($props) > 0) {
         // TimeZones shouldn't have dots
         $tzname = str_replace(".", "", $props[0]->Value());
         $tz = TimezoneUtil::GetFullTZFromTZName($tzname);
     } else {
         $tz = TimezoneUtil::GetFullTZ();
     }
     $output->meetingrequest->timezone = base64_encode(TimezoneUtil::getSyncBlobFromTZ($tz));
     // Fixed values
     $output->meetingrequest->instancetype = 0;
     $output->meetingrequest->responserequested = 1;
     $output->meetingrequest->busystatus = 2;
     // TODO: reminder
     $output->meetingrequest->reminder = "";
 }