#!/usr/bin/perl -w # # Author: Petter Reinholdtsen # Date: 2002-01-10 # # Convert plan calender data to/from icalender format. # # plan, # icalendar, RFC 2445, iCalendar> # # Depend on debian package libdate-ical-perl use warnings; use strict; use Getopt::Std; use Date::Parse; use Date::Format; use Date::ICal; use iCal::Parser; use Data::Dumper; my @events; my %opts; unless (getopts('dif:o:', \%opts)) { usage(); exit 1; } my $debug = $opts{d} || 0; my $input = $opts{f}; my $output = $opts{o}; if ($opts{i}) { # Import read_icalendar($input || "test.ical"); write_planfile($output || $ENV{HOME}."/.plan.dir/fromical"); } else { # Default is to export read_planfile($input || $ENV{HOME}."/.plan.dir/dayplan"); write_icalendar($output || "-"); } exit 0; sub usage { print <; chomp $planver; while () { chomp; if (m%\d+/\d+/\d+\s%) { my ($date, $start, $duration) = split(/\s+/); my $info = ; chomp $info; my ($dontknow, $msg) = $info =~ m/^(.)\t(.+)$/; print STDERR "E: $date $start $duration $msg\n" if $debug; my $timestamp = str2time("$date $start"); my $isostartstamp = time2str("%Y%m%dT%H%M%S", $timestamp); my $icalstartstamp = Date::ICal->new( epoch => $timestamp ); my @f = split(/:/, $duration); $timestamp += ($f[0]*60*60 + $f[1]*60 +$f[2]); my $isoendstamp = time2str("%Y%m%dT%H%M%S", $timestamp); my $icalendstamp = Date::ICal->new( epoch => $timestamp ); print STDERR "IE: $isostartstamp $isoendstamp\n" if $debug; push(@events, { summary => $msg, dtstart => $icalstartstamp->ical, dtend => $icalendstamp->ical, }); } } close(PLAN); } # BEGIN:VCALENDAR # PRODID # :-//test environment//NONSGML plan2icalendar//EN # VERSION # :2.0 # BEGIN:VEVENT # CREATED # :20020110T153939 # UID # :KOrganizer-141229514.660 # SEQUENCE # :0 # LAST-MODIFIED # :20020110T153939 # DTSTAMP # :20020110T153952 # SUMMARY # :SL-veiledning # DTSTART # :20020114T151500 # DTEND # :20020114T160000 # END:VEVENT # END:VCALENDAR sub write_icalendar { my $filename = shift; open(PLAN, ">$filename") || die "Unable to write to $filename"; print PLAN <{uid} = "plan2icalendar-$count" unless $event->{uid}; $event->{dtstamp} = "20020110T153952" unless $event->{dtstamp}; $event->{'last-modified'} = "20020110T153939" unless $event->{'last-modified'}; $event->{sequence} = $count unless $event->{sequence}; $event->{created} = "20020110T153939" unless $event->{created}; print PLAN <{created} UID:$event->{uid} SEQUENCE:$count LAST-MODIFIED:$event->{'last-modified'} DTSTAMP:$event->{dtstamp} SUMMARY:$event->{summary} DTSTART:$event->{dtstart} DTEND:$event->{dtend} END:VEVENT EOF $count++; } print PLAN "END:VCALENDAR\n"; close PLAN; } # # Should probably leave this task to Net::ICal. But it is not # available in debian/sarge, so I make a quick-n-dirty solution # instead. # sub read_icalendar { my $filename = shift; if (1) { my $parser = iCal::Parser->new(); my $hash = $parser->parse($filename); # print Dumper($hash) if $debug; # print Dumper($hash->{'events'}); for my $year (sort keys %{$hash->{'events'}}) { for my $month (sort keys %{$hash->{'events'}->{$year}}) { for my $day (sort keys %{$hash->{'events'}->{$year}->{$month}}) { for my $evid (keys %{$hash->{'events'}->{$year}->{$month}->{$day}}) { my $event = $hash->{'events'}->{$year}->{$month}->{$day}->{$evid}; # print "$year-$month-$day $evid\n"; # print Dumper($event); my %newevent; $newevent{description} = $event->{'DESCRIPTION'}; $newevent{created} = $event->{'CREATED'}; $newevent{dtend} = $event->{'DTEND'}; $newevent{dtstamp} = $event->{'DTSTAMP'}; $newevent{dtstart} = $event->{'DTSTART'}; $newevent{'last-modified'} = $event->{'LAST-MODIFIED'}; $newevent{sequence} = $event->{'SEQUENCE'}; $newevent{summary} = $event->{'SUMMARY'}; $newevent{uid} = $event->{'UID'}; # print Dumper(%newevent); push(@events, \%newevent); print STDERR "Event pushed\n" if $debug; } } } } } else { open (ICALENDAR, "<$filename") or die "Unable to read from $filename"; my $oldval = $/; $/ = "\r\n"; print STDERR "Loading $filename\n" if $debug; while () { chomp; if (m/^BEGIN:VEVENT/) { my %event; while () { chomp; last if (m/END:VEVENT/); $event{description} = $1 if (m/^DESCRIPTION\s*:\s*(.+)$/); $event{created} = $1 if (m/^CREATED\s*:\s*(.+)$/); $event{dtend} = $1 if (m/^DTEND\s*:\s*(.+)$/); $event{dtstamp} = $1 if (m/^DTSTAMP\s*:\s*(.+)$/); $event{dtstart} = $1 if (m/^DTSTART\s*:\s*(.+)$/); $event{last-modified} = $1 if (m/^LAST-MODIFIED\s*:\s*(.+)$/); $event{sequence} = $1 if (m/^SEQUENCE\s*:\s*(.+)$/); $event{summary} = $1 if (m/^SUMMARY\s*:\s*(.+)$/); $event{uid} = $1 if (m/^UID\s*:\s*(.+)$/); } push @events, \%event; print STDERR "Event pushed\n" if $debug; } } close (ICALENDAR); $/ = $oldval; } } # Simple version covering the chars I need. sub utf8tolocalmap { my $string = shift; $string =~ s/ø/ø/g; $string =~ s/æ/æ/g; $string =~ s/Ã¥/å/g; $string =~ s/Ã…/Å/g; $string =~ s/«/«/g; $string =~ s/»/»/g; return $string; } sub write_planfile { my $filename = shift; open(PLAN, ">$filename") or die "Unable to write to $filename"; for my $event (@events) { # offset = 0 -- assume all timestamps in local time zone my $ical; if ("DateTime" eq ref $event->{dtstart}) { $ical = Date::ICal->new( epoch => $event->{dtstart}->epoch ); } else { $ical = Date::ICal->new( ical => $event->{dtstart}, offset => 0 ); } my $date = join("/", $ical->month, $ical->day, $ical->year); my $start = join(":", $ical->hour, $ical->min, $ical->sec); my $icalstop; if ("DateTime" eq ref $event->{dtend}) { $icalstop = Date::ICal->new( epoch => $event->{dtend}->epoch ); } else { $icalstop = Date::ICal->new( ical => $event->{dtend}, offset => 0 ); } my $icalduration = $icalstop - $ical; my $duration = join(":", $icalduration->hours || "0", $icalduration->minutes || "0", $icalduration->seconds || "0"); my $code = "N"; my $summary = utf8tolocalmap($event->{summary}); print PLAN "$date $start $duration 0:0:0 0:0:0 ---------- 0 0\n"; print PLAN "$code\t$summary\n"; } }