ical2rdf.pl
22.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
#!/usr/bin/perl
#
# usage: perl ical2rdf.pl something.ics >something.rdf
#
# by Dan Connolly and Libby Miller
# with contributions by George Huo
# http://lists.w3.org/Archives/Public/www-rdf-calendar/2003Sep/0000.html
# and M.Kanzaki <webmaster@kanzaki.com>
#
# FYI: Dan Connolly's newer work is in fromIcal.py
#
# Open Source. share and enjoy.
#
# RDF Calendar Workspace: http://www.w3.org/2002/12/cal/
#
# Copyright 2002-2003 World Wide Web Consortium, (Massachusetts
# Institute of Technology, European Research Consortium for
# Informatics and Mathematics, Keio University). All Rights
# Reserved. This work is distributed under the W3C(R) Software License
# http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
# in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE.
#
# REFERENCES
#
# Internet Calendaring and Scheduling Core
# Object Specification (iCalendar)
# November 1998
# http://www.ietf.org/rfc/rfc2445.txt
# http://www.imc.org/rfc2445
#
# NOTE: We don't claim to implement the whole spec, nor to even have
# read all of it. We're taking a data-driven, test-driven approach
# to RFC2445 coverage/conformance. We start with a .ics file that we
# understand (because it came from a tool that acts as we expect in
# response to it or some such) and we implement the parts of the
# spec necessary to grok the data in that file. As we work on more
# test files, we cover (and carefully read) more parts of the spec.
#
# Building an RDF model: A quick look at iCalendar
# http://www.w3.org/2000/01/foo
# TimBL 2000/10/02
#
#
#
# CGI version by M.Kanzaki <webmaster@kanzaki.com> 2003-2004
# http://www.kanzaki.com/courier/ical2rdf
#
# see also:
# http://www.ietf.org/internet-drafts/draft-ietf-calsch-many-xcal-00.txt
# http://xml.coverpages.org/iCal-DTD-20011103.txt
#
# versions up to
# vcal2xml.pl,v 1.6 2002/07/16 05:02:23 connolly
# were released under...
# http://dev.w3.org/cvsweb/2001/palmagent/
#
# $Id: ical2rdf.pl,v 1.23 2005/02/26 03:12:47 connolly Exp $
# see change log at end of file.
use strict;
# Digest::SHA1 Perl interface to the SHA-1 Algorithm
# http://search.cpan.org/author/GAAS/Digest-SHA1-2.02/
use Digest::SHA1 qw(sha1_hex);
# Getopt::Long - Extended processing of command line options
# http://search.cpan.org/author/JV/Getopt-Long/lib/Getopt/Long.pm#Options_with_values
use Getopt::Long;
#http://search.cpan.org/~dankogai/Jcode-0.83/
use Jcode;
my($X_ns);
my($componentName);
GetOptions ('xnames=s' => \$X_ns,
'componentName=s' => \$componentName);
my($ICal_ns) = 'http://www.w3.org/2002/12/cal/ical#';
my($Prod_ns) = 'http://www.w3.org/2002/12/cal/prod/';
my(@stack);
my($intag);
my($field, $line);
my($nsDone);
my($rdf); # buffer for most of the output
my($warnmsg); # warning message
#$field = <>;
$field =open (IN, $ARGV[0]);
my(@symbolProps) = ('transp', 'partstat', 'rsvp',
'related');
# The following props can be a symbol _or_ an
# iana-token! they are now handled correctly.
# see %symbolVals
my(@symbolOrTextProps)
= ('action', 'class', 'role', 'cutype');
my(@resProps) = ('standard', 'daylight',
'valarm', 'trigger',#@@mismatch?
);
# dir. @@should it be in valProps? see lexform...
# unclear, works this way
my(@refProps) = ('attendee', 'organizer', 'dir',
'X', # from mozilla calendar stuff. @@OK?
);
my(@valProps) = ('dtstart', 'dtend',
'dtstamp', 'lastModified', 'created', 'completed',
'trigger', 'recurrenceId',
'rrule', # special...
'exdate' #@@comma-separated
#,'summary','location' #by MK for language param, but generated <text>...</text> also.
);
# hmm... slurp this from the RFC, into a schema, then
# read at runtime?
my(%ValueType) = (
'calscale', 'text', # 4.7.1 Calendar Scale
'method', 'text', # 4.7.2 Method
'prodid', 'text', # 4.7.3 Product Identifier
'version', 'text', # 4.7.4 Version
'summary', 'text',
'sequence', 'integer', # 4.8.7.4 Sequence Number
'uid', 'text', # 4.8.4.7 Unique Identifier
'tzid', 'text', # 4.8.3.1 Time Zone Identifier hmm... property and parameter by the same name
'tzoffsetfrom', 'utcOffset', # 4.8.3.3 Time Zone Offset From
'tzoffsetto', 'utcOffset',
'tzname', 'text', # 4.8.3.2 Time Zone Name
'rrule', 'recur', # 4.8.5.4 Recurrence Rule
'transp', 'text', # 4.8.2.7 Time Transparency
'class', 'text', # 4.8.1.3 Classification hmm... symbolprop?
'contact', 'text', #@@CheckSpecAndCite
'location', 'text', # 4.8.1.7 Location
'description', 'text',
'categories', 'text', # 4.8.1.2 Categories hmm... text *("," text)
'organizer', 'calAddress', # 4.8.4.3 Organizer
'attendee', 'calAddress', # 4.8.4.3 Organizer
'duration', 'duration', # 4.8.2.5 Duration
'action', 'text', # 4.8.6.1 Action
'attach', 'uri', # 4.8.1.1 Attachment
'url', 'uri', # @@
'comment', 'text', # 4.8.1.4 Comment
'priority', 'integer', # 4.8.1.9 Priority
'completed', 'dateTime', # 4.8.2.1 Date/Time Completed"
'status', 'text', # 4.8.1.11 Status
'recurrenceId', 'dateTime', # 4.8.4.4 Recurrence ID
'trigger', 'duration', # 4.8.6.3 Trigger
'repeat', 'integer', # 4.8.6.2 Repeat Count
'freebusy', 'period', # 4.8.2.6 Free/Busy Time (@@period is not implemented by this ical2rdf)
);
my(%ValueTypeD) = ('dtend', 'dateTime', # 4.8.2.2 Date/Time End
'dtstart', 'dateTime', # 4.8.2.4 Date/Time Start
'dtstamp', 'dateTime', # 4.8.7.2 Date/Time Stamp
'lastModified', 'dateTime', # 4.8.7.3 Last Modified
'exdate', 'dateTime', # 4.8.5.1 Exception Date/Times
'rdate', 'dateTime', # 4.8.5.3 Recurrence Date/Times
'created', 'dateTime', # 4.8.7.1 Date/Time Created
'due', 'dateTime', # 4.8.2.3 Date/Time Due
);
# attribute value types
my(%ValueTypeA) = ('dir', 'uri' # 4.2.6 Directory listing
);
my(@component) = ("Vevent" , "Vtodo" , "Vjournal" , "Vfreebusy"
, "Vtimezone" ); # / x-name / iana-token)
my(@classnames) = (@component,"Vcalendar");#names not to be lowercase: by MK
# hash of possible values for symbol properties
# we're using $IANATOKEN as a list element to
# indicate that the symbol can be arbitrary text.
# better way to do this?
# currently only used for properties that can be either
# symbols _or_ iana-tokens
my($IANATOKEN) = 0;
my(%symbolVals)
= ('action', ['AUDIO', 'DISPLAY', 'EMAIL', 'PROCEDURE',
$IANATOKEN],
'cutype', ['INDIVIDUAL', 'GROUP', 'RESOURCE', 'ROOM',
'UNKNOWN', $IANATOKEN],
'class', ['PUBLIC', 'PRIVATE', 'CONFIDENTIAL',
$IANATOKEN],
'role', ['CHAIR', 'REQ-PARTICIPANT', 'OPT-PARTICIPANT',
'NON-PARTICIPANT', $IANATOKEN]
);
# VERSION: hmm... kinda worthless.
#first pass to get prodid
while(1){
last unless $field;
while(($line = <IN>) =~ s/^\s//){ # 4.1 Content Lines
$field .= $line;
}
$field =~ s/\r?\n//g; # get rid of newlines
# print STDERR "... field:", $field, "\n";
# not sure where to put this - prodid to create xproperty namespace
if($field =~ m/PRODID/){
icalwarning("clobbering - -xnames $X_ns") if $X_ns; #avoid illegal comment MK
$X_ns=createxns($field);
}
$field = $line;
}#end first pass
#ugly - don't know how else to do it though...
close(IN);
$field =open (ININ, $ARGV[0]);
#second pass to get the rest
while(1){
last unless $field;
while(($line = <ININ>) =~ s/^\s//){ # 4.1 Content Lines
$field .= $line;
}
$field =~ s/\r?\n//g; # get rid of newlines
if($field =~ /^BEGIN:(\w+)/i){
my($n) = ($1);
printstr ("\n>") if $intag;
if($nsDone){
if(grep(lc($_) eq lc($n), @classnames)){ #avoid lower 'vcalendar' by MK
$n = camelCase($n, 1);
if($#stack == 0){
printstr(" <component>\n");
}
#by MK add a space before tag
if($componentName){
printstr (" <".$n." rdf:about='#".$componentName."'>\n");
$componentName++;
}else{
printstr (" <".$n.">\n");
}
}
elsif(grep(lc($_) eq lc($n), @resProps)){
$n = camelCase($n);
printstr (" <".$n." rdf:parseType='Resource'>\n");
}else{
$n = camelCase($n);
printstr (" <".$n.">");
}
}else{
$n = camelCase($n, 1);
printstr("<".$n.">\n");
$nsDone = 1;
}
push(@stack, $n);
}
elsif($field =~ /^END:(\w+)/i){
my($n) = $1;
printstr ("\n>") if $intag;
$intag = 0;
my($m);
$m=pop(@stack);
icalwarning("mismatch [$n] expected [$m]") unless lc($n) eq lc($m);
# some cosmetic space before tag
printstr (" </".$m.">\n");
if($#stack == 0){
printstr(" </component>\n");
}
}
elsif($field =~ s/^([\w-]+)([;:])\s*/$2/){
my($n) = ($1);
my($enc, $iprop, %attrs, $attrp, $xprop);
if($n =~ s/^X-//i){
if(!$X_ns){
icalwarning("X- property ($n) requires PRODID field $X_ns");
$field = $line;
next;
}
$xprop = 1
};
$n = camelCase($n);
if($xprop){ $n = "x:" . $n };
printstr (" <".$n);
# @@ where munging occurs. the colon can appear in a
# quoted value, e.g. in ORGANIZER;DIR="ldap://blah"...
# this now works for all cases except when there is a
# semicolon within quotes.
# to avoid this, we first parse attributes that involve quotes
# check that there is no semicolon within quotes
my($sc_in);
while($field =~ /[";]/g){
$sc_in^=1 if $& eq q(");
if($& eq ";" && $sc_in) { # @@bail out!
icalwarning("Can't parse semicolons within quotes, near ".$field);
}
}
# other than the regex, this code block (is unmodular
# and) does the same as the next one
while($field =~ s/;([\w-]+)="([^;]+)"([;:])/$3/g){
my($an, $av) = (camelCase($1), $2);
if($an eq 'value'){
$iprop = camelCase($av);
}else{
$attrs{$an} = $av;
#icalwarning("found attr on $n: $an = $av");;
$attrp = 1;
}
}
while($field =~ s/^;([\w-]+)=([^;:]+)//){
my($an, $av) = (camelCase($1), $2);
if($an eq 'value'){
$iprop = camelCase($av);
}else{
$attrs{$an} = $av;
#icalwarning("found attr on $n: $an = $av");;
$attrp = 1;
}
}
if(! $iprop) {
if($xprop) { $iprop = 'text' } # 4.8.8.1 Non-standard Properties
else { $iprop = $ValueType{$n} || $ValueTypeD{$n} };
if(! $iprop){
# not to die, by MK
icalwarning("no value type given, default unknown: $n $field");
$iprop = 'text'; #regard type as text if no default found
}
}
##?? not quite meaningful ?? MK
while($field =~ s/^;([\w-]+)//){
$enc = $1;
icalwarning("field: $field; enc = $enc");; #MK
}
if($field =~ s/^:\s*(.*)//){
my($v) = ($1);
if($attrs{'encoding'} eq 'QUOTED-PRINTABLE'){ #not $enc by MK
## ----- qp2utf8 -- qp can be multiple lines. Also need conversion to utf8: by MK
while($v =~ s/=$//){
$v .= $line;
# $line = shift(@lines);
}
$v =~ s/=(..)/pack("c",hex($1))/ge;
Jcode::convert(\$v,'utf8');
## ----- qp2utf8 ends
}
elsif($enc){
icalwarning("unkown enc $enc");
}
# support for `possibly symbol' values
if(grep($_ eq $n, @symbolOrTextProps)){
if(grep($_ eq $v, @{$symbolVals{$n}})){
$v = camelCase($v);
#hmm... another namespace for enumerated values?
printstr(" rdf:resource='". $ICal_ns . $v ."'/>\n");
}else{
printstr(">". asContent($v) ."</". $n .">\n");
}
}
elsif(grep($_ eq $n, @symbolProps)){
$v = camelCase($v);
#hmm... another namespace for enumerated values?
printstr(" rdf:resource='". $ICal_ns . $v ."'/>\n");
}
elsif(grep($_ eq $n, @refProps)){
$v =~ s/^MAILTO:/mailto:/; #fix borkenness
printstr(" rdf:parseType='Resource'>\n");
printstr (" <".$iprop." rdf:resource='".asAttr($v)."'/>\n");#by MK deleted a space before tag
# the valProps code also calls printAttrs
printAttrs(%attrs);
printstr (" </".$n.">\n");
}
elsif(grep($_ eq $n, @valProps)){
printstr(" rdf:parseType='Resource'>\n");
# e.g. RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR
# be careful about defaults!
# hmm... key this off value-type recur (4.3.10 Recurrence Rule)
# rather than the property name?
if($n eq 'rrule'){ # 4.8.5.4 Recurrence Rule
$attrs{'interval'} = '1'; # set default for WKS too? not until we can test it...
while($v =~ s/^([\w-]+)=([^;:]+);?//){
#@@ treat freq as symbolprop? i.e. normalize case of YEARLY etc.
my($an, $av) = (camelCase($1), $2);
$attrs{$an} = $av;
}
}else{
$v = lexForm($iprop, $v);
printstr(" <".$iprop.">".asContent($v)."</".$iprop.">\n"); #by MK deleted a space before tag
}
# the refProps code also calls printAttrs
printAttrs(%attrs);
printstr (" </".$n.">\n");
}
else{
if($iprop eq 'uri'){
printstr (" rdf:resource='".asAttr($v)."'/>\n");
}else{
$v = lexForm($iprop, $v);
printstr (">".asContent($v)."</".$n.">\n");
}
icalwarning("unexpected attrs on $n") if $attrp;
}
}else{
icalwarning("field garbage: [". $field. "]");
}
}
else{
last if eof;
}
$field = $line;
}
printstr ("\n>") if $intag;
startDoc();
print ($rdf);
print ("</rdf:RDF>\n");
sub printAttrs{
my(%attrs) = @_;
my($an);
foreach $an (keys %attrs){
my($av) = $attrs{$an};
# some elements of @symbolProps were being
# ignored before... now they are actually outputted
# as rdf:resource.
# @@ this dupes code from above.
if(grep($_ eq $an, @symbolOrTextProps)){
if(grep($_ eq $av, @{$symbolVals{$an}})){
#hmm... another namespace for enumerated values?
printstr(" <".$an." rdf:resource='". $ICal_ns . camelCase($av) ."'/>\n");
}else{
printstr(" <".$an.">".asContent($av)."</".$an.">\n");
}
}elsif(grep($_ eq $an, @symbolProps)){
printstr(" <".$an." rdf:resource='". $ICal_ns . camelCase($av) ."'/>\n");
}elsif(grep($_ eq $an, @refProps)){
my($anprop);
$an = camelCase($an);
$anprop = $ValueTypeA{$an};
printstr(" <".$an." rdf:parseType='Resource'>\n");
printstr(" <".$anprop." rdf:resource='".asAttr($av)."'/>\n");
printstr(" </".$an.">\n");
}else{
my($av) = $attrs{$an};
printstr(" <".$an.">".asContent($av)."</".$an.">\n");
}
#icalwarning("serialized attr $an = $av");;
}
}
sub startDoc{
# my($n) = @_;
printf(
"<rdf:RDF
xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
xmlns='%s'
xmlns:i='%s'
xmlns:x='%s'
>",
$ICal_ns, $ICal_ns, $X_ns);
if($warnmsg ne ""){
printstr("<!-- warning: $warnmsg -->\n");
}
}
close(IN);
sub asContent{
my($c) = @_;
$c =~ s,&,&,g;
$c =~ s,<,<,g;
$c =~ s,>,>,g;
#$c =~ s/[\200-\377]/'&#'.ord($&).';'/ge; # comment out by MK to handle CJK
#@@hhm... protect newlines too?
return $c
}
sub lexForm{
my($iprop, $v) = @_;
if($iprop eq 'text'
|| $iprop eq 'integer'
|| $iprop eq 'utcOffset' # 4.3.14 UTC Offset hm... xml schema uses punct?
|| $iprop eq 'duration'
){
# do nothing
}
elsif($iprop eq 'dateTime'){
$v =~ s/(\d\d\d\d)(\d\d)(\d\d)T(\d\d)(\d\d)(\d\d)(.*)/$1-$2-$3T$4:$5:$6$7/;
}
elsif($iprop eq 'date'){
$v =~ s/(\d\d\d\d)(\d\d)(\d\d)/$1-$2-$3/;
}
elsif($iprop eq 'uri'){
#umm... hmm... leave URIs as is?
icalwarning("relative URI reference; not clear that this is allowed/interoperable") unless $v =~ /^\w+:/;
}
# cal-address: s/MAILTO/mailto/
else{
icalwarning("unknown iprop $iprop; dunno what to do with value '$v'");
}
return $v;
}
sub asAttr{
my($c) = @_;
$c =~ s,&,&,g;
$c =~ s,<,<,g;
$c =~ s,>,>,g;
$c =~ s,\",",g; #" (just to balance quotation marks)
$c =~ s,\',',g;
#$c =~ s/[\200-\377]/'&#'.ord($&).';'/ge; # comment out by MK for CJK
#@@hhm... protect newlines too?
return $c
}
sub camelCase{
my($n, $initialCap) = @_;
my(@words) = map(lc, split(/-/, $n));
if($initialCap){
return join('', map(ucfirst, @words));
}else{
return $words[0] . join('', map(ucfirst, @words[1..$#words]));
}
}
sub testCamelCase{
my(@cases, $n);
@cases = ("DTSTART", "LAST-MODIFIED");
foreach $n (@cases){
printf "case: %s: prop: %s class: %s\n",
$n, camelCase($n), camelCase($n, 1);
}
}
# for xproperties need to parse the prodid before
# printing anything else out, so create a string and then print it out
# probably a better way of doing this....
sub printstr{
my $str=shift;
$rdf=$rdf.$str;
}
#cf discussion starting with
# x-properties and namespaces
# posted by DanC at 2003-02-26 17:17 (+)
# http://rdfig.xmlhack.com/2003/02/26/2003-02-26.html#1046279854.884486
#and continuing thru
# RDF calendar agenda item C: prodid support to ical2rdf.pl
# posted by libby at 2003-07-09 14:59 (+)
# http://rdfig.xmlhack.com/2003/07/09/2003-07-09.html#1057762764.179078
sub createxns{
my $prodid=shift;
#@@hmm... sure would be nice to include unit tests for creatxns,
# ala python doctest module.
#remove the word "PRODID"
#then remove first three chars of e.g. -//Apple Computer\, Inc//iCal 1.0//EN
$prodid=~ s/PRODID://;
$prodid=~ s/-\/\///;
#then replace all spaces with _
$prodid=~ s/\s/_/g;
#then replace all // with _
$prodid=~ s/\/\//_/g;
#then create sha1 (lowercased)
my $sha=sha1($prodid);
#then add first 10 chars and add '_'
my $xns=substr($prodid,0,10)."_";
#then add first 5 chars of the sha1.
$xns=$xns.substr($sha,0,16);
#prodns - http://www.w3.org/2002/12/cal/prod/
return $Prod_ns.$xns."#";
}
# sha1 for prodid xproperty creation
# note transform to lower case
sub sha1{
my $string = shift;
$string=lc($string);
my $encoded = sha1_hex($string);
return $encoded;
}
sub icalwarning{
# @@hmm... is there a hook in the perl infrastructure
# to redirect the output of the warn statement?
my ($str) = shift;
$warnmsg .= "$str\n";
# printstr("<!-- warning: $str -->\n");
}
# $Log: ical2rdf.pl,v $
# Revision 1.23 2005/02/26 03:12:47 connolly
# refer to newer work
#
# Revision 1.22 2004/01/21 23:30:46 connolly
# - factored out names of developers into
# by line and acknowledgements
# - moved MK's list of changes to the change log
# - moved pointer to MK's online service to REFERENCES
# - removed "ADDED" (from George)
# - changed \3 to $3 per diagnostic from perl -wc
# - indented printstr and nearby subs
#
# Revision 1.21 2004/01/19 23:05:03 lmiller
# added link to Jcode for Japanese character support.
#
# Revision 1.20 2004/01/18 21:00:18 lmiller
# modified to take account of X-WR-CALNAME before PRODID
# cf http://lists.w3.org/Archives/Public/www-rdf-calendar/2004Jan/0001.html
#
# Revision 1.19 2004/01/18 19:07:43 lmiller
# additions from Masahide Kanzaki
# Multiple Vcalendars now work (test is MozMulipleVcalendars.ics).
# - to implement it as CGI (some headers, not 'die' or 'warn' etc)
# - to handle Japanese characters
# - to parse more attributes
# - for cosmetics (add/delete spaces before tags).
# and may contain some dependencies on MK's environment.
#
# Revision 1.18 2003/08/23 08:46:47 ghuo
# Reorganized and added some value types. Fixed output that
# was being munged. Added support for param types in deeper
# levels.
#
# Revision 1.17 2003/07/09 16:43:06 connolly
# 16 chars of sha1 in X- namespace
#
# Revision 1.16 2003/07/09 16:35:48 connolly
# don't rely on -//
#
# Revision 1.15 2003/07/09 16:28:35 connolly
# warning for --xnames, pointer to SHA1 sources
#
# Revision 1.14 2003/07/09 13:09:35 lmiller
# added support for prodid for generating the xproperty namespace rather than having to add it by hand. Now uses http://search.cpan.org/author/GAAS/Digest-SHA1-2.02/ for the sha1 digest.
#
# Revision 1.13 2003/07/07 21:11:08 connolly
# added recurrenceId
#
# Revision 1.12 2003/03/27 22:15:33 connolly
# added support for a few to-do-related properties.
# The data I'm working with are sensitive.
# @@I owe a scrubbed test case.
#
# Revision 1.11 2003/03/14 06:01:34 connolly
# added last-modified support
#
# Revision 1.10 2003/03/14 05:12:36 connolly
# treat dtstamp like dtstart and dtend
#
# Revision 1.9 2003/02/20 21:24:22 connolly
# fixed double-camel-casing value types
# added exdate support
#
# Revision 1.8 2003/02/20 00:00:21 connolly
# --componentName option, e.g.
# for naming Vtimezone's
#
# Revision 1.7 2003/02/14 17:10:05 connolly
# ical.{n3,rdf}:
# added ical:component per 12Feb meeting
# added comment while I was at it
#
# ical2rdf.pl:
# updated copyright/license blurb
# no more about='' on <Vcalendar>, per 12Feb meeting
# calendar description now contains event descriptions,
# linked by ical:component, per 12Feb meeting
# refined rrule support; interval defaults to 1
#
# Makefile:
# ical schema is now based on a 3rd data file, gkexample
# refactored DATA_FOR_SCHEMA
#
# Revision 1.6 2003/01/22 21:17:12 connolly
# fixed value=uri as agreed in #rdfig today
#
# Revision 1.5 2003/01/22 00:19:18 connolly
# handling type=uri
#
# Revision 1.4 2003/01/08 20:01:06 connolly
# added support for METHOD property per section 4.7.2 Method of RFC2445
#
# Revision 1.3 2002/12/20 08:03:37 connolly
# another test; a bunch more properties
#
# Revision 1.2 2002/12/20 07:04:46 connolly
# value type names get camel-cased
#
# Revision 1.1 2002/12/20 06:52:50 connolly
#
# moved ical namespace from 2000/10/swap/pim to 2002/12/cal
# fixed dates to YYYY-MM-DD form
#
# Revision 1.6 2002/12/13 18:55:21 connolly
# added --xnames option to give namespace
# for X- properties
#
# Revision 1.5 2002/09/03 17:20:41 connolly
# handle individual vevents
#
# Revision 1.4 2002/07/18 05:26:36 connolly
# be more conservative about X- stuff
#
# Revision 1.3 2002/07/18 05:16:32 connolly
# oops! got ical URI wrong! thx daml validator
#
# Revision 1.2 2002/07/17 20:59:40 connolly
# using ical:value in stead of rdf:value
#
# Revision 1.1 2002/07/17 20:34:55 connolly
# moving from palmagent
#
# Revision 1.6 2002/07/16 05:02:23 connolly
# rudimentary rrule parsing
#
# Revision 1.5 2002/07/16 04:36:46 connolly
# camelCase
#
# Revision 1.4 2002/06/29 06:13:51 connolly
# produces pretty good RDF from my evolution calendar now;
# handles several different flavors of properties.
#
# Revision 1.3 2002/06/29 04:19:40 connolly
# turns some ical files (from evolution) into nearly RDF.
# it's wf XML, at least.
# need to deal with VALUE= attributes and such.
#
# Revision 1.2 2001/07/27 16:47:43 connolly
# seems to work on my korganizer calendar (addeds support for
# ;params and QUOTED-PRINTABLE).
#
# 1.1 seems to work on two test files from my nokia cellphone.