| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  | #!/usr/bin/perl -w | 
					
						
							|  |  |  | # calendar-export.plx                                         -*- Perl -*- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # NOTE: Overall license of this file is GPLv3-only, due (in part) to Software | 
					
						
							|  |  |  | # Freedom Law Center copyrights (see below).  Kuhn's personal copyrights are | 
					
						
							|  |  |  | # licensed GPLv3-or-later. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-29 15:58:22 -05:00
										 |  |  | # ==================================================================== | 
					
						
							| 
									
										
										
										
											2013-11-30 14:07:37 -05:00
										 |  |  | # The sub's "safe_read_from_pipe" and read_from_process are: | 
					
						
							| 
									
										
										
										
											2013-11-29 15:58:22 -05:00
										 |  |  | # Copyright (c) 2000-2004 CollabNet.  All rights reserved. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # This software is licensed as described in the file COPYING, which | 
					
						
							|  |  |  | # you should have received as part of this distribution.  The terms | 
					
						
							|  |  |  | # are also available at http://subversion.tigris.org/license-1.html. | 
					
						
							|  |  |  | # If newer versions of this license are posted there, you may use a | 
					
						
							|  |  |  | # newer version instead, at your option. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # This software consists of voluntary contributions made by many | 
					
						
							|  |  |  | # individuals.  For exact contribution history, see the revision | 
					
						
							|  |  |  | # history and logs, available at http://subversion.tigris.org/. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #  Note: bkuhn downloaded the license from | 
					
						
							|  |  |  | #  http://subversion.tigris.org/license-1.html on 2013-12-29 which said: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # The license of Subversion 1.7 and later is at | 
					
						
							|  |  |  | # http://svn.apache.org/repos/asf/subversion/trunk/LICENSE. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # The license of Subversion 1.6 and earlier can be found at | 
					
						
							|  |  |  | # http://svn.apache.org/repos/asf/subversion/tags/1.6.0/www/license-1.html. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Both license texts are now included, in APACHE-LICENSE and OLD-SVN-LICENSE, | 
					
						
							|  |  |  | # respectively. | 
					
						
							|  |  |  | # ==================================================================== | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  | # Copyright © 2013 Bradley M. Kuhn <bkuhn@ebb.org> | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # This software's license gives you freedom; you can copy, convey, | 
					
						
							|  |  |  | # propogate, redistribute and/or modify this program under the terms of | 
					
						
							|  |  |  | # the GNU  General Public License (GPL) as published by the Free | 
					
						
							|  |  |  | # Software Foundation (FSF), either version 3 of the License, or (at your | 
					
						
							|  |  |  | # option) any later version of the GPL published by the FSF. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # This program is distributed 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.  See the GNU | 
					
						
							|  |  |  | # General Public License for more details. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | # along with this program in a file in the toplevel directory called | 
					
						
							|  |  |  | # "GPLv3".  If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-30 14:07:37 -05:00
										 |  |  | # ==================================================================== | 
					
						
							| 
									
										
										
										
											2013-11-29 13:46:22 -05:00
										 |  |  | # The functions DoLog, BinarySearchForTZEntry, PrivatizeMergeAndTZIcalFile, | 
					
						
							| 
									
										
										
										
											2013-11-29 16:17:28 -05:00
										 |  |  | # BuildTZList, MergeLists, PrivacyFilterICalFiles, and FilterEmacsToICal material | 
					
						
							| 
									
										
										
										
											2013-11-29 13:42:38 -05:00
										 |  |  | # copyrighted and licensed as below: | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Copyright © 2006 Software Freedom Law Center, Inc. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # This software gives you freedom; it is licensed to you under version 3 | 
					
						
							|  |  |  | # of the GNU General Public License. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # This software is distributed WITHOUT ANY WARRANTY, without even the | 
					
						
							|  |  |  | # implied warranties of MERCHANTABILITY and FITNESS FOR A PARTICULAR | 
					
						
							|  |  |  | # PURPOSE.  See the GNU General Public License for further details. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # You should have received a copy of the GNU General Public License, | 
					
						
							|  |  |  | # version 3.  If not, see <http://www.gnu.org/licenses/> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-29 16:27:00 -05:00
										 |  |  | use strict; | 
					
						
							|  |  |  | use warnings; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  | use POSIX ":sys_wait_h"; | 
					
						
							|  |  |  | use Fcntl;             # for sysopen | 
					
						
							|  |  |  | use Carp; | 
					
						
							|  |  |  | use Data::ICal; | 
					
						
							|  |  |  | use File::Temp qw/:POSIX tempfile/; | 
					
						
							|  |  |  | use DateTime::TimeZone; | 
					
						
							|  |  |  | use Date::Manip; | 
					
						
							|  |  |  | use DateTime::Format::ICal; | 
					
						
							| 
									
										
										
										
											2013-11-29 15:52:07 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | my($CONFIG_FILE) = (@ARGV); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if (@ARGV != 1) { | 
					
						
							|  |  |  |   print STDERR "usage: $0 <CONFIG_FILE>\n"; | 
					
						
							|  |  |  |   exit 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ############################################################################### | 
					
						
							|  |  |  | my $CALENDAR_LOCK_FILE = "$ENV{HOME}/.emacs-calendar-to-ics-lock"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | my $LOCK_CLEANUP_CODE = sub { | 
					
						
							|  |  |  |   return (unlink($CALENDAR_LOCK_FILE) != 1) ? | 
					
						
							|  |  |  |     "Failed unlink of $CALENDAR_LOCK_FILE.  Could cause trouble." : | 
					
						
							|  |  |  |     ""; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  | ############################################################################### | 
					
						
							| 
									
										
										
										
											2013-11-29 13:46:22 -05:00
										 |  |  | { | 
					
						
							|  |  |  |   my %messageHistory; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   sub DoLog ($$$;$) { | 
					
						
							|  |  |  |     my($type, $user, $message, $cleanupCode) = @_; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     use Date::Manip; | 
					
						
							|  |  |  |     my $NOW = ParseDate("now"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     my $lastTime = $messageHistory{$message}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     my $sendIt = 0; | 
					
						
							|  |  |  |     if (not defined $lastTime) { | 
					
						
							|  |  |  |       $sendIt = 1; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       my $err; | 
					
						
							|  |  |  |       my $sinceLast = DateCalc($lastTime,"+ 10 minutes",\$err); | 
					
						
							|  |  |  |       $sendIt = 1 if ($NOW gt $sinceLast); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if ($sendIt) { | 
					
						
							|  |  |  |       my  $fh = File::Temp->new(); | 
					
						
							|  |  |  |       $fh->unlink_on_destroy( 1 ); | 
					
						
							|  |  |  |       my  $fname = $fh->filename; | 
					
						
							|  |  |  |       print $fh "Calendar Export Failure: $message\n"; | 
					
						
							|  |  |  |       $fh->close(); | 
					
						
							|  |  |  |       system('/home/bkuhn/bin/myosd', $fname); | 
					
						
							| 
									
										
										
										
											2013-11-29 16:25:47 -05:00
										 |  |  |       unless (-f "$ENV{HOME}/.silent-running") { | 
					
						
							|  |  |  |         open(ESPEAK, "-|", "/usr/bin/espeak",  '-p', '45', '-s', '130', '-f', $fname, "--stdout"); | 
					
						
							|  |  |  |         open(PAPLAY, "|-", "/usr/bin/paplay"); | 
					
						
							|  |  |  |         my $data; | 
					
						
							|  |  |  |         while (read(ESPEAK, $data, 8) == 8) { | 
					
						
							|  |  |  |           print PAPLAY  $data; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         close PAPLAY; close ESPEAK; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2013-11-29 13:46:22 -05:00
										 |  |  |       system('/usr/bin/notify-send', '-u', 'critical', '-t', '300000', | 
					
						
							|  |  |  |              'Failure', "Calendar export failure: $message"); | 
					
						
							|  |  |  |       $messageHistory{$message} = $NOW; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     my $more; | 
					
						
							|  |  |  |     $more = &$cleanupCode if defined $cleanupCode and ref $cleanupCode; | 
					
						
							|  |  |  |     $message .= "  $more" if (defined $more and $more !~ /^\s*$/); | 
					
						
							|  |  |  |     croak $message if $type eq "die"; | 
					
						
							|  |  |  |     warn $message; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   sub DieLog ($;$) { | 
					
						
							|  |  |  |     DoLog("die", undef, $_[0], $_[1]); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   sub WarnLog ($$) { | 
					
						
							|  |  |  |     DoLog("warn", $_[0], $_[1]); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ############################################################################### | 
					
						
							| 
									
										
										
										
											2013-11-29 15:58:22 -05:00
										 |  |  | # Start a child process safely without using /bin/sh. | 
					
						
							|  |  |  | sub safe_read_from_pipe | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   unless (@_) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       DieLog("$0: safe_read_from_pipe passed no arguments."); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   my $pid = open(SAFE_READ, '-|'); | 
					
						
							|  |  |  |   unless (defined $pid) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       DieLog("$0: cannot fork: $!"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   unless ($pid) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       open(STDERR, ">&STDOUT") | 
					
						
							|  |  |  |         or DieLog("$0: cannot dup STDOUT: $!"); | 
					
						
							|  |  |  |       exec(@_) | 
					
						
							|  |  |  |         or DieLog("$0: cannot exec `@_': $!\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   my @output; | 
					
						
							|  |  |  |   while (<SAFE_READ>) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       s/[\r\n]+$//; | 
					
						
							|  |  |  |       push(@output, $_); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   close(SAFE_READ); | 
					
						
							|  |  |  |   my $result = $?; | 
					
						
							|  |  |  |   my $exit   = $result >> 8; | 
					
						
							|  |  |  |   my $signal = $result & 127; | 
					
						
							|  |  |  |   my $cd     = $result & 128 ? "with core dump" : ""; | 
					
						
							|  |  |  |   if ($signal or $cd) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       DieLog("$0: pipe from `@_' failed $cd: exit=$exit signal=$signal\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   if (wantarray) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       return ($result, @output); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       return $result; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ############################################################################### | 
					
						
							|  |  |  | # Use safe_read_from_pipe to start a child process safely and return | 
					
						
							|  |  |  | # the output if it succeeded or an error message followed by the output | 
					
						
							|  |  |  | # if it failed. | 
					
						
							|  |  |  | sub read_from_process | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   unless (@_) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       DieLog("$0: read_from_process passed no arguments."); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   my ($status, @output) = &safe_read_from_pipe(@_); | 
					
						
							|  |  |  |   if ($status) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       return ("$0: `@_' failed with this output:", @output); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       return @output; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ############################################################################### | 
					
						
							| 
									
										
										
										
											2013-11-29 13:42:38 -05:00
										 |  |  | sub BinarySearchForTZEntry { | 
					
						
							|  |  |  | # $tzList is assumed to be sorted, $dateTime is  | 
					
						
							|  |  |  |   my($tzList, $dateTime) = @_; | 
					
						
							|  |  |  |   my ($l, $u) = (0, @$tzList - 1);  # lower, upper end of search interval | 
					
						
							|  |  |  |   my $i;                       # index of probe | 
					
						
							|  |  |  |   my $final = 0; | 
					
						
							|  |  |  |   while ($l <= $u) { | 
					
						
							|  |  |  |     $i = int(($l + $u)/2); | 
					
						
							|  |  |  |     my $compareVal = DateTime->compare($tzList->[$i]{date}, $dateTime); | 
					
						
							|  |  |  |     if ($compareVal < 0) { | 
					
						
							|  |  |  |       $l = $i+1; | 
					
						
							|  |  |  |       $final = $i; | 
					
						
							|  |  |  |     } elsif ($compareVal > 0) { | 
					
						
							|  |  |  |       $u = $i-1; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return $tzList->[$i]; # found, won't happen often | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return  $tzList->[$final];         # not found, go down one lower | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ############################################################################### | 
					
						
							| 
									
										
										
										
											2013-11-29 16:17:28 -05:00
										 |  |  | # Take a list of keys and a list of values and insersperse them and | 
					
						
							|  |  |  | # return the result | 
					
						
							|  |  |  | sub MergeLists { | 
					
						
							|  |  |  |     my ($keys, $values) = @_; | 
					
						
							|  |  |  |     DieLog("Length mismatch", $LOCK_CLEANUP_CODE) unless @$keys == @$values; | 
					
						
							|  |  |  |     # Add the argument names to the values | 
					
						
							|  |  |  |     my @result; | 
					
						
							|  |  |  |     for (my $i = 0; $i < @$keys; $i++) { | 
					
						
							|  |  |  | 	push @result, $keys->[$i] => $values->[$i]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return @result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ############################################################################### | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  | sub BuildTZList ($$$) { | 
					
						
							|  |  |  |   my($user, $pubEmacsFile, $privEmacsFile) = @_; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   my @tzList; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   foreach my $file ($pubEmacsFile, $privEmacsFile) { | 
					
						
							|  |  |  |     open(DATA, "<$file") or DieLog("unable to read $file: $!", | 
					
						
							|  |  |  |                                    $LOCK_CLEANUP_CODE); | 
					
						
							|  |  |  |     while (my $line = <DATA>) { | 
					
						
							|  |  |  |       if ($line =~ /^\s*;[;\s]*TZ\s*=([^\s,]+)\s*(?:,+\s*LOCA?T?I?O?N?\s*=\"([^"]+)\")? | 
					
						
							|  |  |  |                     \s+(?:at|on)\s*(.*)\s+in\s+(\S+)\s*$/ix) { | 
					
						
							|  |  |  |         my($newTZstr, $location, $dateStartStr, $dateStartTZstr) = ($1, $2, $3, $4); | 
					
						
							|  |  |  |         my $newTZ; | 
					
						
							|  |  |  |         eval { $newTZ = DateTime::TimeZone->new( name => $newTZstr ); }; | 
					
						
							|  |  |  |         if ($@ or not defined $newTZ) { | 
					
						
							|  |  |  |           WarnLog($user, | 
					
						
							|  |  |  |                   "Invalid time zone of \"$newTZstr\" in $line from $file: $@"); | 
					
						
							|  |  |  |           next; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         my $dateStartTZ; | 
					
						
							|  |  |  |         eval { | 
					
						
							|  |  |  |           $dateStartTZ = DateTime::TimeZone->new( name => $dateStartTZstr ); }; | 
					
						
							|  |  |  |         if ($@ or not defined $dateStartTZ) { | 
					
						
							|  |  |  |           WarnLog($user, | 
					
						
							|  |  |  |            "Invalid time zone of \"$dateStartTZstr\" in $line from $file: $@"); | 
					
						
							|  |  |  |           next; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         my(@data) = UnixDate("$dateStartStr", qw(%Y %m %d %H %M %S)); | 
					
						
							|  |  |  |         if (@data != 6) { | 
					
						
							|  |  |  |           WarnLog($user, "Unparseable date string of \"$dateStartStr\"" . | 
					
						
							|  |  |  |                    "in $line from $file"); | 
					
						
							|  |  |  |           next; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         my @args = MergeLists([qw( year month day hour minute second)], \@data); | 
					
						
							|  |  |  |         my $startDate; | 
					
						
							|  |  |  |         eval { | 
					
						
							|  |  |  |           $startDate = DateTime->new(@args, time_zone => $dateStartTZstr); | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |         if ($@ or not defined $startDate) { | 
					
						
							|  |  |  |           WarnLog($user, "Trouble parsing \"$dateStartStr $dateStartTZstr\" " . | 
					
						
							|  |  |  |                   "in $line from $file\n\n" . | 
					
						
							|  |  |  |                   "Most likely $dateStartTZstr was a bad time zone.: $@ "); | 
					
						
							|  |  |  |           next; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         push(@tzList, { date => $startDate, newTZ => $newTZ, location => $location}); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   # If we found nothing, everything is NYC | 
					
						
							|  |  |  |   if (@tzList == 0) { | 
					
						
							|  |  |  |     push(@tzList, { date => DateTime->new(year => 2006,  month => 11, day => 03, | 
					
						
							|  |  |  |                                           hour =>  11, minute => 00,  second => 00, | 
					
						
							|  |  |  |                                           time_zone => "America/New_York"), | 
					
						
							|  |  |  |                     newTZ => "America/New_York", location => undef }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return sort { DateTime->compare($a->{date}, $b->{date}); } @tzList; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ############################################################################### | 
					
						
							|  |  |  | sub FilterEmacsToICal ($$$$$) { | 
					
						
							| 
									
										
										
										
											2013-11-29 15:52:35 -05:00
										 |  |  |   my ($publicCalendarFile, $privateCalendarFile, $outputDir, | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  |       $emacsSettings, $user) = @_; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   my @tzList = BuildTZList($emacsSettings->{reportProblems}, | 
					
						
							|  |  |  |                            $publicCalendarFile, $privateCalendarFile); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   my($elispFH, $elispFile) = tempfile(); | 
					
						
							|  |  |  |   my $icsWillBePrivatizedFile = tmpnam(); | 
					
						
							|  |  |  |   my $icsPublicFile = tmpnam(); | 
					
						
							|  |  |  |   print $elispFH "(setq-default european-calendar-style t)\n" | 
					
						
							|  |  |  |     if $emacsSettings->{calendarStyle} =~  /european/i; | 
					
						
							|  |  |  |   print $elispFH <<ELISP_END | 
					
						
							|  |  |  | (setq icalendar-uid-format "emacs-%u-%h-%s") | 
					
						
							|  |  |  | ELISP_END | 
					
						
							|  |  |  | ; | 
					
						
							| 
									
										
										
										
											2013-11-29 15:52:35 -05:00
										 |  |  |   print $elispFH "(icalendar-export-file \"$privateCalendarFile\" \"$icsWillBePrivatizedFile\")\n" | 
					
						
							|  |  |  |     if defined $privateCalendarFile; | 
					
						
							|  |  |  |   print $elispFH "(icalendar-export-file \"$publicCalendarFile\" \"$icsPublicFile\")\n" | 
					
						
							|  |  |  |     if defined $publicCalendarFile; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  |   $elispFH->close(); | 
					
						
							| 
									
										
										
										
											2013-11-29 16:16:47 -05:00
										 |  |  |   my @emacsOutput = read_from_process($emacsSettings->{emacsBinary}, '--no-windows', | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  |                  '--batch', '--no-site-file', '-l', $elispFile); | 
					
						
							|  |  |  |   DieLog("Emacs process for exporting $privateCalendarFile and " . | 
					
						
							|  |  |  |          "$publicCalendarFile exited with non-zero exit status of " . | 
					
						
							|  |  |  |          "$? ($!), and output of:\n    " . join("\n   ", @emacsOutput), | 
					
						
							|  |  |  |          $LOCK_CLEANUP_CODE) | 
					
						
							|  |  |  |     if ($? != 0); | 
					
						
							|  |  |  |   my $goodCount =0; | 
					
						
							|  |  |  |   foreach my $line (@emacsOutput) { | 
					
						
							|  |  |  |     $goodCount++  | 
					
						
							|  |  |  |       if $line =~ /^\s*Wrote\s+($icsPublicFile|$icsWillBePrivatizedFile)\s*$/; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   DieLog("Unexpected Emacs output: " . join("\n   ", @emacsOutput), | 
					
						
							|  |  |  |          $LOCK_CLEANUP_CODE) | 
					
						
							| 
									
										
										
										
											2013-11-29 15:52:35 -05:00
										 |  |  |     if ($goodCount > 2); | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |   PrivatizeMergeAndTZIcalFile($icsWillBePrivatizedFile, $icsPublicFile, | 
					
						
							| 
									
										
										
										
											2013-11-29 15:52:35 -05:00
										 |  |  |                             $outputDir, \@tzList, $user); | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-29 16:26:01 -05:00
										 |  |  |   PrivacyFilterICalFile($outputDir) if $emacsSettings->{privacyScrub}; | 
					
						
							| 
									
										
										
										
											2014-01-24 09:34:38 -05:00
										 |  |  |   DieLog("Unable to remove temporary files", $LOCK_CLEANUP_CODE) | 
					
						
							| 
									
										
										
										
											2013-11-29 16:26:01 -05:00
										 |  |  |     unless unlink($icsPublicFile, $icsWillBePrivatizedFile) == 2; | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-11-29 13:18:39 -05:00
										 |  |  | ############################################################################### | 
					
						
							| 
									
										
										
										
											2013-11-29 13:41:52 -05:00
										 |  |  | sub PrivacyFilterICalFiles ($$) { | 
					
						
							|  |  |  |   my($icsDirectory) = @_; | 
					
						
							| 
									
										
										
										
											2013-11-29 13:18:39 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-29 13:41:52 -05:00
										 |  |  |   chdir $icsDirectory or die "unable to change to $icsDirectory: $!"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   foreach my $file (<*.ics>) { | 
					
						
							|  |  |  |     my $newCalendar = Data::ICal->new(data => <<END_ICAL | 
					
						
							| 
									
										
										
										
											2013-11-29 13:18:39 -05:00
										 |  |  | BEGIN:VCALENDAR | 
					
						
							|  |  |  | VERSION:2.0 | 
					
						
							| 
									
										
										
										
											2013-11-29 13:41:52 -05:00
										 |  |  | PRODID:-//Emacs//NONSGML icalendar.el//EN | 
					
						
							| 
									
										
										
										
											2013-11-29 13:18:39 -05:00
										 |  |  | END:VCALENDAR | 
					
						
							|  |  |  | END_ICAL | 
					
						
							|  |  |  | ); | 
					
						
							| 
									
										
										
										
											2013-11-29 13:41:52 -05:00
										 |  |  |     my $oldCalendar = Data::ICal->new(filename => $file); | 
					
						
							|  |  |  |     my $entries = (defined $oldCalendar) ? $oldCalendar->entries : []; | 
					
						
							|  |  |  |     my $x =0; | 
					
						
							|  |  |  |     foreach my $entry (@{$entries}) { | 
					
						
							|  |  |  |       my @newSubEntries; | 
					
						
							|  |  |  |       foreach my $subEntry (@{$entry->{entries}}) { | 
					
						
							|  |  |  |         my $refVal = ref $subEntry; | 
					
						
							|  |  |  |         if (defined $refVal and $refVal =~ /Alarm/i) { | 
					
						
							|  |  |  |           # Don't put it in the list in the public version if is an alarm | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           push(@newSubEntries, $subEntry); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-11-29 13:18:39 -05:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2013-11-29 13:41:52 -05:00
										 |  |  |       $entry->{entries} = \@newSubEntries; | 
					
						
							| 
									
										
										
										
											2013-11-29 15:52:35 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-29 13:41:52 -05:00
										 |  |  |       my $classes = $entry->property('class'); | 
					
						
							|  |  |  |       my $class; | 
					
						
							|  |  |  |       foreach my $classProp (@{$classes}) { | 
					
						
							|  |  |  |         $class = $classProp->value; | 
					
						
							|  |  |  |         last if defined $class and | 
					
						
							|  |  |  |           $class =~ /^\s*(?:PUBLIC|PRIVATE|CONFIDENTIAL)\s*/i; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (defined $class and $class  =~ /CONFIDENTIAL/i) { | 
					
						
							|  |  |  |         foreach my $prop (qw/location summary description/) { | 
					
						
							|  |  |  |           my $propList = $entry->property($prop); | 
					
						
							|  |  |  |           $entry->add_property($prop => "Private") | 
					
						
							|  |  |  |             if (defined $propList and @{$propList} > 0); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } elsif (defined $class and $class =~ /PRIVATE/i){ | 
					
						
							|  |  |  |         # do not put this event in the output at all | 
					
						
							|  |  |  |         die "unable to scrub $file in $icsDirectory: $!" | 
					
						
							|  |  |  |           unless unlink($file) == 1; | 
					
						
							| 
									
										
										
										
											2013-11-29 13:18:39 -05:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2013-11-29 13:41:52 -05:00
										 |  |  |       $newCalendar->add_entry($entry); | 
					
						
							| 
									
										
										
										
											2013-11-29 13:18:39 -05:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-11-29 16:27:00 -05:00
										 |  |  |     open(SCRUBBED_CAL, ">$file") or | 
					
						
							|  |  |  |       DieLog("Unable to overwrite $file: $!", $LOCK_CLEANUP_CODE); | 
					
						
							|  |  |  |     print SCRUBBED_CAL $newCalendar->as_string; | 
					
						
							|  |  |  |     close SCRUBBED_CAL; | 
					
						
							|  |  |  |     DieLog("Error when writing $file: $!", $LOCK_CLEANUP_CODE) | 
					
						
							|  |  |  |       unless $? == 0; | 
					
						
							|  |  |  |     undef $newCalendar; | 
					
						
							| 
									
										
										
										
											2013-11-29 13:18:39 -05:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  | ###################################################################### | 
					
						
							|  |  |  | sub PrivatizeMergeAndTZIcalFile ($$$$$$) { | 
					
						
							| 
									
										
										
										
											2013-11-29 13:41:52 -05:00
										 |  |  |   my($icsPrivate, $icsPublic, $icsOutputDir, $tzList, $user, $errorUser) = @_; | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |   my %calendar; | 
					
						
							|  |  |  |   $calendar{private} = Data::ICal->new(filename => $icsPrivate); | 
					
						
							|  |  |  |   $calendar{public} = Data::ICal->new(filename => $icsPublic); | 
					
						
							| 
									
										
										
										
											2013-11-29 13:41:52 -05:00
										 |  |  |   my $type = "public"; | 
					
						
							|  |  |  |   foreach my $type (qw/public private/) { | 
					
						
							|  |  |  |     my $entries = (defined $calendar{$type}) ? $calendar{$type}->entries : []; | 
					
						
							|  |  |  |     foreach my $entry (@{$entries}) { | 
					
						
							|  |  |  |       my $newCalendar = Data::ICal->new(data => <<END_ICAL | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  | BEGIN:VCALENDAR | 
					
						
							|  |  |  | VERSION:2.0 | 
					
						
							|  |  |  | PRODID:-//Emacs//NONSGML icalendar.el//EN | 
					
						
							|  |  |  | END:VCALENDAR | 
					
						
							|  |  |  | END_ICAL | 
					
						
							| 
									
										
										
										
											2013-11-29 13:41:52 -05:00
										 |  |  |       ); | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  |       $entry->add_property(class => "CONFIDENTIAL") if ($type eq "private"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # Let's shift some timezones around. | 
					
						
							|  |  |  |       foreach my $dateType (qw/DTSTART DTEND/) { | 
					
						
							|  |  |  |         my $datePropList = $entry->property($dateType); | 
					
						
							|  |  |  |         next unless @$datePropList > 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-29 13:41:52 -05:00
										 |  |  |         WarnLog($errorUser, "Strange that the entry below for $icsOutputDir had more " . | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  |                       "than one $dateType:\n" . Data::Dumper->Dumper($entry) ) | 
					
						
							|  |  |  |           unless @$datePropList == 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         my $dateProp = $datePropList->[0]; | 
					
						
							|  |  |  |         # Only continue processing date if we have this property.  (Duh) | 
					
						
							|  |  |  |         next unless defined $dateProp; | 
					
						
							|  |  |  |         my $params = $dateProp->parameters(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Only continue if it is a DATE-TIME property.  This is a bit of a | 
					
						
							|  |  |  |         # judgement call but I think it's the right one.  When someone | 
					
						
							|  |  |  |         # creates an all-day event, we don't want to allow it to drift to | 
					
						
							|  |  |  |         # antoher day merely because the user has moved time zones. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         next unless defined $params and defined $params->{VALUE} | 
					
						
							|  |  |  |                                     and $params->{VALUE} =~ /DATE\-TIME/i; | 
					
						
							|  |  |  |         my $nyTime = DateTime::Format::ICal->parse_datetime($dateProp->value); | 
					
						
							|  |  |  |         my $newDate = DateTime::Format::ICal->parse_datetime($dateProp->value); | 
					
						
							|  |  |  |         $nyTime->set_time_zone("America/New_York") | 
					
						
							|  |  |  |           if $nyTime->time_zone->name =~ /floating/; | 
					
						
							|  |  |  |         my $val = BinarySearchForTZEntry($tzList, $nyTime); | 
					
						
							|  |  |  |         $newDate->set_time_zone($val->{newTZ}); | 
					
						
							|  |  |  |         $newDate->set_time_zone("America/New_York"); | 
					
						
							|  |  |  |         $newDate->set_time_zone("floating"); | 
					
						
							|  |  |  |         my $newICalDate = DateTime::Format::ICal->format_datetime($newDate); | 
					
						
							|  |  |  |         $dateProp->value($newICalDate); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       $newCalendar->add_entry($entry); | 
					
						
							| 
									
										
										
										
											2013-11-29 13:41:52 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |       # Now, write out each event into a single ics file in $icsOutputDir. | 
					
						
							|  |  |  |       # This will overwrite existing events of the same name. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       my $uidList = $entry->property('UID'); | 
					
						
							| 
									
										
										
										
											2014-01-24 09:34:38 -05:00
										 |  |  |       DieLog("This entry has multiple UIDs: @{$uidList}", $LOCK_CLEANUP_CODE) | 
					
						
							|  |  |  |         unless @$uidList == 1; | 
					
						
							| 
									
										
										
										
											2013-11-29 16:31:45 -05:00
										 |  |  |       my $uid = $uidList->[0]->value; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-29 13:41:52 -05:00
										 |  |  |       my $outputFile = File::Spec->catpath("", $icsOutputDir, "${uid}.ics"); | 
					
						
							|  |  |  |       open(SINGLE_EVENT_ICAL, ">", $outputFile) or | 
					
						
							|  |  |  |         DieLog("Unable to overwrite $outputFile: $!", $LOCK_CLEANUP_CODE); | 
					
						
							|  |  |  |       print SINGLE_EVENT_ICAL $newCalendar->as_string; | 
					
						
							|  |  |  |       close SINGLE_EVENT_ICAL; | 
					
						
							|  |  |  |       DieLog("Error ($?) while writing $outputFile ($?): $!", $LOCK_CLEANUP_CODE) unless $? == 0; | 
					
						
							|  |  |  |       undef $newCalendar; | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-11-29 13:41:52 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |   # Create specialized "Time Zone change" events to indicate the user's travel. | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  |   foreach my $tzEntry (@$tzList) { $tzEntry->{date}->set_time_zone("floating"); } | 
					
						
							|  |  |  |   for (my $ii = 0; $ii < @$tzList; $ii++) { | 
					
						
							|  |  |  |     my $tzEntry = $tzList->[$ii]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     next unless defined $tzEntry->{location} and | 
					
						
							|  |  |  |                 $tzEntry->{location} !~ /^\s*NYC\s*$/i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     my $startDate = DateTime::Format::ICal->format_datetime($tzEntry->{date}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     my $nextDate = ($ii+1 < @$tzList) ? | 
					
						
							|  |  |  |       DateTime::Format::ICal->format_datetime($tzList->[$ii+1]{date}) : $startDate; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     $nextDate =~ s/T\d+Z?$//; $startDate =~ s/T\d+Z?$//; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     my $whereEvent = Data::ICal::Entry::Event->new(); | 
					
						
							|  |  |  |     my $desc = "$user Travel: ". $tzEntry->{location}; | 
					
						
							|  |  |  |     my $uid = "bkuhnScript" . '-' . sha1($desc . $startDate); | 
					
						
							|  |  |  |     $whereEvent->add_properties(summary     => "$user Travel: ". $tzEntry->{location}, | 
					
						
							|  |  |  |                                 description => $tzEntry->{location}, | 
					
						
							|  |  |  |                                 dtstart     => [ $startDate, { VALUE => 'DATE' } ], | 
					
						
							|  |  |  |                                 dtend       => [ $nextDate,{ VALUE => 'DATE' } ], | 
					
						
							| 
									
										
										
										
											2013-11-29 13:41:52 -05:00
										 |  |  |                                 uid         => $uid); | 
					
						
							|  |  |  |       my $newCalendar = Data::ICal->new(data => <<END_ICAL | 
					
						
							|  |  |  | BEGIN:VCALENDAR | 
					
						
							|  |  |  | VERSION:2.0 | 
					
						
							|  |  |  | PRODID:-//Emacs//NONSGML icalendar.el//EN | 
					
						
							|  |  |  | END:VCALENDAR | 
					
						
							|  |  |  | END_ICAL | 
					
						
							|  |  |  |       ); | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  |     $newCalendar->add_entry($whereEvent); | 
					
						
							| 
									
										
										
										
											2013-11-29 13:41:52 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     my $outputFile = File::Spec->catpath("", $icsOutputDir, "${uid}.ics"); | 
					
						
							|  |  |  |     open(SINGLE_EVENT_ICAL, ">", $outputFile) or | 
					
						
							|  |  |  |       DieLog("Unable to overwrite $outputFile: $!", $LOCK_CLEANUP_CODE); | 
					
						
							|  |  |  |     print SINGLE_EVENT_ICAL $newCalendar->as_string; | 
					
						
							|  |  |  |     close SINGLE_EVENT_ICAL; | 
					
						
							|  |  |  |     DieLog("Error ($?) while writing $outputFile ($?): $!", $LOCK_CLEANUP_CODE) unless $? == 0; | 
					
						
							|  |  |  |     undef $newCalendar; | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-11-29 13:41:52 -05:00
										 |  |  |   return \%calendar; | 
					
						
							| 
									
										
										
										
											2013-11-29 13:12:24 -05:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-11-29 15:52:35 -05:00
										 |  |  | ###################################################################### | 
					
						
							|  |  |  | sub ReadConfig($) { | 
					
						
							|  |  |  |   my($configFile) = @_; | 
					
						
							|  |  |  |   open (CONFIG_FILE, "<", $configFile) or DieLog("unable to read $configFile ($?): $!"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   my %config; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   while (my $line = <CONFIG_FILE>) { | 
					
						
							| 
									
										
										
										
											2013-11-29 16:16:56 -05:00
										 |  |  |     chomp $line; | 
					
						
							| 
									
										
										
										
											2014-01-24 09:34:38 -05:00
										 |  |  |     DieLog("Unable to parse $line in config file, $configFile", | 
					
						
							|  |  |  |            $LOCK_CLEANUP_CODE) | 
					
						
							| 
									
										
										
										
											2013-11-29 15:52:35 -05:00
										 |  |  |       unless $line =~ /^\s*([^:]+)\s*:\s*([^:]+)\s*$/; | 
					
						
							|  |  |  |     $config{$1} = $2; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-01-24 09:34:38 -05:00
										 |  |  |   close CONFIG_FILE;  DieLog("Error reading $configFile ($?): $!", | 
					
						
							|  |  |  |                              $LOCK_CLEANUP_CODE) if $? != 0; | 
					
						
							| 
									
										
										
										
											2013-11-29 15:52:35 -05:00
										 |  |  |   return \%config; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ###################################################################### | 
					
						
							| 
									
										
										
										
											2013-11-30 13:36:52 -05:00
										 |  |  | system("/usr/bin/lockfile -r 8 $CALENDAR_LOCK_FILE"); | 
					
						
							| 
									
										
										
										
											2014-01-24 09:34:38 -05:00
										 |  |  | unless ($? == 0) { | 
					
						
							|  |  |  |   print "\${color5}Calendar export failure: Cannot aquire lock on $CALENDAR_LOCK_FILE\n"; | 
					
						
							| 
									
										
										
										
											2014-02-26 07:54:43 -05:00
										 |  |  |   exit 1; | 
					
						
							| 
									
										
										
										
											2014-01-24 09:34:38 -05:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-01-24 07:02:22 -05:00
										 |  |  | if (not -r $CONFIG_FILE) { | 
					
						
							|  |  |  |   print "\${color5}$CONFIG_FILE does not exist\n"; | 
					
						
							| 
									
										
										
										
											2014-02-19 18:21:06 -05:00
										 |  |  |   exit 1; | 
					
						
							| 
									
										
										
										
											2014-01-24 07:02:22 -05:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-11-29 15:52:35 -05:00
										 |  |  | my $config = ReadConfig($CONFIG_FILE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | $config->{scrubPrivate} = 0 if not defined $config->{scrubPrivate}; | 
					
						
							|  |  |  | $config->{reportProblems} = $config->{user} if not defined $config->{reportProblems}; | 
					
						
							| 
									
										
										
										
											2013-11-29 16:16:47 -05:00
										 |  |  | $config->{emacsBinary} = "/usr/bin/emacs" if not defined $config->{emacsBinary}; | 
					
						
							| 
									
										
										
										
											2013-11-29 16:26:17 -05:00
										 |  |  | $config->{calendarStyle} = 'plain' if not defined $config->{calendarStyle}; | 
					
						
							| 
									
										
										
										
											2013-11-30 14:45:43 -05:00
										 |  |  | DieLog("$config->{emacsBinary} doesn't appear to be executable for $config->{emacsBinary}") | 
					
						
							| 
									
										
										
										
											2013-11-30 14:20:07 -05:00
										 |  |  |     unless defined $config->{emacsBinary} and -x $config->{emacsBinary}; | 
					
						
							| 
									
										
										
										
											2013-11-29 16:16:47 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-10 08:53:02 -05:00
										 |  |  | DieLog("$CONFIG_FILE doesn't specify a (readable) output directory via outputDir setting: $!") | 
					
						
							|  |  |  |   unless defined $config->{outputDir} and -d $config->{outputDir}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-29 17:15:23 -05:00
										 |  |  | if (defined $config->{cleanOutputDirFirst} and $config->{cleanOutputDirFirst}) { | 
					
						
							|  |  |  |   chdir $config->{outputDir} or die "unable to change directory to $config->{outputDir} $? $!"; | 
					
						
							| 
									
										
										
										
											2013-11-30 13:36:52 -05:00
										 |  |  |   system("/bin/rm -f *.ics"); | 
					
						
							| 
									
										
										
										
											2013-11-29 17:15:23 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-19 18:22:48 -05:00
										 |  |  | foreach my $key (qw/publicDiary privateDiary/) { | 
					
						
							|  |  |  |   unless (defined $config->{$key} and -r $config->{$key}) { | 
					
						
							|  |  |  |     print "\${color5}$key file, $config->{$key} does not exist\n"; | 
					
						
							|  |  |  |     exit 1; | 
					
						
							| 
									
										
										
										
											2014-01-24 14:53:40 -05:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-11-29 15:52:35 -05:00
										 |  |  | FilterEmacsToICal($config->{publicDiary}, $config->{privateDiary}, | 
					
						
							|  |  |  |                   $config->{outputDir}, $config, $config->{user}); | 
					
						
							| 
									
										
										
										
											2013-11-29 13:41:52 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-30 13:36:52 -05:00
										 |  |  | &$LOCK_CLEANUP_CODE(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-29 15:52:35 -05:00
										 |  |  | __END__ | 
					
						
							|  |  |  | # Local variables: | 
					
						
							|  |  |  | # compile-command: "perl -c calendar-export.plx" | 
					
						
							|  |  |  | # End: |