#!/usr/bin/perl -w use strict; use warnings; use diagnostics; use Data::Dumper; my %callback = ( methode => 'parse_datei', datei => <<'TESTDATEI' BEGIN:VCALENDAR VERSION:2.0 PRODID:-//hacksw/handcal//NONSGML v1.0//EN BEGIN:VEVENT DTSTART:19970714T170000Z DTEND:19970715T035959Z SUMMARY:Bastille Day Party END:VEVENT END:VCALENDAR TESTDATEI , ); ical(\%callback); print Dumper(\$callback{termine}); %callback = ( methode => 'parse_datei', datei => <<'TESTDATEI' BEGIN:VCALENDAR VERSION:2.0 PRODID:-//hacksw/handcal//NONSGML v1.0//EN BEGIN:VEVENT DTSTART:19970714T170000Z DTEND:19970715T035959Z SUMMARY:Bastille Day Party END:VEVENT END:VCALENDAR BEGIN:VCALENDAR VERSION:2.0 PRODID:-//hacksw/handcal//NONSGML v1.0//EN BEGIN:VEVENT DTSTART:19970714T170000Z DTEND:19970715T035959Z SUMMARY:Bastille Day Party END:VEVENT END:VCALENDAR TESTDATEI , ); ical(\%callback); print Dumper(\$callback{termine}); %callback = ( methode => 'parse_datei', datei => <<'TESTDATEI' BEGIN:VCALENDAR METHOD:PUBLISH PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN VERSION:2.0 BEGIN:VEVENT CREATED:20130104T150431Z LAST-MODIFIED:20130104T150431Z DTSTAMP:20130104T150431Z SUMMARY:Osterferien Nordrhein-Westfalen DTSTART;VALUE=DATE:20140414 DTEND;VALUE=DATE:20140427 URL:http://www.schulferien.org DESCRIPTION:Alle Termine auf www.schulferien.org TRANSP:TRANSPARENT UID:Osterferien-Nordrhein_Westfalen-201404271110802642@schulferien.org END:VEVENT BEGIN:VEVENT CREATED:20130104T150431Z LAST-MODIFIED:20130104T150431Z DTSTAMP:20130104T150431Z SUMMARY:Pfingstferien Nordrhein-Westfalen DTSTART;VALUE=DATE:20140610 DTEND;VALUE=DATE:20140611 URL:http://www.schulferien.org DESCRIPTION:Alle Termine auf www.schulferien.org TRANSP:TRANSPARENT UID:Pfingstferien-Nordrhein_Westfalen-201406111177927743@schulferien.org END:VEVENT BEGIN:VEVENT CREATED:20130104T150431Z LAST-MODIFIED:20130104T150431Z DTSTAMP:20130104T150431Z SUMMARY:Sommerferien Nordrhein-Westfalen DTSTART;VALUE=DATE:20140707 DTEND;VALUE=DATE:20140820 URL:http://www.schulferien.org DESCRIPTION:Alle Termine auf www.schulferien.org TRANSP:TRANSPARENT UID:Sommerferien-Nordrhein_Westfalen-201408201297968072@schulferien.org END:VEVENT BEGIN:VEVENT CREATED:20130104T150431Z LAST-MODIFIED:20130104T150431Z DTSTAMP:20130104T150431Z SUMMARY:Herbstferien Nordrhein-Westfalen DTSTART;VALUE=DATE:20141006 DTEND;VALUE=DATE:20141019 URL:http://www.schulferien.org DESCRIPTION:Alle Termine auf www.schulferien.org TRANSP:TRANSPARENT UID:Herbstferien-Nordrhein_Westfalen-201410191101440705@schulferien.org END:VEVENT BEGIN:VEVENT CREATED:20130104T150431Z LAST-MODIFIED:20130104T150431Z DTSTAMP:20130104T150431Z SUMMARY:Weihnachtsferien Nordrhein-Westfalen DTSTART;VALUE=DATE:20140101 DTEND;VALUE=DATE:20140108 URL:http://www.schulferien.org DESCRIPTION:Alle Termine auf www.schulferien.org TRANSP:TRANSPARENT UID:Weihnachtsferien-Nordrhein_Westfalen-201401081011962781@schulferien.org END:VEVENT BEGIN:VEVENT CREATED:20130104T150431Z LAST-MODIFIED:20130104T150431Z DTSTAMP:20130104T150431Z SUMMARY:Weihnachtsferien Nordrhein-Westfalen DTSTART;VALUE=DATE:20141222 DTEND;VALUE=DATE:20150101 URL:http://www.schulferien.org DESCRIPTION:Alle Termine auf www.schulferien.org TRANSP:TRANSPARENT UID:Weihnachtsferien-Nordrhein_Westfalen-201501011006645835@schulferien.org END:VEVENT END:VCALENDAR TESTDATEI , ); ical(\%callback); print Dumper(\$callback{termine}); ############################################################################## sub ical { # # Konvertiert # @arraystruktur_icalformat <=> iCal Datei # # Aufruf: # ======= # my %callback = ( # methode => [siehe Methoden unten], # datei => iCal Datei als String, # termine => \@arraystruktur_icalformat, # ); # ical(\%callback); # # Rückgabe innerhalb von \%callback: # ================================== # fehler => defined bei Fehler oder !exists wenn alles ok ist # fehlertext => Text zum Fehler, nur belegt wenn exists fehler # # Methoden: # ========= # parse_datei -> liest eine *.ics Datei, deren Inhalt (kein # Filehandle!) in Parameter datei als String übergeben # wird # my ($cb) = @_; my %conf = ( zeilenverbinder => qr{^\s+(.+)}, # Verbindet überlange Zeilen miteinander ); my %tmp = ( abschnittoffen => 0, string => '', terminarray => [], terminoffen => 0, );; if ($cb->{methode} eq 'parse_datei') { ($tmp{datei} = $cb->{datei}) =~ s/\r//g; my %verarbeite = ( abschnitt => sub { my ($tmp) = @_; if ($tmp->{string} eq 'END:VCALENDAR') { $tmp->{abschnitt}{t} = [@{$tmp{terminarray}}]; push @{$cb->{termine}},{%{$tmp{abschnitt}}}; $tmp->{abschnittoffen} = 0; } elsif ($tmp->{string} eq 'BEGIN:VCALENDAR') { $tmp->{abschnittoffen} = 1; $tmp->{abschnitt} = (); } elsif ($tmp->{string} eq 'BEGIN:VEVENT') { $tmp->{terminoffen} = 1; } elsif ($tmp->{string} =~ /^([^:]+):(.+)$/) { $tmp->{abschnitt}{$1} = $2; } }, termin => sub { my ($tmp) = @_; if ($tmp->{string} eq 'END:VEVENT') { push @{$tmp{terminarray}},{%{$tmp{termin}}}; $tmp->{terminoffen} = 0; } elsif ($tmp->{string} =~ /^([^:]+):(.+)$/) { $tmp->{termin}{$1} = $2; } }, ); foreach my $zeile (split /\n/,$tmp{datei}) { if ($zeile =~ $conf{zeilenverbinder}) { $tmp{string} .= $1; } else { if ($tmp{string} ne '') { $verarbeite{$tmp{terminoffen} ? 'termin' : 'abschnitt'}->(\%tmp); $tmp{string} = ''; } $tmp{string} = $zeile; } } if ($tmp{string} ne '') { $verarbeite{$tmp{terminoffen} ? 'termin' : 'abschnitt'}->(\%tmp); } } }