예제 #1
0
 /**
  * The constructor, which just calls the actual type configured
  */
 function PublicSession()
 {
     global $c;
     $principal = new Principal('username', 'unauthenticated');
     // Assign each field in the selected record to the object
     foreach ($principal as $k => $v) {
         $this->{$k} = $v;
     }
     $this->username = $principal->username();
     $this->user_no = $principal->user_no();
     $this->principal_id = $principal->principal_id();
     $this->email = $principal->email();
     $this->dav_name = $principal->dav_name();
     $this->principal = $principal;
     if (function_exists("awl_set_locale") && isset($this->locale) && $this->locale != "") {
         awl_set_locale($this->locale);
     }
     $this->groups = isset($c->public_groups) ? $c->public_groups : array();
     $this->roles = array('Public' => true);
     $this->logged_in = false;
 }
예제 #2
0
/**
* Creates some default home collections for the user.
* @param string $username The username of the user we are creating relationships for.
*/
function CreateHomeCollections($username, $defult_timezone = null)
{
    global $session, $c;
    if (!isset($c->default_collections)) {
        $c->default_collections = array();
        if (!empty($c->home_calendar_name)) {
            $c->default_collections[] = array('type' => 'calendar', 'name' => $c->home_calendar_name);
        }
        if (!empty($c->home_addressbook_name)) {
            $c->default_collections[] = array('type' => 'addressbook', 'name' => $c->home_addressbook_name);
        }
    }
    if (!is_array($c->default_collections) || !count($c->default_collections)) {
        return true;
    }
    $principal = new Principal('username', $username);
    $user_fullname = $principal->fullname;
    // user fullname
    $user_rfullname = implode(' ', array_reverse(explode(' ', $principal->fullname)));
    // user fullname in reverse order
    $sql = 'INSERT INTO collection (user_no, parent_container, dav_name, dav_etag, dav_displayname, is_calendar, is_addressbook, default_privileges, created, modified, resourcetypes) ';
    $sql .= 'VALUES( :user_no, :parent_container, :collection_path, :dav_etag, :displayname, :is_calendar, :is_addressbook, :privileges::BIT(24), current_timestamp, current_timestamp, :resourcetypes );';
    foreach ($c->default_collections as $v) {
        if ($v['type'] == 'calendar' || $v['type'] == 'addressbook') {
            if (!empty($v['name'])) {
                $qry = new AwlQuery('SELECT 1 FROM collection WHERE dav_name = :dav_name', array(':dav_name' => $principal->dav_name() . $v['name'] . '/'));
                if (!$qry->Exec()) {
                    $c->messages[] = i18n('There was an error reading from the database.');
                    return false;
                }
                if ($qry->rows() > 0) {
                    $c->messages[] = i18n('Home ' . ($v['type'] == 'calendar' ? 'calendar' : 'addressbook') . ' already exists.');
                    return true;
                } else {
                    $params[':user_no'] = $principal->user_no();
                    $params[':parent_container'] = $principal->dav_name();
                    $params[':dav_etag'] = '-1';
                    $params[':collection_path'] = $principal->dav_name() . $v['name'] . '/';
                    $params[':displayname'] = !isset($v['displayname']) || empty($v['displayname']) ? $user_fullname . ($v['type'] == 'calendar' ? ' calendar' : ' addressbook') : str_replace(array('%fn', '%rfn'), array($user_fullname, $user_rfullname), $v['displayname']);
                    $params[':resourcetypes'] = $v['type'] == 'calendar' ? '<DAV::collection/><urn:ietf:params:xml:ns:caldav:calendar/>' : '<DAV::collection/><urn:ietf:params:xml:ns:carddav:addressbook/>';
                    $params[':is_calendar'] = $v['type'] == 'calendar' ? true : false;
                    $params[':is_addressbook'] = $v['type'] == 'addressbook' ? true : false;
                    $params[':privileges'] = !isset($v['privileges']) || $v['privileges'] === null ? null : privilege_to_bits($v['privileges']);
                    $qry = new AwlQuery($sql, $params);
                    if ($qry->Exec()) {
                        $c->messages[] = i18n('Home ' . ($v['type'] == 'calendar' ? 'calendar' : 'addressbook') . ' added.');
                        dbg_error_log("User", ":Write: Created user's home " . ($v['type'] == 'calendar' ? 'calendar' : 'addressbook') . " at '%s'", $params[':collection_path']);
                        // create value for urn:ietf:params:xml:ns:caldav:supported-calendar-component-set property
                        if ($v['type'] == 'calendar' && isset($v['calendar_components']) && $v['calendar_components'] != null && is_array($v['calendar_components']) && count($v['calendar_components'])) {
                            // convert the array to uppercase and allow only real calendar compontents
                            $components_clean = array_intersect(array_map("strtoupper", $v['calendar_components']), array('VEVENT', 'VTODO', 'VJOURNAL', 'VTIMEZONE', 'VFREEBUSY', 'VPOLL', 'VAVAILABILITY'));
                            // convert the $components_clean array to XML string
                            $result_xml = '';
                            foreach ($components_clean as $curr) {
                                $result_xml .= sprintf('<comp name="%s" xmlns="urn:ietf:params:xml:ns:caldav"/>', $curr);
                            }
                            // handle the components XML string as user defined property (see below)
                            if ($result_xml != '') {
                                $v['default_properties']['urn:ietf:params:xml:ns:caldav:supported-calendar-component-set'] = $result_xml;
                            }
                        }
                        // store all user defined properties (note: it also handles 'calendar_components' - see above)
                        if (isset($v['default_properties']) && $v['default_properties'] != null && is_array($v['default_properties']) && count($v['default_properties'])) {
                            $sql2 = 'INSERT INTO property (dav_name, property_name, property_value, changed_on, changed_by) ';
                            $sql2 .= 'VALUES (:collection_path, :property_name, :property_value, current_timestamp, :user_no);';
                            $params2[':user_no'] = $principal->user_no();
                            $params2[':collection_path'] = $principal->dav_name() . $v['name'] . '/';
                            foreach ($v['default_properties'] as $key => $val) {
                                $params2[':property_name'] = $key;
                                $params2[':property_value'] = $val;
                                $qry2 = new AwlQuery($sql2, $params2);
                                if ($qry2->Exec()) {
                                    dbg_error_log("User", ":Write: Created property '%s' for " . ($v['type'] == 'calendar' ? 'calendar' : 'addressbook') . " at '%s'", $params2[':property_name'], $params2[':collection_path']);
                                } else {
                                    $c->messages[] = i18n("There was an error writing to the database.");
                                    return false;
                                }
                            }
                        }
                    } else {
                        $c->messages[] = i18n("There was an error writing to the database.");
                        return false;
                    }
                }
            }
        }
    }
    return true;
}
예제 #3
0
/**
* Create/Update the scheduling requests for this resource.  This includes updating
* the scheduled user's default calendar.
* @param vComponent $resource The VEVENT/VTODO/... resource we are scheduling
* @param boolean $create true if the scheduling requests are being created.
* @return true If there was any scheduling action
*/
function do_scheduling_requests(vCalendar $resource, $create, $old_data = null, $remoteAttendee = false)
{
    global $request, $c;
    if (!isset($request) || isset($c->enable_auto_schedule) && !$c->enable_auto_schedule) {
        return false;
    }
    if (!is_object($resource)) {
        trace_bug('do_scheduling_requests called with non-object parameter (%s)', gettype($resource));
        return false;
    }
    $organizer = $resource->GetOrganizer();
    if ($organizer === false || empty($organizer)) {
        dbg_error_log('PUT', 'Event has no organizer - no scheduling required.');
        return false;
    }
    $organizer_email = preg_replace('/^mailto:/i', '', $organizer->Value());
    if ($request->principal->email() != $organizer_email) {
        return do_scheduling_reply($resource, $organizer);
    }
    $schedule_request = clone $resource;
    $schedule_request->AddProperty('METHOD', 'REQUEST');
    $old_attendees = array();
    if (!empty($old_data)) {
        $old_resource = new vCalendar($old_data);
        $old_attendees = $old_resource->GetAttendees();
    }
    $attendees = $resource->GetAttendees();
    if (count($attendees) == 0 && count($old_attendees) == 0) {
        dbg_error_log('PUT', 'Event has no attendees - no scheduling required.', count($attendees));
        return false;
    }
    $removed_attendees = array();
    foreach ($old_attendees as $attendee) {
        $email = preg_replace('/^mailto:/i', '', $attendee->Value());
        if ($email == $request->principal->email()) {
            continue;
        }
        $removed_attendees[$email] = $attendee;
    }
    $uids = $resource->GetPropertiesByPath('/VCALENDAR/*/UID');
    if (count($uids) == 0) {
        dbg_error_log('PUT', 'No UID in VCALENDAR - giving up on REPLY.');
        return false;
    }
    $uid = $uids[0]->Value();
    dbg_error_log('PUT', 'Writing scheduling resources for %d attendees', count($attendees));
    $scheduling_actions = false;
    foreach ($attendees as $attendee) {
        $email = preg_replace('/^mailto:/i', '', $attendee->Value());
        if ($email == $request->principal->email()) {
            dbg_error_log("PUT", "not delivering to owner '%s'", $request->principal->email());
            continue;
        }
        if ($create) {
            $attendee_is_new = true;
        } else {
            $attendee_is_new = !isset($removed_attendees[$email]);
            if (!$attendee_is_new) {
                unset($removed_attendees[$email]);
            }
        }
        $agent = $attendee->GetParameterValue('SCHEDULE-AGENT');
        if ($agent && $agent != 'SERVER') {
            dbg_error_log("PUT", "not delivering to %s, schedule agent set to value other than server", $email);
            continue;
        }
        $schedule_target = new Principal('email', $email);
        $response = '3.7';
        // Attendee was not found on server.
        dbg_error_log('PUT', 'Handling scheduling resources for %s on %s which is %s', $email, $create ? 'create' : 'update', $attendee_is_new ? 'new' : 'an update');
        if ($schedule_target->Exists()) {
            // Instead of always writing to schedule-default-calendar, we first try to
            // find a calendar with an existing instance of the event.
            $sql = 'SELECT caldav_data.dav_name, caldav_data.caldav_data, caldav_data.collection_id FROM caldav_data JOIN calendar_item USING(dav_id) ';
            $sql .= 'WHERE caldav_data.collection_id IN (SELECT collection_id FROM collection WHERE is_calendar AND user_no =?) ';
            $sql .= 'AND uid=? LIMIT 1';
            $qry = new AwlQuery($sql, $schedule_target->user_no(), $uid);
            if (!$qry->Exec('PUT', __LINE__, __FILE__) || $qry->rows() < 1) {
                dbg_error_log('PUT', "Could not find event in attendee's calendars");
                $attendee_calendar = new WritableCollection(array('path' => $schedule_target->internal_url('schedule-default-calendar')));
            } else {
                $row = $qry->Fetch();
                $r = new DAVResource($row);
                $attendee_calendar = new WritableCollection(array('path' => $r->parent_path()));
                if ($attendee_calendar->IsCalendar()) {
                    dbg_error_log('XXX', "found the event in attendee's calendar %s", $attendee_calendar->dav_name());
                } else {
                    dbg_error_log('XXX', 'could not find the event in any calendar, using schedule-default-calendar');
                    $attendee_calendar = new WritableCollection(array('path' => $schedule_target->internal_url('schedule-default-calendar')));
                }
            }
            if (!$attendee_calendar->Exists()) {
                dbg_error_log('ERROR', 'Default calendar at "%s" does not exist for user "%s"', $attendee_calendar->dav_name(), $schedule_target->username());
                $response = '5.2';
                // No scheduling support for user
            } else {
                $attendee_inbox = new WritableCollection(array('path' => $schedule_target->internal_url('schedule-inbox')));
                if (!$attendee_inbox->HavePrivilegeTo('schedule-deliver-invite')) {
                    $response = '3.8';
                    // No authority to deliver invitations to user.
                } else {
                    if ($attendee_inbox->WriteCalendarMember($schedule_request, $attendee_is_new) !== false) {
                        $response = '1.2';
                        // Scheduling invitation delivered successfully
                        if ($attendee_calendar->WriteCalendarMember($resource, $attendee_is_new) === false) {
                            dbg_error_log('ERROR', 'Could not write %s calendar member to %s', $attendee_is_new ? 'new' : 'updated', $attendee_calendar->dav_name(), $attendee_calendar->dav_name(), $schedule_target->username());
                            trace_bug('Failed to write scheduling resource.');
                        }
                    }
                }
            }
        } else {
            if ($remoteAttendee) {
                $attendee->is_remote = true;
                $remote = new iSchedule();
                $answer = $remote->sendRequest($email, 'VEVENT/REQUEST', $schedule_request->Render());
            } else {
                $remote = new iSchedule();
                $answer = $remote->sendRequest($email, 'VEVENT/REQUEST', $schedule_request->Render());
                if ($answer === false) {
                    $response = "3.7;Invalid Calendar User";
                } else {
                    foreach ($answer as $a) {
                        if ($a === false) {
                            $response = "3.7;Invalid Calendar User";
                        } elseif (substr($a, 0, 1) >= 1) {
                            $response = $a;
                        } else {
                            $response = "2.0;Success";
                        }
                    }
                }
            }
        }
        dbg_error_log('PUT', 'Status for attendee <%s> set to "%s"', $attendee->Value(), $response);
        $attendee->SetParameterValue('SCHEDULE-STATUS', $response);
        $scheduling_actions = true;
    }
    if (!$create) {
        foreach ($removed_attendees as $attendee) {
            $schedule_target = new Principal('email', $email);
            if ($schedule_target->Exists()) {
                $attendee_calendar = new WritableCollection(array('path' => $schedule_target->internal_url('schedule-default-calendar')));
            }
        }
    }
    return $scheduling_actions;
}
예제 #4
0
 static function importFromDirectory()
 {
     global $c;
     if (empty($_POST["calendar_path"])) {
         dbg_error_log("importFromDirectory", "calendar path not given");
         return;
     }
     $path_ics = $_POST["calendar_path"];
     if (substr($path_ics, -1, 1) != '/') {
         $path_ics .= '/';
     }
     // ensure that we target a collection
     if (substr($path_ics, 0, 1) != '/') {
         $path_ics = '/' . $path_ics;
     }
     // ensure that we target a collection
     if (empty($_POST["directory_path"])) {
         dbg_error_log("importFromDirectory", "directory path not given");
         return;
     }
     $dir = $_POST["directory_path"];
     if (!is_readable($dir)) {
         $c->messages[] = sprintf(i18n('directory %s is not readable'), htmlspecialchars($dir));
         dbg_error_log("importFromDirectory", "directory is not readable");
         return;
     }
     if ($handle = opendir($dir)) {
         $c->readonly_webdav_collections = false;
         // Override this setting so we can create collections/events on import.
         while (false !== ($file = readdir($handle))) {
             if ($file == "." || $file == ".." || substr($file, -4) != '.ics') {
                 continue;
             }
             if (!is_readable($dir . '/' . $file)) {
                 dbg_error_log("importFromDirectory", "ics file '%s' is not readable", $dir . '/' . $file);
                 continue;
             }
             $ics = file_get_contents($dir . '/' . $file);
             $ics = trim($ics);
             if ($ics != '') {
                 if (!check_string($ics)) {
                     $c->messages[] = sprintf(translate('The file "%s" is not UTF-8 encoded, please check error for more details'), $dir . '/' . $file);
                     continue;
                 }
                 $username = substr($file, 0, -4);
                 $principal = new Principal('username', $username);
                 if (!$principal->Exists()) {
                     $c->messages[] = sprintf(translate('The principal "%s" does not exist'), $username);
                     continue;
                 }
                 $path = "/" . $username . $path_ics;
                 $user_no = $principal->user_no();
                 if (controlRequestContainer($username, $user_no, $path, false) === -1) {
                     continue;
                 }
                 dbg_error_log("importFromDirectory", "importing to {$path}");
                 import_collection($ics, $user_no, $path, 1);
                 $c->messages[] = sprintf(translate('All events of user "%s" were deleted and replaced by those from file %s'), substr($file, 0, -4), $dir . '/' . $file);
             }
         }
         closedir($handle);
     }
 }
