diff --git a/contrib/ical2rem-0.7/GITHUB b/contrib/ical2rem-0.7/GITHUB new file mode 100644 index 00000000..7e9dafae --- /dev/null +++ b/contrib/ical2rem-0.7/GITHUB @@ -0,0 +1,3 @@ +The upstream GitHub project for ical2rem is: + +https://github.com/jbalcorn/ical2rem diff --git a/contrib/ical2rem-0.7/LICENSE b/contrib/ical2rem-0.7/LICENSE new file mode 100644 index 00000000..bd884f16 --- /dev/null +++ b/contrib/ical2rem-0.7/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Justin B. Alcorn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/contrib/ical2rem-0.7/README.md b/contrib/ical2rem-0.7/README.md new file mode 100644 index 00000000..f8c8bf5e --- /dev/null +++ b/contrib/ical2rem-0.7/README.md @@ -0,0 +1,103 @@ +# ical2rem +The original iCal to Remind script, first released in 2005. + +Reads iCal files and outputs remind-compatible files. Tested ONLY with + calendar files created by Mozilla Calendar/Sunbird. Use at your own risk. + +## License +In 2005, this was released with the Gnu Public License V2. However, I am changing it to the MIT License, since that provides greater freedom to do with this code what you want. + +Copyright (c) 2005, 2007, 2019 Justin B. Alcorn + +## How I use Remind and Google Calendar together + + - My family has a Google Email domain, and our email addresses all end in the same domain. We all use Google Calendars and I want to mail reminders to each of the family members containing both Google Calendar and .reminder information. + - Under my ~/.rem/ directory each family member has a directory. Each directory contains a standard remind file called 'reminders' that at the very least has the line "INCLUDE /home/jalcorn/.rem//ical2rem" and flag files indicating whether they want Daily or Weekly reminders. My reminders files references my standard .reminders file, and I also have a flag so if I run a Test run I'll get it. There's actually a lot more files (I have a big family). +```` + ./rem + ./son1: + drwxrwxr-x 2 jalcorn jalcorn 4096 Dec 12 14:02 . + drwxr-xr-x 12 jalcorn jalcorn 4096 Dec 12 14:13 .. + -rw-rw-r-- 1 jalcorn jalcorn 51 Mar 3 06:10 ical2rem + lrwxrwxrwx 1 jalcorn jalcorn 33 Oct 27 2016 son1.ics -> /home/jalcorn/calendars/son1.ics + -rw-rw-r-- 1 jalcorn jalcorn 976 Dec 12 14:02 reminders + -rw-rw-r-- 1 jalcorn jalcorn 0 Oct 27 2016 Weekly + + ./justin: + drwxrwxr-x 2 jalcorn jalcorn 4096 Feb 27 08:29 . + drwxr-xr-x 12 jalcorn jalcorn 4096 Dec 12 14:13 .. + lrwxrwxrwx 1 jalcorn jalcorn 32 Oct 27 2016 son1.ics -> /home/jalcorn/calendars/son1.ics + -rw-rw-r-- 1 jalcorn jalcorn 0 Nov 7 2016 Daily + lrwxrwxrwx 1 jalcorn jalcorn 34 Oct 27 2016 family.ics -> /home/jalcorn/calendars/family.ics + -rw-rw-r-- 1 jalcorn jalcorn 37320 Mar 3 06:10 ical2rem + lrwxrwxrwx 1 jalcorn jalcorn 34 Oct 27 2016 justin.ics -> /home/jalcorn/calendars/justin.ics + lrwxrwxrwx 1 jalcorn jalcorn 24 Nov 7 2016 reminders -> /home/jalcorn/.reminders + lrwxrwxrwx 1 jalcorn jalcorn 34 Oct 27 2016 vmd.ics -> /home/jalcorn/calendars/vmd.ics + -rw-rw-r-- 1 jalcorn jalcorn 0 Oct 27 2016 Test + -rw-rw-r-- 1 jalcorn jalcorn 0 Nov 7 2016 Weekly +```` + - bin/getgooglecals.sh runs out of crontab and downloads whatever calendars I want. Note that we can also download organization calendars, I've included a public one here (Cleveland Heights Vocal Music Department calendar). + - dailyreminders.sh is linked to weeklyreminders.sh and testreminders.sh so I can run it in different modes. The concatenate the various calendar outputs as a single remind file then send the reminders via email. +### Example: .rem/son1/reminders file: +```` +INCLUDE /home/jalcorn/.rem/defs.rem +INCLUDE /home/jalcorn/.rem/float +INCLUDE /home/jalcorn/.rem/son1/ical2rem +fset _weeks() coerce("STRING", (trigdate()-today())/7) + plural((trigdate()-today())/7, " week") +FSET _sfun(x) choose(x, -60, 30, 5, 0) +FSET oldfloat(y,m,d) trigger(MAX(realtoday(), date(y,m,d))) +FSET due(y,m,d) "(" + (date(y,m,d)-trigdate()) + ")" +SET fullmoon moondate(2) +REM [trigger(realtoday())] SPECIAL SHADE 145 70 100 % +REM [float(2019,4,15,105)] MSG File tax return [due(2017,4,15)]% +REM PRIORITY 9999 MSG %"%"% +INCLUDE /home/jalcorn/.rem/bdays +SET $LongDeg 81 +SET $LongMin 11 +SET $LongSec 11 +SET $LatDeg 41 +SET $LatMin 11 +SET $LatSec 11 +REM [trigger(moondate(2))] +1 MSG %"Full Moon%" %b% +fset _srtd() coerce("STRING", _no_lz(_am_pm(sunrise(today())))) +fset _sstd() coerce("STRING", _no_lz(_am_pm(sunset(today())))) +MSG Sun is up today from [_srtd()] to [_sstd()].%"%"% +```` +## Revision History +### Version 0.7 2024-09-04 + - ISSUE 8: New version of remind complains if _sfun isn't defined. Output a header + to define a function that does nothing if the function doesn't exist. +### Version 0.6 2019-03-01 + - Publish on GitHub and change license to MIT License + - Add supporting files and explanation of how I use it +### version 0.5.2 2007-03-23 + - BUG: leadtime for recurring events had a max of 4 instead of DEFAULT_LEAD_TIME + - remove project-lead-time, since Category was a non-standard attribute + - NOTE: There is a bug in iCal::Parser v1.14 that causes multiple calendars to + fail if a calendar with recurring events is followed by a calendar with no + recurring events. This has been reported to the iCal::Parser author. +### version 0.5.1 2007-03-21 + - BUG: Handle multiple calendars on STDIN + - add --heading option for priority on section headers +### version 0.5 2007-03-21 + - Add more help options + - --project-lead-time option + - Supress printing of heading if there are no todos to print +### version 0.4 + - Version 0.4 changes all written or inspired by, and thanks to Mark Stosberg + - Change to GetOptions + - Change to pipe + - Add --label, --help options + - Add Help Text + - Change to subroutines + - Efficiency and Cleanup +### version 0.3 + - Convert to GPL (Thanks to Mark Stosberg) + - Add usage +### version 0.2 + - add command line switches + - add debug code + - add SCHED _sfun keyword + - fix typos +### version 0.1 - ALPHA CODE. + diff --git a/contrib/ical2rem-0.7/cal_futureonly.pl b/contrib/ical2rem-0.7/cal_futureonly.pl new file mode 100644 index 00000000..02815208 --- /dev/null +++ b/contrib/ical2rem-0.7/cal_futureonly.pl @@ -0,0 +1,82 @@ +#!/usr/bin/perl -w +# +# cal_futureonly.pl - +# Reads iCal files and outputs events between 1 month ago and 1 year from now. +# Copyright (c) 2005, 2007, 2019 Justin B. Alcorn + +=head1 SYNOPSIS + + cal_futureonly.pl --file=filname.ics > output.ics + + --help Usage + --man Complete man page + --infile (REQUIRED) name of input calendar file + --file (REQUIRED) name of output calendar file + +Expects an ICAL stream on STDIN. Converts it to the format +used by the C script and prints it to STDOUT. + +=head2 --infile + +Input file + +=head2 --file + +Output File + +=cut + +use strict; +use Data::ICal; +use Data::ICal::Entry; +use DateTime::Span; +use Data::ICal::DateTime; +use DateTime; +use Getopt::Long 2.24 qw':config auto_help'; +use Pod::Usage; +use Data::Dumper; +use vars '$VERSION'; +$VERSION = "0.1"; + +my $help; +my $man; +my $infile; +my $file; +my $debug = 0; + +GetOptions ( + "help|?" => \$help, + "man" => \$man, + "debug" => \$debug, + "infile=s" => \$infile, + "file=s" => \$file +); +pod2usage(1) if $help; +pod2usage(1) if (! $file); +pod2usage(-verbose => 2) if $man; + +my $limit = DateTime->now(); +$limit->subtract( months => 1); +my $endlimit = DateTime->now()->add(years =>1); +print STDERR "including events from: ",$limit->ymd," to: ".$endlimit->ymd,"\n" if $debug; +my $span = DateTime::Span->from_datetimes( start => $limit, end => $endlimit ); +print STDERR "Parsing $infile\n" if $debug; +my $cal = Data::ICal->new(filename => $infile); +if (! $cal) { + die "Died Trying to read $infile :".$cal->error_message; +} +#my $archive = Data::ICal->new(filename => 'archive.ics'); +print "Output = $file\n" if $debug; +my $new = Data::ICal->new(); +if (! $new) { + die $new->error_message; +} + +my @events = $cal->events($span); +$new->add_entries(@events); + +open(NEW, ">$file"); +print NEW $new->as_string; +close NEW; +exit 0; +#:vim set ft=perl ts=4 sts=4 expandtab : diff --git a/contrib/ical2rem-0.7/dailyreminders.sh b/contrib/ical2rem-0.7/dailyreminders.sh new file mode 100644 index 00000000..3341209f --- /dev/null +++ b/contrib/ical2rem-0.7/dailyreminders.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +r=`basename $0` + +if [ $r == 'weeklyreminders.sh' ]; +then + t=14; + w=Weekly; +elif [ $r == 'dailyreminders.sh' ]; +then + t=3; + w=Daily; +else + t=5 + w=Test; +fi + +cd .rem +for d in * ; +do + if [ "$( ls -A $d/$w 2>/dev/null )" ]; + then + echo "Sending a $w reminder to $d" + ft=/tmp/$d-t-$$.txt + f=/tmp/$d-$$.txt + echo "Reminders for next $t days:" >> $f + cat /dev/null > $d/ical2rem + for c in $d/*.ics + do + calname=`basename $c .ics | tr a-z A-Z` + cat $c 2>/dev/null | sed -e "s/^SUMMARY:/SUMMARY: {${calname}} /" \ + | sed -e 's/DT\([A-Z]*\);TZID=UTC:\([0-9T]*\)/DT\1:\2Z/' >> $ft + done + cat $ft | ~/bin/ical2rem.pl --label "Online Calendar" --heading "PRIORITY 9999" --lead-time $t >> $d/ical2rem + if [ -e $d/reminders ];then r="${d}/reminders"; else r="${d}/ical2rem";fi + /usr/bin/remind -q -iplain=1 $r >> $f + echo " +All calendars can be accessed by logging into https://calendar.google.com/ as $d@jalcorn.net +" >> $f + cat $f | mail -s "$w Reminders for $d" $d@jalcorn.net; + cat $f + rm $f + rm $ft + fi; +done diff --git a/contrib/ical2rem-0.7/getgooglecals.sh b/contrib/ical2rem-0.7/getgooglecals.sh new file mode 100644 index 00000000..6571f7b2 --- /dev/null +++ b/contrib/ical2rem-0.7/getgooglecals.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# +# Get google calendars, fix issues caused by changes in Google calendars, and remove all past events. +# +# Obviously, I've removed the private hashes from private calendars. +# +cd ~/calendars +wget -q -O full/justin.ics --no-check-certificate https://www.google.com/calendar/ical/jbalcorn\%40gmail.com/private-aaaaaaaaaaaaaaaaaaaaaaaaaa/basic.ics +wget -q -O full/family.ics --no-check-certificate https://www.google.com/calendar/ical/jalcorn.net_aaaaaaaaaaaaaaaaaaaaaaaaaa\%40group.calendar.google.com/private-6c42a79dec0b3b3bb7b9b0ebf9776bc1/basic.ics +wget -q -O full/son1.ics --no-check-certificate https://www.google.com/calendar/ical/son1\%40jalcorn.net/private-aaaaaaaaaaaaaaaaaaaaaaaaaa/basic.ics +wget -q -O full/vmd.ics --no-check-certificate https://calendar.google.com/calendar/ical/chuh.org_0pmkefjkiqc4snoel7occlslh8%40group.calendar.google.com/public/basic.ics + +for i in full/*.ics;do + cat $i 2>/dev/null | sed -e 's/DT\([A-Z]*\);TZID=UTC:\([0-9T]*\)/DT\1:\2Z/' > /tmp/temp.ics + cp /tmp/temp.ics $i +done + +~/bin/cal_futureonly.pl --infile=full/justin.ics --file=justin.ics +~/bin/cal_futureonly.pl --infile=full/family.ics --file=family.ics +~/bin/cal_futureonly.pl --infile=full/son1.ics --file=son1.ics +~/bin/cal_futureonly.pl --infile=full/vmd.ics --file=vmd.ics diff --git a/contrib/ical2rem.pl b/contrib/ical2rem-0.7/ical2rem.pl similarity index 65% rename from contrib/ical2rem.pl rename to contrib/ical2rem-0.7/ical2rem.pl index eae25fd8..e5c41007 100755 --- a/contrib/ical2rem.pl +++ b/contrib/ical2rem-0.7/ical2rem.pl @@ -19,7 +19,8 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # -# +# version 0.6 2019-03-01 +# - Updates to put on GitHub # version 0.5.2 2007-03-23 # - BUG: leadtime for recurring events had a max of 4 instead of DEFAULT_LEAD_TIME # - remove project-lead-time, since Category was a non-standard attribute @@ -32,7 +33,7 @@ # version 0.5 2007-03-21 # - Add more help options # - --project-lead-time option -# - Suppress printing of heading if there are no todos to print +# - Supress printing of heading if there are no todos to print # version 0.4 # - Version 0.4 changes all written or inspired by, and thanks to Mark Stosberg # - Change to GetOptions @@ -56,12 +57,19 @@ cat /path/to/file*.ics | ical2rem.pl > ~/.ical2rem All options have reasonable defaults: - --label Calendar name (Default: Calendar) + --label Calendar name (Default: Calendar) + --start Start of time period to parse (parsed by str2time) + --end End of time period to parse --lead-time Advance days to start reminders (Default: 3) --todos, --no-todos Process Todos? (Default: Yes) - --heading Define a priority for static entries - --help Usage - --man Complete man page + --iso8601 Use YYYY-MM-DD date format + --locations, --no-locations Include location? (Default: Yes) + --end-times, --no-end-times Include event end times in reminder text + (Default: No) + --heading Define a priority for static entries + --help Usage + --debug Enable debug output + --man Complete man page Expects an ICAL stream on STDIN. Converts it to the format used by the C script and prints it to STDOUT. @@ -74,6 +82,14 @@ The syntax generated includes a label for the calendar parsed. By default this is "Calendar". You can customize this with the "--label" option. +=head2 --iso8601 + +Use YYYY-MM-DD date format in output instead of Mmm DD YYYY + +=head2 --locations, --no-locations + +Whether or not to include locations in events + =head2 --lead-time ical2rem.pl --lead-time 3 @@ -84,7 +100,7 @@ How may days in advance to start getting reminders about the events. Defaults to ical2rem.pl --no-todos -If you don't care about the ToDos the calendar, this will suppress +If you don't care about the ToDos the calendar, this will surpress printing of the ToDo heading, as well as skipping ToDo processing. =head2 --heading @@ -98,6 +114,7 @@ the calendar entries. See the file defs.rem from the remind distribution for mo use strict; use iCal::Parser; +use Date::Parse; use DateTime; use Getopt::Long 2.24 qw':config auto_help'; use Pod::Usage; @@ -108,19 +125,31 @@ $VERSION = "0.5.2"; # Declare how many days in advance to remind my $DEFAULT_LEAD_TIME = 3; my $PROCESS_TODOS = 1; -my $HEADING = ""; +my $HEADING = ""; my $help; +my $debug; my $man; +my $iso8601; +my $do_location = 1; +my $do_end_times; +my $start; +my $end; my $label = 'Calendar'; GetOptions ( "label=s" => \$label, + "start=s" => \$start, + "end=s" => \$end, "lead-time=i" => \$DEFAULT_LEAD_TIME, "todos!" => \$PROCESS_TODOS, + "iso8601!" => \$iso8601, + "locations!" => \$do_location, + "end-times!" => \$do_end_times, "heading=s" => \$HEADING, "help|?" => \$help, + "debug" => \$debug, "man" => \$man -); +) or pod2usage(1); pod2usage(1) if $help; pod2usage(-verbose => 2) if $man; @@ -136,8 +165,22 @@ while (<>) { $in = ""; } } -my $parser = iCal::Parser->new(); +print STDERR "Read all calendars\n" if $debug; +my(%parser_opts) = ("debug" => $debug); +if ($start) { + my $t = str2time($start); + die "Invalid time $start\n" if (! $t); + $parser_opts{'start'} = DateTime->from_epoch(epoch => $t); +} +if ($end) { + my $t = str2time($end); + die "Invalid time $end\n" if (! $t); + $parser_opts{'end'} = DateTime->from_epoch(epoch => $t); +} +print STDERR "About to parse calendars\n" if $debug; +my $parser = iCal::Parser->new(%parser_opts); my $hash = $parser->parse_strings(@calendars); +print STDERR "Calendars parsed\n" if $debug; ############################################################## # @@ -209,6 +252,13 @@ sub _process_todos { # ###################################################################### +# Issue 8 https://github.com/jbalcorn/ical2rem/issues/8 +# Make sure there is a _sfun function declared in the reminder file. We'll just make it do nothing here. +print 'IF args("_sfun") < 1 + FSET _sfun(x) choose(x,0) +ENDIF +'; + print _process_todos($hash->{'todos'}) if $PROCESS_TODOS; my ($leadtime, $yearkey, $monkey, $daykey,$uid,%eventsbyuid); @@ -260,20 +310,67 @@ foreach $yearkey (sort keys %{$events} ) { $leadtime = "+".$DEFAULT_LEAD_TIME; } my $start = $event->{'DTSTART'}; - print "REM ".$start->month_abbr." ".$start->day." ".$start->year." $leadtime "; - if ($start->hour > 0) { - print " AT "; - print $start->strftime("%H:%M"); - print " +15 MSG %a %2 "; - } else { - print " MSG %a "; + my $end = $event->{'DTEND'}; + my $duration = ""; + if ($end and ($start->hour or $start->minute or $end->hour or $end->minute)) { + # We need both an HH:MM version of the delta, to put in the + # DURATION specifier, and a human-readable version of the + # delta, to put in the message if the user requested it. + my $seconds = $end->epoch - $start->epoch; + my $minutes = int($seconds / 60); + my $hours = int($minutes / 60); + $minutes -= $hours * 60; + $duration = sprintf("DURATION %d:%02d ", $hours, $minutes); } - print "%\"$event->{'SUMMARY'}"; - print " at $event->{'LOCATION'}" if $event->{'LOCATION'}; - print "\%\"%\n"; + print "REM "; + if ($iso8601) { + print $start->strftime("%F "); + } else { + print $start->month_abbr." ".$start->day." ".$start->year." "; + } + print "$leadtime "; + if ($duration or $start->hour > 0 or $start->minute > 0) { + print "AT "; + print $start->strftime("%H:%M"); + print " SCHED _sfun ${duration}MSG %a %2 "; + } else { + print "MSG %a "; + } + print "%\"", "e($event->{'SUMMARY'}); + print(" at ", "e($event->{'LOCATION'})) + if ($do_location and $event->{'LOCATION'}); + print "\%\""; + if ($do_end_times and ($start->hour or $start->minute or + $end->hour or $end->minute)) { + my $start_date = $start->strftime("%F"); + my $start_time = $start->strftime("%k:%M"); + my $end_date = $end->strftime("%F"); + my $end_time = $end->strftime("%k:%M"); + # We don't want leading whitespace; some strftime's support + # disabling the pdding in the format string, but not all, + # so for maximum portability we do it ourselves. + $start_time =~ s/^\s+//; + $end_time =~ s/^\s+//; + my(@pieces); + if ($start_date ne $end_date) { + push(@pieces, $end_date); + } + if ($start_time ne $end_time) { + push(@pieces, $end_time); + } + print " (-", join(" ", @pieces), ")"; + } + print "%\n"; } } } } + +sub quote { + local($_) = @_; + s/\[/["["]/g; + return $_; +} + exit 0; #:vim set ft=perl ts=4 sts=4 expandtab :