DAVx5 reported a 500 Internal Server Error on a time-range REPORT
against a calendar containing a recurring event whose DTSTART/DTEND used
a Windows-style TZID (e.g. "W. Europe Standard Time", as commonly written
by Outlook/Exchange and some Thunderbird/Lightning setups) instead of an
IANA zone name.
go-ical resolves TZID via a plain time.LoadLocation call, which only
understands IANA names. A simple decode of such an event succeeds (RRULE
dates aren't parsed eagerly), but expanding its recurrence - which
go-webdav's caldav.Filter does for every time-range REPORT - calls
Component.RecurrenceSet, which does call time.LoadLocation(tzid) and
fails with "ical: error parsing start time: unknown time zone ...".
Add internal/icalfix, a small shared helper that rewrites recognized
Windows timezone identifiers (TZID parameters and VTIMEZONE TZID: lines)
to their IANA equivalent in raw ICS bytes before decoding. Wire it into
every ical.NewDecoder call site: internal/caldav/backend.go's
decodeObject (fixes the reported bug), internal/web/calendar.go's event
rendering/ICS import, and internal/icssub's remote feed fetching, so a
subscribed feed with the same issue doesn't hit it either.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Users can now subscribe to a remote ICS/webcal feed from the dashboard
(name + color), the same way they set up a real calendar or the virtual
Birthdays calendar. Subscriptions are read-only, per-user, and share the
"/cal/home/<name>/" namespace with real calendars and "birthdays" (name
collisions are rejected in both directions).
- internal/db: new ics_subscriptions table + CRUD (internal/db/ics.go);
CreateCalendarWithColor checks for a colliding subscription name.
- internal/icssub: shared HTTP-fetch + TTL cache (15 min) for remote ICS
calendars, with webcal:// -> https:// rewriting and stale-on-error
fallback, used by both the web UI and the CalDAV backend.
- internal/web: dashboard "Subscribe to an ICS/webcal calendar" form,
color picker, delete button (internal/web/ics.go,
templates/dashboard.templ); month view renders subscription events in
their chosen color, read-only (internal/web/calendar.go).
- internal/caldav: subscriptions are exposed as read-only calendars
(internal/caldav/ics.go) - listed in PROPFIND, events served via
GET/REPORT, PUT/DELETE on individual events rejected with 403, but
DELETE on the calendar itself unsubscribes; calendar-color is injected
the same way as for real calendars and Birthdays.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>