"""Divide un .ics (un VCALENDAR con N VEVENT) en N VCALENDARs independientes. Funcion pura: sin I/O, sin estado, determinista. Cada salida es un VCALENDAR completo y autonomo con un unico VEVENT, listo para subir como recurso CalDAV individual. Las VTIMEZONE del original se incluyen en cada salida (un VEVENT puede referenciar un TZID definido en el VCALENDAR padre). Solo usa stdlib (re). """ import re _VEVENT_RE = re.compile(r"BEGIN:VEVENT.*?END:VEVENT", re.DOTALL) _VTIMEZONE_RE = re.compile(r"BEGIN:VTIMEZONE.*?END:VTIMEZONE", re.DOTALL) _DEFAULT_PRODID = "-//xandikos-migracion//google-export//EN" def _to_crlf(text: str) -> str: """Normaliza saltos de linea a CRLF (RFC 5545).""" return text.strip().replace("\r\n", "\n").replace("\n", "\r\n") def split_vevents_to_vcalendars(ics_text: str, prodid: str = _DEFAULT_PRODID) -> list: """Divide un VCALENDAR con N VEVENT en N VCALENDARs independientes. Args: ics_text: contenido completo del .ics (un VCALENDAR con uno o varios VEVENT). Tolera LF o CRLF. prodid: valor del campo PRODID a usar en el header de cada VCALENDAR de salida. Default: identifica la migracion a Xandikos. Returns: Lista de strings. Cada elemento es un VCALENDAR completo y autonomo ('BEGIN:VCALENDAR'..'END:VCALENDAR' terminado en CRLF) con header VERSION/PRODID/CALSCALE, las VTIMEZONE del original (si las habia) y un unico VEVENT. Lista vacia si no hay ningun VEVENT. """ if not ics_text: return [] events = _VEVENT_RE.findall(ics_text) timezones = _VTIMEZONE_RE.findall(ics_text) tz_block = "" for tz in timezones: tz_block += _to_crlf(tz) + "\r\n" header = ( "BEGIN:VCALENDAR\r\n" "VERSION:2.0\r\n" "PRODID:%s\r\n" "CALSCALE:GREGORIAN\r\n" % prodid ) out = [] for ev in events: body = header + tz_block + _to_crlf(ev) + "\r\nEND:VCALENDAR\r\n" out.append(body) return out