]> pere.pagekite.me Git - homepage.git/blobdiff - linux/plan2icalendar
Generated.
[homepage.git] / linux / plan2icalendar
index 92ef801561d794a6d71d15a3846df8c383c61b25..ad051624b2cd7c74a8b92fe4f8b06e2491bda2e4 100755 (executable)
@@ -3,21 +3,55 @@
 # Author: Petter Reinholdtsen <pere@hungry.com>
 # Date:   2002-01-10
 #
 # Author: Petter Reinholdtsen <pere@hungry.com>
 # Date:   2002-01-10
 #
-# Convert plan calender data to icalender format.
+# Convert plan calender data to/from icalender format.
 #
 # plan, <URL:http://www.bitrot.de/>
 # icalendar, RFC 2445, <URL:http://www.faqs.org/rfcs/rfc2445.html">iCalendar>
 #
 # plan, <URL:http://www.bitrot.de/>
 # icalendar, RFC 2445, <URL:http://www.faqs.org/rfcs/rfc2445.html">iCalendar>
+#
+# Depend on debian package libdate-ical-perl
+
+use warnings;
+use strict;
 
 
+use Getopt::Std;
 use Date::Parse;
 use Date::Format;
 use Date::Parse;
 use Date::Format;
+use Date::ICal;
+use iCal::Parser;
+use Data::Dumper;
 
 my @events;
 
 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};
 
 
-my $mailto = "pere\@hungry.com";
+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 <<EOF
+Usage: $0 [-i] [-f infile] [-o outfile]
 
 
-read_planfile(".plan.dir/dayplan");
-write_icalendar();
+Imports or exports between plan and iCalendar.
 
 
+  -i          import ical file
+  -f infile   read input from 'infile'
+  -o outfile  read output from 'outfile'
+  -d          enable debug output
+EOF
+}
 sub read_planfile {
     my ($planfile) = @_;
     open(PLAN, "<$planfile") || die "Unable to read $planfile";
 sub read_planfile {
     my ($planfile) = @_;
     open(PLAN, "<$planfile") || die "Unable to read $planfile";
@@ -30,22 +64,22 @@ sub read_planfile {
             my $info = <PLAN>;
             chomp $info;
             my ($dontknow, $msg) = $info =~ m/^(.)\t(.+)$/;
             my $info = <PLAN>;
             chomp $info;
             my ($dontknow, $msg) = $info =~ m/^(.)\t(.+)$/;
-            print STDERR "E: $date $start $duration $msg\n";
+            print STDERR "E: $date $start $duration $msg\n" if $debug;
 
             my $timestamp = str2time("$date $start");
 
             my $timestamp = str2time("$date $start");
-            $isostartstamp  = time2str("%Y%m%dT%H%M%S", $timestamp);
+            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 @f = split(/:/, $duration);
             $timestamp += ($f[0]*60*60 + $f[1]*60 +$f[2]);
-            $isoendstamp  = time2str("%Y%m%dT%H%M%S", $timestamp);
+            my $isoendstamp  = time2str("%Y%m%dT%H%M%S", $timestamp);
+            my $icalendstamp = Date::ICal->new( epoch => $timestamp );
 
 
-            print STDERR "IE: $isostartstamp $isoendstamp\n";
+            print STDERR "IE: $isostartstamp $isoendstamp\n" if $debug;
             push(@events, {
             push(@events, {
-                organizer => "$mailto",
                 summary   => $msg,
                 summary   => $msg,
-                dtstart   => $isostartstamp,
-                dtend     => $isoendstamp,
-                priority  => '1'
+                dtstart   => $icalstartstamp->ical,
+                dtend     => $icalendstamp->ical,
                 });
         }
     }
                 });
         }
     }
@@ -55,7 +89,7 @@ sub read_planfile {
 
 # BEGIN:VCALENDAR
 # PRODID
 
 # BEGIN:VCALENDAR
 # PRODID
-#  :-//K Desktop Environment//NONSGML KOrganizer//EN
+#  :-//test environment//NONSGML plan2icalendar//EN
 # VERSION
 #  :2.0
 # BEGIN:VEVENT
 # VERSION
 #  :2.0
 # BEGIN:VEVENT
@@ -69,12 +103,8 @@ sub read_planfile {
 #  :20020110T153939
 # DTSTAMP
 #  :20020110T153952
 #  :20020110T153939
 # DTSTAMP
 #  :20020110T153952
-# ORGANIZER
-#  :MAILTO:pre@diskless.uio.no
 # SUMMARY
 #  :SL-veiledning
 # SUMMARY
 #  :SL-veiledning
-# PRIORITY
-#  :1
 # DTSTART
 #  :20020114T151500
 # DTEND
 # DTSTART
 #  :20020114T151500
 # DTEND
@@ -82,41 +112,151 @@ sub read_planfile {
 # END:VEVENT
 # END:VCALENDAR
 sub write_icalendar {
 # END:VEVENT
 # END:VCALENDAR
 sub write_icalendar {
-    print <<EOF;
+    my $filename = shift;
+    open(PLAN, ">$filename") || die "Unable to write to $filename";
+    print PLAN <<EOF;
 BEGIN:VCALENDAR
 BEGIN:VCALENDAR
-PRODID
- :-//K Desktop Environment//NONSGML KOrganizer//EN
-VERSION
- :2.0
+CALSCALE:GREGORIAN
+PRODID:-//test environment//NONSGML plan2icalender//EN
+VERSION:2.0
 EOF
     my $count = 0;
 EOF
     my $count = 0;
-    my $event;
-    for $event (@events) {
-        print <<EOF;
+    for my $event (@events) {
+        $event->{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 <<EOF;
 BEGIN:VEVENT
 BEGIN:VEVENT
-CREATED
- :20020110T153939
-UID
- :plan2icalendar-$count
-SEQUENCE
- :$count
-LAST-MODIFIED
- :20020110T153939
-DTSTAMP
- :20020110T153952
-ORGANIZER
- :MAILTO:$event->{organizer}
-SUMMARY
- :$event->{summary}
-PRIORITY
- :$event->{priority}
-DTSTART
- :$event->{dtstart}
-DTEND
- :$event->{dtend}
+CREATED:$event->{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
 END:VEVENT
+
 EOF
         $count++;
     }
 EOF
         $count++;
     }
-    print "END:VCALENDAR\n";
+    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 (<ICALENDAR>) {
+        chomp;
+        if (m/^BEGIN:VEVENT/) {
+            my %event;
+            while (<ICALENDAR>) {
+                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/Ã\85/Å/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";
+    }
 }
 }