]> pere.pagekite.me Git - homepage.git/blob - linux/plan2icalendar
Sort by date.
[homepage.git] / linux / plan2icalendar
1 #!/usr/bin/perl -w
2 #
3 # Author: Petter Reinholdtsen <pere@hungry.com>
4 # Date: 2002-01-10
5 #
6 # Convert plan calender data to/from icalender format.
7 #
8 # plan, <URL:http://www.bitrot.de/>
9 # icalendar, RFC 2445, <URL:http://www.faqs.org/rfcs/rfc2445.html">iCalendar>
10
11 use warnings;
12 use strict;
13
14 use Getopt::Std;
15 use Date::Parse;
16 use Date::Format;
17 use Date::ICal;
18
19 my @events;
20 my %opts;
21 my $debug = 0;
22 unless (getopts('if:o:', \%opts)) {
23 usage();
24 exit 1;
25 }
26
27 my $input = $opts{f};
28 my $output = $opts{o};
29
30 if ($opts{i}) { # Import
31 read_icalendar($input || "test.ical");
32 write_planfile($output || $ENV{HOME}."/.plan.dir/fromical");
33 } else { # Default is to export
34 read_planfile($input || $ENV{HOME}."/.plan.dir/dayplan");
35 write_icalendar($output || "-");
36 }
37 exit 0;
38
39 sub usage {
40 print <<EOF
41 Usage: $0 [-i] [-f infile] [-o outfile]
42
43 Imports or exports between plan and iCalendar.
44
45 -i import ical file
46 -f infile read input from 'infile'
47 -o outfile read output from 'outfile'
48 EOF
49 }
50 sub read_planfile {
51 my ($planfile) = @_;
52 open(PLAN, "<$planfile") || die "Unable to read $planfile";
53 my $planver = <PLAN>;
54 chomp $planver;
55 while (<PLAN>) {
56 chomp;
57 if (m%\d+/\d+/\d+\s%) {
58 my ($date, $start, $duration) = split(/\s+/);
59 my $info = <PLAN>;
60 chomp $info;
61 my ($dontknow, $msg) = $info =~ m/^(.)\t(.+)$/;
62 print STDERR "E: $date $start $duration $msg\n" if $debug;
63
64 my $timestamp = str2time("$date $start");
65 my $isostartstamp = time2str("%Y%m%dT%H%M%S", $timestamp);
66 my $icalstartstamp = Date::ICal->new( epoch => $timestamp );
67
68 my @f = split(/:/, $duration);
69 $timestamp += ($f[0]*60*60 + $f[1]*60 +$f[2]);
70 my $isoendstamp = time2str("%Y%m%dT%H%M%S", $timestamp);
71 my $icalendstamp = Date::ICal->new( epoch => $timestamp );
72
73 print STDERR "IE: $isostartstamp $isoendstamp\n" if $debug;
74 push(@events, {
75 summary => $msg,
76 dtstart => $icalstartstamp->ical,
77 dtend => $icalendstamp->ical,
78 });
79 }
80 }
81 close(PLAN);
82 }
83
84
85 # BEGIN:VCALENDAR
86 # PRODID
87 # :-//test environment//NONSGML plan2icalendar//EN
88 # VERSION
89 # :2.0
90 # BEGIN:VEVENT
91 # CREATED
92 # :20020110T153939
93 # UID
94 # :KOrganizer-141229514.660
95 # SEQUENCE
96 # :0
97 # LAST-MODIFIED
98 # :20020110T153939
99 # DTSTAMP
100 # :20020110T153952
101 # SUMMARY
102 # :SL-veiledning
103 # DTSTART
104 # :20020114T151500
105 # DTEND
106 # :20020114T160000
107 # END:VEVENT
108 # END:VCALENDAR
109 sub write_icalendar {
110 my $filename = shift;
111 open(PLAN, ">$filename") || die "Unable to write to $filename";
112 print PLAN <<EOF;
113 BEGIN:VCALENDAR
114 CALSCALE:GREGORIAN
115 PRODID:-//test environment//NONSGML plan2icalender//EN
116 VERSION:2.0
117 EOF
118 my $count = 0;
119 for my $event (@events) {
120 $event->{uid} = "plan2icalendar-$count" unless $event->{uid};
121 $event->{dtstamp} = "20020110T153952" unless $event->{dtstamp};
122 $event->{'last-modified'} = "20020110T153939" unless $event->{'last-modified'};
123 $event->{sequence} = $count unless $event->{sequence};
124 $event->{created} = "20020110T153939" unless $event->{created};
125 print PLAN <<EOF;
126 BEGIN:VEVENT
127 CREATED:$event->{created}
128 UID:$event->{uid}
129 SEQUENCE:$count
130 LAST-MODIFIED:$event->{'last-modified'}
131 DTSTAMP:$event->{dtstamp}
132 SUMMARY:$event->{summary}
133 DTSTART:$event->{dtstart}
134 DTEND:$event->{dtend}
135 END:VEVENT
136
137 EOF
138 $count++;
139 }
140 print PLAN "END:VCALENDAR\n";
141 close PLAN;
142 }
143
144 #
145 # Should probably leave this task to Net::ICal. But it is not
146 # available in debian/sarge, so I make a quick-n-dirty solution
147 # instead.
148 #
149 sub read_icalendar {
150 my $filename = shift;
151 open (ICALENDAR, "<$filename") or die "Unable to read from $filename";
152 my $oldval = $/;
153 $/ = "\r\n";
154 while (<ICALENDAR>) {
155 chomp;
156 if (m/^BEGIN:VEVENT/) {
157 my %event;
158 while (<ICALENDAR>) {
159 chomp;
160 last if (m/END:VEVENT/);
161 $event{description} = $1 if (m/^DESCRIPTION\s*:\s*(.+)$/);
162 $event{created} = $1 if (m/^CREATED\s*:\s*(.+)$/);
163 $event{dtend} = $1 if (m/^DTEND\s*:\s*(.+)$/);
164 $event{dtstamp} = $1 if (m/^DTSTAMP\s*:\s*(.+)$/);
165 $event{dtstart} = $1 if (m/^DTSTART\s*:\s*(.+)$/);
166 $event{last-modified} = $1 if (m/^LAST-MODIFIED\s*:\s*(.+)$/);
167 $event{sequence} = $1 if (m/^SEQUENCE\s*:\s*(.+)$/);
168 $event{summary} = $1 if (m/^SUMMARY\s*:\s*(.+)$/);
169 $event{uid} = $1 if (m/^UID\s*:\s*(.+)$/);
170 }
171 push @events, \%event;
172 }
173 }
174 close (ICALENDAR);
175 $/ = $oldval;
176 }
177
178 # Simple version covering the chars I need.
179 sub utf8tolocalmap {
180 my $string = shift;
181 $string =~ s/ø/ø/g;
182 $string =~ s/æ/æ/g;
183 $string =~ s/Ã¥/å/g;
184 return $string;
185 }
186
187 sub write_planfile {
188 my $filename = shift;
189 open(PLAN, ">$filename") or die "Unable to write to $filename";
190 for my $event (@events) {
191 # offset = 0 -- assume all timestamps in local time zone
192 my $ical = Date::ICal->new( ical => $event->{dtstart}, offset => 0 );
193 my $date = join("/", $ical->month, $ical->day, $ical->year);
194 my $start = join(":", $ical->hour, $ical->min, $ical->sec);
195
196 my $icalstop = Date::ICal->new( ical => $event->{dtend}, offset => 0 );
197 my $icalduration = $icalstop - $ical;
198 my $duration = join(":",
199 $icalduration->hours || "0",
200 $icalduration->minutes || "0",
201 $icalduration->seconds || "0");
202
203 my $code = "N";
204 my $summary = utf8tolocalmap($event->{summary});
205 print PLAN "$date $start $duration 0:0:0 0:0:0 ---------- 0 0\n";
206 print PLAN "$code\t$summary\n";
207 }
208 }