function query_events($user, $want_repeated, $date_filter, $cat_id = '', $is_task = false)
{
    global $db_connection_info, $jumpdate, $layers, $login, $max_until, $PUBLIC_ACCESS_DEFAULT_VISIBLE, $result, $thismonth, $thisyear;
    global $OVERRIDE_PUBLIC, $OVERRIDE_PUBLIC_TEXT;
    // New multiple categories requires some checking to see if this cat_id is
    // valid for this cal_id. It could be done with nested SQL,
    // but that may not work for all databases. This might be quicker also.
    $catlist = $cloneRepeats = $layers_byuser = $result = array();
    $sql = 'SELECT DISTINCT( cal_id ) FROM webcal_entry_categories ';
    // None was selected...return only events without categories.
    if ($cat_id == -1) {
        $rows = dbi_get_cached_rows($sql, array());
    } elseif (!empty($cat_id)) {
        $cat_array = explode(',', $cat_id);
        $placeholders = '';
        for ($p_i = 0, $cnt = count($cat_array); $p_i < $cnt; $p_i++) {
            $placeholders .= $p_i == 0 ? '?' : ', ?';
        }
        $rows = dbi_get_cached_rows($sql . 'WHERE cat_id IN ( ' . $placeholders . ' )', $cat_array);
    }
    if (!empty($cat_id)) {
        // $rows = dbi_get_cached_rows ( $sql, array ( $cat_id ) );
        if ($rows) {
            for ($i = 0, $cnt = count($rows); $i < $cnt; $i++) {
                $row = $rows[$i];
                $catlist[$i] = $row[0];
            }
        }
    }
    $catlistcnt = count($catlist);
    $query_params = array();
    $sql = 'SELECT we.cal_name, we.cal_description, we.cal_date, we.cal_time,
    we.cal_id, we.cal_ext_for_id, we.cal_priority, we.cal_access,
    we.cal_duration, weu.cal_status, we.cal_create_by, weu.cal_login,
    we.cal_type, we.cal_location, we.cal_url, we.cal_due_date, we.cal_due_time,
    weu.cal_percent, we.cal_mod_date, we.cal_mod_time ' . ($want_repeated ? ', wer.cal_type, wer.cal_end, wer.cal_frequency,
      wer.cal_days, wer.cal_bymonth, wer.cal_bymonthday,
      wer.cal_byday, wer.cal_bysetpos, wer.cal_byweekno,
      wer.cal_byyearday, wer.cal_wkst, wer.cal_count, wer.cal_endtime
      FROM webcal_entry we, webcal_entry_repeats wer, webcal_entry_user weu
      WHERE we.cal_id = wer.cal_id AND ' : 'FROM webcal_entry we, webcal_entry_user weu WHERE ') . 'we.cal_id = weu.cal_id AND weu.cal_status IN ( \'A\',\'W\' ) ';
    if ($catlistcnt > 0) {
        $placeholders = '';
        for ($p_i = 0; $p_i < $catlistcnt; $p_i++) {
            $placeholders .= $p_i == 0 ? '?' : ', ?';
            $query_params[] = $catlist[$p_i];
        }
        if ($cat_id > 0) {
            $sql .= 'AND we.cal_id IN ( ' . $placeholders . ' ) ';
        } elseif ($cat_id == -1) {
            // Eliminate events with categories.
            $sql .= 'AND we.cal_id NOT IN ( ' . $placeholders . ' ) ';
        }
    } else {
        if (!empty($cat_id)) {
            // Force no rows to be returned. No matching entries in category.
            $sql .= 'AND 1 = 0 ';
        }
    }
    $sql .= 'AND we.cal_type IN ' . ($is_task == false ? '( \'E\',\'M\' ) ' : '( \'N\',\'T\' ) AND ( we.cal_completed IS NULL ) ') . (strlen($user) > 0 ? 'AND ( weu.cal_login = ? ' : '');
    $query_params[] = $user;
    if ($user == $login && strlen($user) > 0 && $layers) {
        foreach ($layers as $layer) {
            $layeruser = $layer['cal_layeruser'];
            $sql .= 'OR weu.cal_login = ? ';
            $query_params[] = $layeruser;
            // While we are parsing the whole layers array, build ourselves
            // a new array that will help when we have to check for dups.
            $layers_byuser[$layeruser] = $layer['cal_dups'];
        }
    }
    $rows = dbi_get_cached_rows($sql . ($user == $login && strlen($user) && $PUBLIC_ACCESS_DEFAULT_VISIBLE == 'Y' ? 'OR weu.cal_login = \'__public__\' ' : '') . (strlen($user) > 0 ? ') ' : '') . $date_filter . (!$is_task ? ' ORDER BY we.cal_time, we.cal_name' : ''), $query_params);
    if ($rows) {
        $i = 0;
        $checkdup_id = $first_i_this_id = -1;
        for ($ii = 0, $cnt = count($rows); $ii < $cnt; $ii++) {
            $row = $rows[$ii];
            if ($row[9] == 'D' || $row[9] == 'R') {
                continue;
            }
            // Don't show deleted/rejected ones.
            // Get primary category for this event, used for icon and color.
            $categories = get_categories_by_id($row[4], $user);
            $cat_keys = array_keys($categories);
            $primary_cat = empty($cat_keys[0]) ? '' : $cat_keys[0];
            if ($login == '__public__' && !empty($OVERRIDE_PUBLIC) && $OVERRIDE_PUBLIC == 'Y') {
                $evt_name = $OVERRIDE_PUBLIC_TEXT;
                $evt_descr = $OVERRIDE_PUBLIC_TEXT;
            } else {
                $evt_name = $row[0];
                $evt_descr = $row[1];
            }
            if ($want_repeated && !empty($row[20])) {
                // row[20] = cal_type
                $item = new RepeatingEvent($evt_name, $evt_descr, $row[2], $row[3], $row[4], $row[5], $row[6], $row[7], $row[8], $row[9], $row[10], $primary_cat, $row[11], $row[12], $row[13], $row[14], $row[15], $row[16], $row[17], $row[18], $row[19], $row[20], $row[21], $row[22], $row[23], $row[24], $row[25], $row[26], $row[27], $row[28], $row[29], $row[30], $row[31], $row[32], array(), array(), array());
            } else {
                $item = new Event($evt_name, $evt_descr, $row[2], $row[3], $row[4], $row[5], $row[6], $row[7], $row[8], $row[9], $row[10], $primary_cat, $row[11], $row[12], $row[13], $row[14], $row[15], $row[16], $row[17], $row[18], $row[19]);
            }
            if ($item->getID() != $checkdup_id) {
                $checkdup_id = $item->getID();
                $first_i_this_id = $i;
            }
            if ($item->getLogin() == $user) {
                // Insert this one before all other ones with this ID.
                array_splice($result, $first_i_this_id, 0, array($item));
                $i++;
                if ($first_i_this_id + 1 < $i) {
                    // There's another one with the same ID as the one we inserted.
                    // Check for dup and if so, delete it.
                    $other_item = $result[$first_i_this_id + 1];
                    if (!empty($layers_byuser[$other_item->getLogin()]) && $layers_byuser[$other_item->getLogin()] == 'N') {
                        // NOTE:  array_splice requires PHP4
                        array_splice($result, $first_i_this_id + 1, 1);
                        $i--;
                    }
                }
            } else {
                if ($i == $first_i_this_id || !empty($layers_byuser[$item->getLogin()]) && $layers_byuser[$item->getLogin()] != 'N') {
                    // This item either is the first one with its ID, or allows dups.
                    // Add it to the end of the array.
                    $result[$i++] = $item;
                }
            }
            // Does event go past midnight?
            if (date('Ymd', $item->getDateTimeTS()) != date('Ymd', $item->getEndDateTimeTS()) && !$item->isAllDay() && $item->getCalTypeName() == 'event') {
                getOverLap($item, $i, true);
                $i = count($result);
            }
        }
    }
    if ($want_repeated) {
        // Now load event exceptions/inclusions and store as array.
        // TODO:  Allow passing this max_until as param in case we create
        // a custom report that shows N years of events.
        if (empty($max_until)) {
            $max_until = mktime(0, 0, 0, $thismonth + 2, 1, $thisyear);
        }
        for ($i = 0, $resultcnt = count($result); $i < $resultcnt; $i++) {
            if ($result[$i]->getID() != '') {
                $rows = dbi_get_cached_rows('SELECT cal_date, cal_exdate
          FROM webcal_entry_repeats_not
          WHERE cal_id = ?', array($result[$i]->getID()));
                for ($ii = 0, $rowcnt = count($rows); $ii < $rowcnt; $ii++) {
                    $row = $rows[$ii];
                    // If this is not a clone, add exception date.
                    if (!$result[$i]->getClone()) {
                        $except_date = $row[0];
                    }
                    if ($row[1] == 1) {
                        $result[$i]->addRepeatException($except_date, $result[$i]->getID());
                    } else {
                        $result[$i]->addRepeatInclusion($except_date);
                    }
                }
                // Get all dates for this event.
                // If clone, we'll get the dates from parent later.
                if (!$result[$i]->getClone()) {
                    $until = $result[$i]->getRepeatEndDateTimeTS() ? $result[$i]->getRepeatEndDateTimeTS() : $max_until;
                    // Try to minimize the repeat search by shortening
                    // until if BySetPos is not used.
                    if (!$result[$i]->getRepeatBySetPos() && $until > $max_until) {
                        $until = $max_until;
                    }
                    $rpt_count = 999;
                    //Some BIG number.
                    // End date... for year view and some reports we need whole year...
                    // So, let's do up to 365 days after current month.
                    // TODO:  Add this end time as a parameter in case someone creates
                    // a custom report that asks for N years of events.
                    // $jump = mktime ( 0, 0, 0, $thismonth -1, 1, $thisyear);
                    if ($result[$i]->getRepeatCount()) {
                        $rpt_count = $result[$i]->getRepeatCount() - 1;
                    }
                    $date = $result[$i]->getDateTimeTS();
                    if ($result[$i]->isAllDay() || $result[$i]->isUntimed()) {
                        $date += 43200;
                    }
                    //A simple hack to prevent DST problems.
                    // TODO get this to work
                    // C heck if this event id has been cached.
                    // $file = '';
                    // if ( ! empty ( $db_connection_info['cachedir'] ) ){
                    // $hash = md5 ( $result[$i]->getId () . $until . $jump );
                    // $file = $db_connection_info['cachedir'] . '/' . $hash . '.dat';
                    // }
                    // if ( file_exists ( $file ) ) {
                    // $dates =  unserialize ( file_get_contents ( $file ) );
                    // } else {
                    $dates = get_all_dates($date, $result[$i]->getRepeatType(), $result[$i]->getRepeatFrequency(), array($result[$i]->getRepeatByMonth(), $result[$i]->getRepeatByWeekNo(), $result[$i]->getRepeatByYearDay(), $result[$i]->getRepeatByMonthDay(), $result[$i]->getRepeatByDay(), $result[$i]->getRepeatBySetPos()), $rpt_count, $until, $result[$i]->getRepeatWkst(), $result[$i]->getRepeatExceptions(), $result[$i]->getRepeatInclusions(), $jumpdate);
                    $result[$i]->addRepeatAllDates($dates);
                    // Serialize and save in cache for later use.
                    // if ( ! empty ( $db_connection_info['cachedir'] ) ) {
                    // $fd = @fopen ( $file, 'w+b', false );
                    // if ( empty ( $fd ) ) {
                    // dbi_fatal_error ( "Cache error: could not write file $file" );
                    // }
                    // fwrite ( $fd, serialize ( $dates ) );
                    // fclose ( $fd );
                    // chmod ( $file, 0666 );
                    // }
                    // }
                } else {
                    // Process clones if any.
                    if (count($result[$i - 1]->getRepeatAllDates()) > 0) {
                        $parentRepeats = $result[$i - 1]->getRepeatAllDates();
                        $cloneRepeats = array();
                        for ($j = 0, $parentRepeatscnt = count($parentRepeats); $j < $parentRepeatscnt; $j++) {
                            $cloneRepeats[] = gmdate('Ymd', date_to_epoch($parentRepeats[$j]) + ONE_DAY);
                        }
                        $result[$i]->addRepeatAllDates($cloneRepeats);
                    }
                }
            }
        }
    }
    return $result;
}
Exemplo n.º 2
0
// Confidential and not user's and not assistant,
// then they cannot see name or description.
// if ( $row[8] == "R" && ! $is_my_event && ! $is_admin ) {
if ($cal_access == 'R' && !$is_my_event && !access_is_enabled()) {
    $is_private = true;
    $description = $name = '[' . translate('Private') . ']';
} else {
    if ($cal_access == 'C' && !$is_my_event && !$is_assistant && !access_is_enabled()) {
        $is_confidential = true;
        $description = $name = '[' . translate('Confidential') . ']';
    }
}
$event_date = $event_repeats && !empty($date) ? $date : ($event_time > 0 ? date('Ymd', date_to_epoch($orig_date . sprintf("%06d", $event_time))) : $orig_date);
// Get category Info
if ($CATEGORIES_ENABLED == 'Y') {
    $categories = get_categories_by_id($id, !empty($user) && strlen($user) && ($is_assistant || $is_admin) ? $user : $login, true);
    $category = implode(', ', $categories);
}
// get reminders
$reminder = getReminders($id, true);
echo '
    <h2>' . $name . ($is_nonuser_admin || $is_admin && !empty($user) && $user == '__public__' ? '  ( ' . translate('Admin mode') . ' )' : '') . ($is_assistant ? ' ( ' . translate('Assistant mode') . ' )' : '') . '</h2>
    <table width="100%" summary="">
      <tr>
        <td class="aligntop bold" width="10%">' . translate('Description') . ':</td>
        <td>';
if (!empty($ALLOW_HTML_DESCRIPTION) && $ALLOW_HTML_DESCRIPTION == 'Y') {
    $str = $description;
    // $str = str_replace ( '&', '&amp;', $description );
    $str = str_replace('&amp;amp;', '&amp;', $str);
    // If there is no HTML found, then go ahead and replace
Exemplo n.º 3
0
            $error = print_not_auth(31);
        }
    } else {
        // Not a participant for this event.
        $error = print_not_auth(32);
    }
    dbi_free_result($res);
} else {
    $error = db_error();
}
$cat_id = getValue('cat_id', '-?[0-9,\\-]*', true);
$cat_ids = $cat_name = array();
$catNames = '';
// Get user's categories for this event.
$globals_found = false;
$categories = get_categories_by_id($id, $login, true);
if (!empty($categories)) {
    $catNames = implode(', ', $categories);
    $keys = array_keys($categories);
    $catList = implode(',', $keys);
    sort($keys);
    if ($keys[0] < 0) {
        $globals_found = true;
    }
}
// Get event name and make sure event exists.
$event_name = '';
$res = dbi_execute('SELECT cal_name FROM webcal_entry WHERE cal_id = ?', array($id));
if ($res) {
    if ($row = dbi_fetch_row($res)) {
        $event_name = $row[0];
 function print_upcoming_event($e, $date)
 {
     global $display_link, $link_target, $SERVER_URL, $charset, $login, $display_tzid, $showTime, $showPopups, $eventinfo, $username, $hcalendar_output, $UPCOMING_DISPLAY_CAT_ICONS;
     $popupid = 'pop' . $e->getId() . '-' . $date;
     $private = $confidential = false;
     // Access: P=Public, R=Private, C=Confidential
     if ($e->getAccess() == 'R') {
         // not a public event, so we will just display "Private"
         $private = true;
     } else {
         if ($e->getAccess() == 'C') {
             // not a public event, so we will just display "Confidential"
             $confidential = true;
         }
     }
     if (!empty($SERVER_URL) && !$private && !$confidential) {
         echo "<div class=\"vevent\">\n";
         if ($display_link) {
             if ($showPopups) {
                 $timestr = '';
                 if ($e->isAllDay()) {
                     $timestr = translate('All day event');
                 } else {
                     if ($e->getTime() >= 0) {
                         $timestr = display_time($e->getDatetime());
                         if ($e->getDuration() > 0) {
                             $timestr .= ' - ' . display_time($e->getEndDateTime());
                         }
                     }
                 }
                 $eventinfo .= build_entry_popup('eventinfo-' . $popupid, $username, $e->getDescription(), $timestr, site_extras_for_popup($e->getId()), $e->getLocation(), $e->getName(), $e->getId());
             }
             $link = "<a class=\"entry\" id=\"{$popupid}\" title=\"" . htmlspecialchars($e->getName()) . '" href="' . $SERVER_URL . 'view_entry.php?id=' . $e->getID() . "&amp;date={$date}&amp;user="******"\" target=\"{$link_target}\"";
             }
             $link .= '>';
             if (empty($UPCOMING_DISPLAY_CAT_ICONS) || $UPCOMING_DISPLAY_CAT_ICONS != 'N') {
                 $catNum = abs($e->getCategory());
                 if ($catNum > 0) {
                     $catIcon = 'icons/cat-' . $catNum . '.gif';
                     if (file_exists($catIcon)) {
                         echo $link . '<img src="' . $catIcon . '" alt="category icon" border="0"/></a>';
                     }
                 }
             }
             echo $link;
         }
     }
     if ($private) {
         echo '[' . translate('Private') . ']';
     } else {
         if ($confidential) {
             echo '[' . translate('Confidential') . ']';
         } else {
             echo '<span class="summary">' . htmlspecialchars($e->getName()) . '</span>';
         }
     }
     if ($display_link && !empty($SERVER_URL) && !$private) {
         echo '</a>';
     }
     //added for hCalendar
     if ($hcalendar_output) {
         echo '<abbr class="dtstart" title="' . export_ts_utc_date($e->getDateTimeTS()) . '">' . $e->getDateTime() . "</abbr>\n";
         echo '<abbr class="dtend" title="' . export_ts_utc_date($e->getEndDateTimeTS()) . '">' . $e->getEndDateTimeTS() . "</abbr>\n";
         echo '<span class="description">' . $e->getDescription() . "</span>\n";
         if (strlen($e->getLocation()) > 0) {
             echo '<span class="location">' . $e->getLocation() . "</span>\n";
         }
         $categories = get_categories_by_id($e->getId(), $username);
         $category = implode(', ', $categories);
         if (strlen($category) > 0) {
             echo '<span class="categories">' . htmlentities($category) . "</span>\n";
         }
         if (strlen($e->getUrl()) > 0) {
             echo '<span class="url">' . $e->getUrl() . "</span>\n";
         }
         $rrule = export_recurrence_ical($e->getId());
         if (strlen($rrule) > 6) {
             echo '<span class="rrule">' . substr($rrule, 6) . "</span>\n";
         }
     }
     if ($showTime) {
         //show event time if requested (default=don't show)
         if ($e->isAllDay()) {
             echo ' (' . translate('All day event') . ")\n";
         } else {
             if ($e->getTime() != -1) {
                 echo ' (' . display_time($e->getDateTime(), $display_tzid) . ")\n";
             }
         }
     }
     echo "</div>\n";
 }
         // Get Repeat Exceptions.
         $res = dbi_execute('SELECT cal_date, cal_exdate
   FROM webcal_entry_repeats_not WHERE cal_id = ?', array($id));
         if ($res) {
             while ($row = dbi_fetch_row($res)) {
                 if ($row[1] == 1) {
                     $exceptions[] = $row[0];
                 } else {
                     $inclusions[] = $row[0];
                 }
             }
             dbi_free_result($res);
         }
     }
     if ($CATEGORIES_ENABLED == 'Y') {
         $catById = get_categories_by_id($id, $real_user, true);
         if (!empty($catById)) {
             $catNames = implode(', ', $catById);
             $catList = implode(',', array_keys($catById));
         }
     }
     //end CATEGORIES_ENABLED test
     // Get reminders.
     $reminder = getReminders($id);
     $reminder_offset = empty($reminder) ? 0 : $reminder['offset'];
     $rem_status = count($reminder);
     $rem_use_date = !empty($reminder['date']);
     // Get participants.
     $res = dbi_execute('SELECT cal_login, cal_status FROM webcal_entry_user WHERE cal_id = ?
 AND cal_status IN ( \'A\', \'W\' )', array($id));
     if ($res) {
Exemplo n.º 6
0
function export_ical($id = 'all', $attachment = false)
{
    global $publish_fullname, $login, $cal_type, $cat_filter, $vtimezone_data, $use_vtimezone;
    $exportId = -1;
    $ret = $Vret = $vtimezone_data = $use_vtimezone = '';
    $res = export_get_event_entry($id, $attachment);
    $entry_array = array();
    $count = 0;
    while ($entry = dbi_fetch_row($res)) {
        $entry_array[$count++] = $entry;
    }
    dbi_free_result($res);
    //abort if no records to output
    if ($count == 0) {
        return;
    }
    // Always output something, even if no records come back
    // This prevents errors on the iCal client
    $ret = "BEGIN:VCALENDAR\r\n";
    $title = utf8_encode('X-WR-CALNAME;VALUE=TEXT:' . (empty($publish_fullname) ? $login : translate($publish_fullname)));
    $title = str_replace(',', "\\,", $title);
    $ret .= "{$title}\r\n";
    $ret .= generate_prodid('ics');
    $ret .= "VERSION:2.0\r\n";
    $ret .= "METHOD:PUBLISH\r\n";
    while (list($key, $row) = each($entry_array)) {
        $id = $row[0];
        $event_uid = generate_uid($id);
        $name = $row[1];
        $priority = $row[2];
        $date = $row[3];
        $time = sprintf("%06d", $row[4]);
        $status = $row[5];
        $create_by = $row[6];
        $access = $row[7];
        $duration = $row[8];
        $description = $row[9];
        // New columns to support tasks
        $percent = empty($row[10]) ? 0 : $row[10];
        $completed = empty($row[11]) ? '' : substr($row[11], 0, 8) . 'T' . sprintf("%06d", substr($row[11], 9, 6));
        $due_date = $row[12];
        $due_time = $row[13];
        $location = $row[14];
        $url = $row[15];
        $cal_type = $row[16];
        $moddate = $row[17];
        $modtime = $row[18];
        // Figure out Categories
        $categories = get_categories_by_id($id, $login);
        // Add entry in webcal_import_data if it does not exist.
        // Even thought we're exporting, this data needs to be valid
        // for proper parsing of response from iCal client.
        // If this is the first event that has never been published,
        // then create a new import instance to associate with what we are doing.
        $sql = 'SELECT wid.cal_external_id
      FROM webcal_import_data wid, webcal_entry_user weu
      WHERE wid.cal_id = weu.cal_id AND wid.cal_id = ? AND
      weu.cal_login = ?';
        $res = dbi_execute($sql, array($id, $login));
        if ($res) {
            if ($row = dbi_fetch_row($res)) {
                // event has been published (or imported) before
                $event_uid = $row[0];
            } else {
                if ($exportId < 0) {
                    // This is first event that has not been published before.
                    // Create an entry in webcal_import.
                    // It would be nice if we could put a name in here of who
                    // or where the remote cal subscription is coming from in case
                    // they update some of our events. But, I cannot see a way to
                    // do that.
                    $exportId = create_import_instance();
                }
                if ($attachment == false) {
                    save_uid_for_event($exportId, $id, $event_uid);
                }
            }
            dbi_free_result($res);
        }
        // get recurrance info
        $recurrance = export_recurrence_ical($id);
        if (!empty($recurrance)) {
            $use_vtimezone = true;
        }
        /* snippet from RFC2445
          The "VTIMEZONE" calendar component MUST be present if the iCalendar
           object contains an RRULE that generates dates on both sides of a time
           zone shift (e.g. both in Standard Time and Daylight Saving Time)
           unless the iCalendar object intends to convey a floating time (See
           the section "4.1.10.11 Time" for proper interpretation of floating
           time). It can be present if the iCalendar object does not contain
           such a RRULE. In addition, if a RRULE is present, there MUST be valid
           time zone information for all recurrence instances.
        
           However, this is not possible to implement at this time
           */
        // if Categories were selected as an export filter, then abort this
        // event if it does not contain that category
        if (!empty($cat_filter)) {
            if (count($categories) == 0 || !array_key_exists($cat_filter, $categories)) {
                continue;
            }
        }
        if ($cal_type == 'E' || $cal_type == 'M') {
            $exporting_event = true;
            /* Start of event */
            $Vret .= "BEGIN:VEVENT\r\n";
        } else {
            if ($cal_type == 'T' || $cal_type == 'N') {
                $exporting_event = false;
                /* Start of VTODO */
                $Vret .= "BEGIN:VTODO\r\n";
            } else {
                if ($cal_type == 'J' || $cal_type == 'O') {
                    $exporting_event = false;
                    /* Start of VJOURNAL */
                    $Vret .= "BEGIN:VJOURNAL\r\n";
                }
            }
        }
        /* UID of the event (folded to 76 char) */
        $array = export_fold_lines("UID:{$event_uid}");
        while (list($key, $value) = each($array)) {
            $Vret .= "{$value}\r\n";
        }
        $Vret .= 'LAST-MODIFIED:' . export_get_utc_date($moddate, $modtime) . "\r\n";
        $name = preg_replace("/\r/", ' ', $name);
        // escape,;  \ in octal ascii
        $name = addcslashes($name, ",;\\");
        $description = preg_replace("/\r/", ' ', $description);
        $description = addcslashes($description, ",;\\");
        $description = str_replace(chr(10), chr(92) . chr(110), $description);
        /* SUMMARY of the event (folded to 76 char) */
        $name = 'SUMMARY:' . $name;
        $array = export_fold_lines($name, 'utf8');
        while (list($key, $value) = each($array)) {
            $Vret .= "{$value}\r\n";
        }
        /* DESCRIPTION if any (folded to 76 char) */
        if ($description != '') {
            $description = 'DESCRIPTION:' . $description;
            $array = export_fold_lines($description, 'utf8');
            while (list($key, $value) = each($array)) {
                $Vret .= "{$value}\r\n";
            }
        }
        /* LOCATION if any (folded to 76 char) */
        if ($location != '') {
            $location = 'LOCATION:' . $location;
            $array = export_fold_lines($location, 'utf8');
            while (list($key, $value) = each($array)) {
                $Vret .= "{$value}\r\n";
            }
        }
        /* URL if any (folded to 76 char) */
        if ($url != '') {
            $url = 'URL:' . $url;
            $array = export_fold_lines($url, 'utf8');
            while (list($key, $value) = each($array)) {
                $Vret .= "{$value}\r\n";
            }
        }
        /* CATEGORIES if any (folded to 76 char) */
        if (isset($categories) && count($categories)) {
            $categories = 'CATEGORIES:' . implode(',', $categories);
            $array = export_fold_lines($categories, 'utf8');
            while (list($key, $value) = each($array)) {
                $Vret .= "{$value}\r\n";
            }
        }
        /* CLASS either "PRIVATE", "CONFIDENTIAL",  or "PUBLIC" (the default) */
        if ($access == 'R') {
            $Vret .= "CLASS:PRIVATE\r\n";
        } else {
            if ($access == 'C') {
                $Vret .= "CLASS:CONFIDENTIAL\r\n";
            } else {
                $Vret .= "CLASS:PUBLIC\r\n";
            }
        }
        /* STATUS */
        if ($cal_type == 'E' || $cal_type == 'M') {
            if ($status == 'A') {
                $Vret .= "STATUS:CONFIRMED\r\n";
            } else {
                if ($status == 'W') {
                    $Vret .= "STATUS:TENTATIVE\r\n";
                } else {
                    if ($status == 'D') {
                        $Vret .= "STATUS:CANCELLED\r\n";
                    }
                }
            }
        } else {
            if ($cal_type == 'T' || $cal_type == 'N') {
                if ($status == 'A' && empty($completed)) {
                    $Vret .= "STATUS:IN-PROCESS\r\n";
                } else {
                    if ($status == 'A') {
                        $Vret .= "STATUS:COMPLETED\r\n";
                    } else {
                        if ($status == 'W') {
                            $Vret .= "STATUS:NEEDS-ACTION\r\n";
                        } else {
                            if ($status == 'D') {
                                $Vret .= "STATUS:CANCELLED\r\n";
                            }
                        }
                    }
                }
            }
        }
        // ATTENDEE of the event
        $attendee = export_get_attendee($id, 'ical');
        $attendcnt = count($attendee);
        for ($i = 0; $i < $attendcnt; $i++) {
            $attendee[$i] = export_fold_lines($attendee[$i], 'utf8');
            while (list($key, $value) = each($attendee[$i])) {
                $Vret .= "{$value}\r\n";
            }
        }
        /* Time - all times are utc */
        $Vret .= export_time($date, $duration, $time, 'ical', $cal_type);
        // VTODO specific items
        $task_complete = false;
        if ($cal_type == 'T' || $cal_type == 'N') {
            $Vret .= 'DUE:' . $due_date . 'T' . sprintf("%06d", $due_time) . "Z\r\n";
            if (!empty($completed)) {
                $Vret .= 'COMPLETED:' . $completed . "\r\n";
                $task_complete = true;
            }
            $Vret .= 'PERCENT-COMPLETE:' . $percent . "\r\n";
        }
        /* Recurrence */
        $Vret .= $recurrance;
        /* handle alarms */
        $Vret .= export_alarm_ical($id, $date, $description, $task_complete);
        if ($cal_type == 'E' || $cal_type == 'M') {
            /* End of event */
            $Vret .= "END:VEVENT\r\n";
        } else {
            if ($cal_type == 'T' || $cal_type == 'N') {
                /* Start of VTODO */
                $Vret .= "END:VTODO\r\n";
            } else {
                if ($cal_type == 'J' || $cal_type == 'O') {
                    /* Start of VJOURNAL */
                    $Vret .= "END:VJOURNAL\r\n";
                }
            }
        }
    }
    /* VTIMEZONE Set in export_time () if needed */
    $ret .= $vtimezone_data . $Vret;
    $ret .= "END:VCALENDAR\r\n";
    // attachment will be true if called during email creation
    if (!$attachment) {
        echo $ret;
    } else {
        return $ret;
    }
}