From: Tim Pope Date: Wed, 24 Aug 2005 06:31:09 +0000 (+0000) Subject: Ugly iCal hack (to be improved, hopefully) X-Git-Url: http://git.tpope.net/?p=tpope-extra.git;a=commitdiff_plain;h=7bb0bf9e97c742e1c32066c016911346cddc0a8a Ugly iCal hack (to be improved, hopefully) --- diff --git a/perl/schedproc b/perl/schedproc index dc5df8c..de2e0e0 100755 --- a/perl/schedproc +++ b/perl/schedproc @@ -40,7 +40,7 @@ if($arg eq "-x") { Getopt::Long::Configure ("bundling", "auto_help"); die "Invalid arguments\n" unless -GetOptions(\%opts, 'schedule|S=s', 'grades|G=s', 'faculty=s', 'name|n=s', 'format|f=s', 'config|F=s', 'out|o=s'); +GetOptions(\%opts, 'schedule|S=s', 'grades|G=s', 'faculty=s', 'name|n=s', 'email|e=s', 'format|f=s', 'config|F=s', 'out|o=s'); if (-r $opts{'config'}) { open CONFIG, $opts{'config'} or die $!; @@ -48,8 +48,8 @@ if (-r $opts{'config'}) { s/\#.*//; next unless m/^([^=]*)=(.*)/; my ($l, $r) = ($1, $2); - if ($l =~ /^(schedule|grades|name|faculty)$/) { - $opts{$l}||=$r; + if ($l =~ /^(schedule|grades|name|email|faculty)$/) { + $opts{$l}=$r unless(defined($opts{$l})); } else { warn "Unknown config file option $l.\n"; } @@ -73,7 +73,7 @@ if(!defined($opts{'format'}) && defined($opts{'out'})) { $opts{'format'} = $opts{'out'}; $opts{'format'} =~ s/.*\.//; $opts{'format'} =~ s/^(.*\/|)\.?schedule$/mhc/; - undef $opts{'out'} if($opts{'out'} =~ /^(html|mhc|csv|vcs|xml|grades)$/); + undef $opts{'out'} if($opts{'out'} =~ /^(html|mhc|csv|vcs|ics|xml|grades)$/); } $opts{'format'} ||= ""; @@ -88,6 +88,7 @@ sub generate_id { } sub first_class { + my %days = (M => 1, T => 2, W => 3, R => 4, F => 5, S => 6, U => 7); my %class = @_; $class{'duration'} =~ /(\d\d\d\d)(\d\d)(\d\d)-(\d\d\d\d)(\d\d)(\d\d)/; my $days = Delta_Days($1,$2,$3,$4,$5,$6); @@ -95,8 +96,8 @@ sub first_class { my $lastday = Date::Calc->new($4,$5,$6); my $today; my @days=(); - foreach(split(" ",$class{'days'})) { - push @days, Decode_Day_of_Week($_); + foreach(split("",$class{'days'})) { + push @days, $days{$_}; } my @off = (); @off = @{$class{'off'}} if ($class{'off'}); @@ -109,6 +110,7 @@ sub first_class { } sub next_class { + my %days = (M => 1, T => 2, W => 3, R => 4, F => 5, S => 6, U => 7); my %class = @_; $class{'duration'} =~ /(\d\d\d\d)(\d\d)(\d\d)-(\d\d\d\d)(\d\d)(\d\d)/; my $days = Delta_Days($1,$2,$3,$4,$5,$6); @@ -116,8 +118,8 @@ sub next_class { my $lastday = Date::Calc->new($4,$5,$6); my $today = Date::Calc->new(Date::Calc->localtime(time+3600*6)->date); my @days=(); - foreach(split(" ",$class{'days'})) { - push @days, Decode_Day_of_Week($_); + foreach(split("",$class{'days'})) { + push @days, $days{$_}; } my @off = (); @off = @{$class{'off'}} if ($class{'off'}); @@ -135,6 +137,16 @@ sub next_class { return undef; } +sub ical_datetime { + my $date=shift; + my $time=shift; + $date =~ /(\d\d\d\d)(\d\d)(\d\d)/; + my ($y,$m,$d)=($1,$2,$3); + $time =~ /(\d\d):?(\d\d)/; + my $day=Date::Calc->gmtime(Mktime($y,$m,$d,$1,$2,0)); + return sprintf ("%02d%02d%02dT%02d%02d%02dZ", $day->year(), $day->month(), $day->day(), $day->time()); +} + sub capitalize { local $_ = shift || ""; s/ +$//; @@ -171,14 +183,20 @@ sub read_fileurl { $ua->env_proxy; # $ua->cookie_jar( {} ); my $response = $ua->get("$url") or die "$!"; - die $response->status_line unless $response->is_success; - $content = $response->content; + if($response->is_success) { + $content = $response->content; + } else { + die "$!" unless $_[0]; + } } else { - open(F,$url) || die "$!"; - $content = join ("", ); - close F; + if(open(F,$url)) { + $content = join ("", ); + close F; + } else { + die "$!" unless $_[0]; + } } - return $content; + return $content||""; #my $ref = XMLin($content, ForceArray => [ 'class', 'cumulative', 'off' ], KeyAttr => ""); #return @{$ref->{'class'}}; } @@ -199,7 +217,8 @@ sub get_grades { sub load_faculty { my ($name, $email, $url, $content); if(($opts{'faculty'}) && ! %faculty) { - $content = read_fileurl($opts{'faculty'}); + $faculty{'done'} = "true"; + $content = read_fileurl($opts{'faculty'},1); foreach $_ (split("\n", $content)) { m/"([^"]*)",([^,]*),([^,]*)/; # " ($name, $email, $url) = ($1, $2, $3); @@ -269,6 +288,7 @@ sub do_mhc_schedule { foreach my $row (@schedule) { map {s/\n/-/g if defined; $_} %$row; my $id=generate_id($row->{'id'}); + my $next = next_class(%$row); $row->{'days'} =~ s/([MTWRFS])/ $days{$1}/g; $row->{'days'} =~ s/^ //; #$row->{'duration'} =~ s/(\d\d)-(\d\d)-(\d\d)/20$3$1$2/g; @@ -290,7 +310,6 @@ sub do_mhc_schedule { $row->{'instructor'} = '"' . $row->{'instructor'} . '" <'. ($email || ($1 || "unknown") . "\@from.sctweb") . ">"; $row->{'duration'} =~ /^(\d\d\d\d)(\d\d)(\d\d)-\d{8}$/; $row->{'begin'} =~ /^(\d\d):(\d\d)$/; - my $next = next_class(%$row); my @date = Gmtime(Mktime($next->date,$1,$2,0)); $current .= sprintf "Date: %s, %2d %s %4d %02d:%02d:00 +0000\n", Day_of_Week_Abbreviation($date[7]), $date[2], $mon[$date[1]-1], $date[0], $date[3], $date[4], $date[5]; $current .= "Subject: " . $row->{'title'} . "\n"; @@ -334,9 +353,9 @@ sub do_csv_schedule { foreach my $row (@schedule) { map {s/\n/-/g if defined; $_} %$row; my $id=generate_id($row->{'id'}); + my $next = next_class(%$row); $row->{'days'} =~ s/([MTWRFS])/ $days{$1}/g; $row->{'days'} =~ s/^ //; - my $next = next_class(%$row); $current = ""; #print "# $id\n"; $current .= $row->{'id'} . ","; @@ -355,13 +374,11 @@ sub do_vcalendar_schedule { my %days = (M => "MO", T => "TU", W => "WE", R => "TH", F => "FR", S => "SA", U => "SU"); my $file = $opts{'out'}; my @schedule = get_schedule(@_); - open(STDOUT, ">>" . $file) || die $! if(defined($file) && (! -d $file)); + open(STDOUT, ">" . $file) || die $! if(defined($file) && (! -d $file)); open(STDOUT, ">/dev/null") || die $! if(defined($file) && (-d $file)); print "BEGIN:VCALENDAR\r\nVERSION:1.0\r\n"; foreach my $row (@schedule) { map { s/\n/-/g; $_} %$row; - $row->{'days'} =~ s/([MTWRFS])/ $days{$1}/g; - $row->{'days'} =~ s/^ //; my @day = (); @day = @{$row->{'off'}} if ($row->{'off'}); my $day = ""; @@ -373,6 +390,7 @@ sub do_vcalendar_schedule { my ($startdate, $stopdate)=split(/-/, $row->{'duration'}); $starttime =~ s/://; $stoptime =~ s/://; + my $first = first_class(%$row); if(defined($file) && (-d $file)) { open FH, ">$file/" . $row->{'id'} . ".vcs" or die "$!"; select FH; @@ -383,11 +401,14 @@ sub do_vcalendar_schedule { print "DESCRIPTION:", $row->{'id'}, "\r\n"; print "LOCATION:", $row->{'location'}, "\r\n"; print "CATEGORIES:Education\r\n"; - print "DTSTART:", first_class(%$row)."T".$starttime, "00\r\n"; - print "DTEND:", first_class(%$row)."T".$stoptime, "00\r\n"; + #print "DTSTART:", ical_datetime(first_class(%$row),$starttime), "\r\n"; + print "DTSTART:", $first."T".$starttime, "00\r\n"; + print "DTEND:", $first."T".$stoptime, "00\r\n"; + $row->{'days'} =~ s/([MTWRFS])/ $days{$1}/g; + $row->{'days'} =~ s/^ //; print "RRULE:W1 ", $row->{'days'} . " $stopdate", "T000000\r\n"; print("EXDATE:$day\r\n") if($day); - print "ATTENDEE;ROLE=OWNER;STATUS=CONFIRMED:", $opts{'name'}, "\r\n" if(defined($opts{'name'})); + print "ATTENDEE;ROLE=OWNER;STATUS=CONFIRMED:", $opts{'name'}, ($opts{'email'}?" <".$opts{'email'}.">":""), "\r\n" if(defined($opts{'name'})); print "ATTENDEE;ROLE=ORGANIZER;STATUS=CONFIRMED:", $row->{'instructor'}, " <" . (get_faculty_email($row->{'instructor'}) || "fake\@ddress"), ">\r\n"; print "END:VEVENT\r\n"; if(defined($file) && (-d $file)) { @@ -399,6 +420,78 @@ sub do_vcalendar_schedule { print "END:VCALENDAR\r\n"; } +sub do_icalendar_schedule { + $| = 1; + my $r="\r"; + # Ugh, I can't find a better solution than hardwiring it to CST + my $tzn = "America/Chicago"; + my $timezone = < "MO", T => "TU", W => "WE", R => "TH", F => "FR", S => "SA", U => "SU"); + my $file = $opts{'out'}; + my @schedule = get_schedule(@_); + open(STDOUT, ">" . $file) || die $! if(defined($file) && (! -d $file)); + open(STDOUT, ">/dev/null") || die $! if(defined($file) && (-d $file)); + print "BEGIN:VCALENDAR$r\nVERSION:2.0$r\n$timezone"; + foreach my $row (@schedule) { + map { s/\n/-/g; $_} %$row; + my @day = (); + @day = @{$row->{'off'}} if ($row->{'off'}); + my ($starttime, $stoptime)=($row->{'begin'}, $row->{'end'}); + my ($startdate, $stopdate)=split(/-/, $row->{'duration'}); + $starttime =~ s/://; + $stoptime =~ s/://; + my $first = first_class(%$row); + if(defined($file) && (-d $file)) { + open FH, ">$file/" . $row->{'id'} . ".vcs" or die "$!"; + select FH; + print "BEGIN:VCALENDAR$r\nVERSION:2.0$r\n$timezone"; + } + print "BEGIN:VEVENT$r\n"; + print "SUMMARY:", $row->{'title'}, "$r\n"; + print "DESCRIPTION:", $row->{'id'}, "$r\n"; + print "LOCATION:", $row->{'location'}, "$r\n"; + print "CATEGORIES:Education$r\n"; + #print "DTSTART;$tzn$first,$starttime), "$r\n"; + #print "DTEND;$tzn$first,$stoptime), "$r\n"; + print "DTSTART;\"$tzn\":", $first."T".$starttime, "00$r\n"; + print "DTEND;\"$tzn\":", $first."T".$stoptime, "00$r\n"; + $row->{'days'} =~ s/([MTWRFS])/,$days{$1}/g; + $row->{'days'} =~ s/^,//; + print "RRULE:FREQ=WEEKLY;UNTIL=$stopdate;BYDAY=", $row->{'days'}, "$r\n"; + foreach my $day (@day) { + print("\"EXDATE\";$tzn$day$r\n"); + } + print "ATTENDEE;CN=".$row->{'instructor'}.";RSVP=FALSE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:" . (get_faculty_email($row->{'instructor'}) || "fake\@ddress"), "$r\n"; + print "ATTENDEE;CN=".$opts{'name'}.";RSVP=FALSE;PARTSTAT=ACCEPTED;ROLE=REQ-PARTICIPANT:mailto:" . ($opts{'email'} || "fake\@ddress"), "$r\n" if $opts{'name'}; + print "END:VEVENT$r\n"; + if(defined($file) && (-d $file)) { + print "END:VCALENDAR$r\n"; + close FH; + select STDOUT; + } + } + print "END:VCALENDAR$r\n"; +} + sub do_xml_schedule { my $file = $opts{'out'}; my $schedule = { class => [ get_schedule(@_) ] }; @@ -505,6 +598,8 @@ if ($opts{'format'} eq "xml") { do_csv_schedule(@ARGV); } elsif ($opts{'format'} eq "vcs") { do_vcalendar_schedule(@ARGV); +} elsif ($opts{'format'} eq "ics") { + do_icalendar_schedule(@ARGV); } elsif ($opts{'format'} eq "grades") { do_html_grades(@ARGV); } else {