예제 #5
0
/**
 * Does the actual processing of the iTIP CANCEL message on behalf of an ATTENDEE,
 * which generally means writing it into the ATTENDEE's default calendar.
 * 
 * @param vCalendar $vcal The message.
 * @param vProperty $attendee
 * @param WritableCollection $attendee_calendar
 */
function processItipCancel(vCalendar $vcal, vProperty $attendee, WritableCollection $attendee_calendar, Principal $attendee_principal)
{
    global $request;
    dbg_error_log('schedule', 'Processing iTIP CANCEL to %s', $attendee->Value());
    header("Debug: Could maybe do the iMIP message dance for attendee " . $attendee->Value());
    if (!$attendee_calendar->Exists()) {
        if (doImipMessage('CANCEL', $attendee_principal->email(), $vcal)) {
            return '1.1';
            // Scheduling whoosit 'Sent'
        } else {
            dbg_error_log('ERROR', 'Default calendar at "%s" does not exist for attendee "%s"', $attendee_calendar->dav_name(), $attendee->Value());
            return '5.2';
            // No scheduling support for user
        }
    }
    $sql = 'SELECT caldav_data.dav_name FROM caldav_data JOIN calendar_item USING(dav_id) ';
    $sql .= 'WHERE caldav_data.collection_id IN (SELECT collection_id FROM collection WHERE is_calendar AND user_no =?) ';
    $sql .= 'AND uid=? LIMIT 1';
    $uids = $vcal->GetPropertiesByPath('/VCALENDAR/*/UID');
    if (count($uids) == 0) {
        dbg_error_log('schedule', 'No UID in VCALENDAR - giving up on CANCEL processing.');
        return '3.8';
    }
    $uid = $uids[0]->Value();
    $qry = new AwlQuery($sql, $attendee_principal->user_no(), $uid);
    if (!$qry->Exec('schedule', __LINE__, __FILE__) || $qry->rows() < 1) {
        dbg_error_log('schedule', 'Could not find ATTENDEE copy of original event - not trying to DELETE it!');
        return '1.2';
    }
    $row = $qry->Fetch();
    if ($attendee_calendar->actualDeleteCalendarMember($row->dav_name) === false) {
        dbg_error_log('ERROR', 'Could not delete calendar member %s for %s', $row->dav_name(), $attendee->Value());
        trace_bug('Failed to write scheduling resource.');
        return '5.2';
    }
    return '1.2';
    // Scheduling invitation delivered successfully
}