Commit 24c2c9c3 authored by Ana Guerrero López's avatar Ana Guerrero López

Import Upstream version 03.01.10

parent f54b015b
......@@ -3,7 +3,7 @@ THE REMIND COPYRIGHT
1. REMIND refers to the entire set of files and documentation in the
REMIND package.
2. REMIND is Copyright 1999-2008 Roaring Penguin Software Inc.,
2. REMIND is Copyright 1999-2010 Roaring Penguin Software Inc.,
except where noted in individual files.
3. DISTRIBUTION AND USE
......
MICROSOFT WINDOWS
=================
I used to prohibit porting Remind to Microsoft Windows. However, this
may cause problems with the GPL, so I have removed that restriction.
......@@ -11,5 +12,19 @@ If you port Remind to Windows, I will not provide support or answers to
questions -- you're on your own. On the other hand, I will feel no guilt
in taking enhancements and merging them into the UNIX stream.
APPLE
=====
I can't prevent you from using Remind on Apple's products, but I hope
you don't. Apple's corporate culture is the very antithesis of Free
Software. Rather than using Mac OS X, I encourage you to switch to
Linux or FreeBSD, two Free Software operating systems that are every
bit as capable as Mac OS X and which are unencumbered by Apple's
arbitrary restrictions.
And if you're looking to port Remind to other Apple products like the
iPhone or iPad, please don't. Those products enforce Apple's rigorous
controls much more stringently than Mac OS X on an Apple PC.
--
David F. Skoll.
David F. Skoll
......@@ -25,7 +25,7 @@ clean:
cd src; $(MAKE) clean
test:
cd src && $(MAKE) test
@cd src && $(MAKE) test
distclean: clean
rm -f config.cache config.log config.status src/Makefile src/config.h tests/test.out www/Makefile
......
......@@ -1691,6 +1691,36 @@ EOF
ac_config_headers="$ac_config_headers src/config.h"
if test "`uname -s`" = "Darwin" ; then
trap 'echo Be patient...' INT TERM
cat <<'EOF'
Please don't use Apple products. This script will continue in 30 seconds
if you insist on compiling Remind on Mac OS X.
EOF
for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do
sleep 1
done
trap - INT
trap - TERM
fi
if uname -s | grep -i -q 'cygwin' ; then
trap 'echo Be patient...' INT TERM
cat <<'EOF'
Please don't use Microsoft products. This script will continue in 30
seconds if you insist on compiling Remind on Cygwin.
EOF
for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do
sleep 1
done
trap - INT
trap - TERM
fi
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
......@@ -4691,7 +4721,9 @@ _ACEOF
for ac_header in sys/file.h glob.h
for ac_header in sys/file.h glob.h wctype.h locale.h
do
as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
......@@ -5191,7 +5223,9 @@ fi
for ac_func in setenv unsetenv glob
for ac_func in setenv unsetenv glob mbstowcs setlocale
do
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
{ echo "$as_me:$LINENO: checking for $ac_func" >&5
......@@ -5284,7 +5318,7 @@ _ACEOF
fi
done
VERSION=03.01.05
VERSION=03.01.10
ac_config_files="$ac_config_files src/Makefile www/Makefile src/version.h"
......
......@@ -14,6 +14,36 @@ EOF
AC_CONFIG_HEADER(src/config.h)
if test "`uname -s`" = "Darwin" ; then
trap 'echo Be patient...' INT TERM
cat <<'EOF'
Please don't use Apple products. This script will continue in 30 seconds
if you insist on compiling Remind on Mac OS X.
EOF
for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do
sleep 1
done
trap - INT
trap - TERM
fi
if uname -s | grep -i -q 'cygwin' ; then
trap 'echo Be patient...' INT TERM
cat <<'EOF'
Please don't use Microsoft products. This script will continue in 30
seconds if you insist on compiling Remind on Cygwin.
EOF
for i in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do
sleep 1
done
trap - INT
trap - TERM
fi
dnl Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL
......@@ -31,7 +61,7 @@ AC_CHECK_SIZEOF(unsigned int)
AC_CHECK_SIZEOF(unsigned long)
dnl Checks for header files.
AC_CHECK_HEADERS(sys/file.h glob.h)
AC_CHECK_HEADERS(sys/file.h glob.h wctype.h locale.h)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_STRUCT_TM
......@@ -44,7 +74,7 @@ if test "$GCC" = yes; then
CFLAGS="$CFLAGS -Wall -Wstrict-prototypes"
fi
AC_CHECK_FUNCS(setenv unsetenv glob)
VERSION=03.01.05
AC_CHECK_FUNCS(setenv unsetenv glob mbstowcs setlocale)
VERSION=03.01.10
AC_SUBST(VERSION)
AC_OUTPUT(src/Makefile www/Makefile src/version.h)
This directory contains contributed scripts. They are provided
"as-is" with no warranty. Please do not contact David Skoll
or Roaring Penguin Software Inc. for help with these scripts;
instead, contact the script authors.
You should check the upstream sources; there may be newer versions
of these scripts available.
--
David F. Skoll
#!/usr/bin/perl -w
#
# ical2rem.pl -
# Reads iCal files and outputs remind-compatible files. Tested ONLY with
# calendar files created by Mozilla Calendar/Sunbird. Use at your own risk.
# Copyright (c) 2005, 2007, Justin B. Alcorn
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# 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; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#
# 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.
=head1 SYNOPSIS
cat /path/to/file*.ics | ical2rem.pl > ~/.ical2rem
All options have reasonable defaults:
--label Calendar name (Default: Calendar)
--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
Expects an ICAL stream on STDIN. Converts it to the format
used by the C<remind> script and prints it to STDOUT.
=head2 --label
ical2rem.pl --label "Bob's Calendar"
The syntax generated includes a label for the calendar parsed.
By default this is "Calendar". You can customize this with
the "--label" option.
=head2 --lead-time
ical2rem.pl --lead-time 3
How may days in advance to start getting reminders about the events. Defaults to 3.
=head2 --no-todos
ical2rem.pl --no-todos
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
ical2rem.pl --heading "PRIORITY 9999"
Set an option on static messages output. Using priorities can made the static messages look different from
the calendar entries. See the file defs.rem from the remind distribution for more information.
=cut
use strict;
use iCal::Parser;
use DateTime;
use Getopt::Long 2.24 qw':config auto_help';
use Pod::Usage;
use Data::Dumper;
use vars '$VERSION';
$VERSION = "0.5.2";
# Declare how many days in advance to remind
my $DEFAULT_LEAD_TIME = 3;
my $PROCESS_TODOS = 1;
my $HEADING = "";
my $help;
my $man;
my $label = 'Calendar';
GetOptions (
"label=s" => \$label,
"lead-time=i" => \$DEFAULT_LEAD_TIME,
"todos!" => \$PROCESS_TODOS,
"heading=s" => \$HEADING,
"help|?" => \$help,
"man" => \$man
);
pod2usage(1) if $help;
pod2usage(-verbose => 2) if $man;
my $month = ['None','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
my @calendars;
my $in;
while (<>) {
$in .= $_;
if (/END:VCALENDAR/) {
push(@calendars,$in);
$in = "";
}
}
my $parser = iCal::Parser->new();
my $hash = $parser->parse_strings(@calendars);
##############################################################
#
# Subroutines
#
#############################################################
#
# _process_todos()
# expects 'todos' hashref from iCal::Parser is input
# returns String to output
sub _process_todos {
my $todos = shift;
my ($todo, @newtodos, $leadtime);
my $output = "";
$output .= 'REM '.$HEADING.' MSG '.$label.' ToDos:%"%"%'."\n";
# For sorting, make sure everything's got something
# To sort on.
my $now = DateTime->now;
for $todo (@{$todos}) {
# remove completed items
if ($todo->{'STATUS'} && $todo->{'STATUS'} eq 'COMPLETED') {
next;
} elsif ($todo->{'DUE'}) {
# All we need is a due date, everything else is sugar
$todo->{'SORT'} = $todo->{'DUE'}->clone;
} elsif ($todo->{'DTSTART'}) {
# for sorting, sort on start date if there's no due date
$todo->{'SORT'} = $todo->{'DTSTART'}->clone;
} else {
# if there's no due or start date, just make it now.
$todo->{'SORT'} = $now;
}
push(@newtodos,$todo);
}
if (! (scalar @newtodos)) {
return "";
}
# Now sort on the new Due dates and print them out.
for $todo (sort { DateTime->compare($a->{'SORT'}, $b->{'SORT'}) } @newtodos) {
my $due = $todo->{'SORT'}->clone();
my $priority = "";
if (defined($todo->{'PRIORITY'})) {
if ($todo->{'PRIORITY'} == 1) {
$priority = "PRIORITY 1000";
} elsif ($todo->{'PRIORITY'} == 3) {
$priority = "PRIORITY 7500";
}
}
if (defined($todo->{'DTSTART'}) && defined($todo->{'DUE'})) {
# Lead time is duration of task + lead time
my $diff = ($todo->{'DUE'}->delta_days($todo->{'DTSTART'})->days())+$DEFAULT_LEAD_TIME;
$leadtime = "+".$diff;
} else {
$leadtime = "+".$DEFAULT_LEAD_TIME;
}
$output .= "REM ".$due->month_abbr." ".$due->day." ".$due->year." $leadtime $priority MSG \%a $todo->{'SUMMARY'}\%\"\%\"\%\n";
}
$output .= 'REM '.$HEADING.' MSG %"%"%'."\n";
return $output;
}
#######################################################################
#
# Main Program
#
######################################################################
print _process_todos($hash->{'todos'}) if $PROCESS_TODOS;
my ($leadtime, $yearkey, $monkey, $daykey,$uid,%eventsbyuid);
print 'REM '.$HEADING.' MSG '.$label.' Events:%"%"%'."\n";
my $events = $hash->{'events'};
foreach $yearkey (sort keys %{$events} ) {
my $yearevents = $events->{$yearkey};
foreach $monkey (sort {$a <=> $b} keys %{$yearevents}){
my $monevents = $yearevents->{$monkey};
foreach $daykey (sort {$a <=> $b} keys %{$monevents} ) {
my $dayevents = $monevents->{$daykey};
foreach $uid (sort {
DateTime->compare($dayevents->{$a}->{'DTSTART'}, $dayevents->{$b}->{'DTSTART'})
} keys %{$dayevents}) {
my $event = $dayevents->{$uid};
if ($eventsbyuid{$uid}) {
my $curreventday = $event->{'DTSTART'}->clone;
$curreventday->truncate( to => 'day' );
$eventsbyuid{$uid}{$curreventday->epoch()} =1;
for (my $i = 0;$i < $DEFAULT_LEAD_TIME && !defined($event->{'LEADTIME'});$i++) {
if ($eventsbyuid{$uid}{$curreventday->subtract( days => $i+1 )->epoch() }) {
$event->{'LEADTIME'} = $i;
}
}
} else {
$eventsbyuid{$uid} = $event;
my $curreventday = $event->{'DTSTART'}->clone;
$curreventday->truncate( to => 'day' );
$eventsbyuid{$uid}{$curreventday->epoch()} =1;
}
}
}
}
}
foreach $yearkey (sort keys %{$events} ) {
my $yearevents = $events->{$yearkey};
foreach $monkey (sort {$a <=> $b} keys %{$yearevents}){
my $monevents = $yearevents->{$monkey};
foreach $daykey (sort {$a <=> $b} keys %{$monevents} ) {
my $dayevents = $monevents->{$daykey};
foreach $uid (sort {
DateTime->compare($dayevents->{$a}->{'DTSTART'}, $dayevents->{$b}->{'DTSTART'})
} keys %{$dayevents}) {
my $event = $dayevents->{$uid};
if (exists($event->{'LEADTIME'})) {
$leadtime = "+".$event->{'LEADTIME'};
} else {
$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 " SCHED _sfun MSG %a %2 ";
} else {
print " MSG %a ";
}
print "%\"$event->{'SUMMARY'}";
print " at $event->{'LOCATION'}" if $event->{'LOCATION'};
print "\%\"%\n";
}
}
}
}
exit 0;
#:vim set ft=perl ts=4 sts=4 expandtab :
DESTDIR?=
PREFIX?=/usr
BINDIR?=$(PREFIX)/bin
MANDIR?=$(PREFIX)/share/man
default: rem2ics.1
rem2ics.1:
pod2man -c "" rem2ics > rem2ics.1
install: rem2ics.1
install -p -D rem2ics $(DESTDIR)$(BINDIR)/rem2ics
install -p -D -m 0644 rem2ics.1 $(DESTDIR)$(MANDIR)/man1/rem2ics.1
#!/usr/bin/perl -w
# rem2ics -- convert the output of "remind -s" into RFC2445 iCalendar format.
# Copyright 2007,2008,2009
# Mark Atwood <me@mark.atwood.name>
# Paul Hinze <paul dot t dot hinze at gmail dot com>
# Michael Schultz <mjschultz at gmail dot com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# 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; if not, write to the
# Free Software Foundation, Inc.
# 51 Franklin Street, Fifth Floor
# Boston MA 02110-1301 USA
use strict;
use warnings;
=head1 NAME
rem2ics - convert the output of "remind -s" into RFC2445 iCalendar format.
=head1 SYNOPSIS
TZ=I<timezone> B<rem2ics> [B<-man>] [B<-do>] [B<-norecur>] [B<-usetag>] E<lt>input E<gt>output
=head1 OPTIONS AND ARGUMENTS
=over 8
=item B<-man>
Print the manual page and exit.
=item B<-do>
Actually do the conversion. Otherwise just print a brief help message
and usage example, and then exit.
=item B<-norecur>
Do not attempt to detect and fold together recurring events.
=item B<-usetag>
Generate UIDs using remind TAG clauses.
=back
Input is from standard input
Output is to standard output.
=head1 USAGE
remind -s360 -irem2ics=1 ~/.reminders 1 Jan 1991 | TZ=PST8PDT rem2ics -do >reminders.ics
This tells B<remind> to use ~/.reminders, and to process the entire
range of dates it can handle (from Jan 1 1991 to Dec 31 2020), and to
define a variable named C<rem2ics>, which can be used in
C<IF !defined("rem2ics")> / C<ENDIF> pairs.
B<rem2ics> will use a timezone of PST8PDT, and will fold events that
have the same name and duration into a single iCalendar VEVENT object.
=head1 NOTES
=head2 Timezones and the TZ environment variable.
B<rem2ics> uses the TZ environment variable to determine the value of
the RFC2445 TZID property. If you are running on a Linux or other GNU
libc based system, you probably don't (and probably shouldn't)
normally have TZ set. You can confirm this by running C<printenv TZ>
at a shell prompt. If your remind data is in your "local time", and
it probably is, you should probably set TZ to a good name for your
local timezone just for the run of this script. You probably should
NOT set TZ in your login scripts.
You can use TZ like this:
remind -s ~/.reminders | TZ=PST8PDT rem2ics -do >reminders.ics
or
remind -s ~/.reminders | TZ=US/Pacific rem2ics -do >reminders.ics
If, for some reason, your remind files are all in GMT instead of
localtime (you smart person you!), you can do this:
remind -s ~/.reminders | TZ=GMT rem2ics -do >reminders.ics
or
remind -s ~/.reminders | TZ=0 rem2ics -do >reminders.ics
and B<rem2ics> will use the ISO8601 "Z" notation for GMT time in the ics
file. (Other synonyms for GMT are the empty string (not the same as
the TZ not set), "I<0>", "I<Z>", "I<Zulu>", "I<Greenwitch>", "I<GMT>",
"I<GMT+0>, and "I<GMT-0>".)
If you leave TZ undefined and unset, B<rem2ics> will use the ISO8601
"T" notation date strings with no TZID property, which RFC2445 calls a
"floating time". Who knows, it might work for you!
The TZ string value is literally incorporated into the iCalendar
stream, so whatever your iCalendar-using application needs is what you
should use. You may have to experiment a bit.
You can look around in C</usr/share/zoneinfo> to get the names of
every timezone anywhere. This is the "Olson database" that RFC2445
refers to. Read the man page for L<tzfile(5)> for more than you ever
wanted to know about the format of these files, and about GNU libc's
handling of timezones. As complex as it is, it's certainly better
than what POSIX defines or what most legacy UNIX systems do, and most
certainly better than Microsoft, who in their "cutting edge" "state of
the art" "server" OS, still hasn't figured out that daylight time
rules might be different in different years.
If you just ran B<rem2ics> without reading all this stuff, or if you
don't want to worry about it at all, and somehow your iCalendar
application manager is able to guess the proper timezone for you, just
leave TZ undefined, and B<rem2ics> will use the ISO8601 "T" notation
date strings with no TZID property, which RFC2445 calls a "floating
time". Who knows, it might work for you!
=head2 Detecting recurring events
B<rem2ics> tries to detect recurring events. If any multiple events
appear with exactly the text and exactly the same duration (including
"no duration"), instead of multiple VEVENT objects, there will be just
one VEVENT object, that will have a RFC2445 C<RDATE> property.
B<rem2ics> is not yet smart enough to derive an C<RRULE> based
recurrance. If you really want that feature, either implement it and
send in a patch, or contact the author and convince him to do it.
=head2 Other iCalendar Properties
B<rem2ics> does not generate C<DESCRIPTION> or C<LOCATION>. One
would have to heuristically parse them out of the text, and everyone
uses a idiosyncratic way of putting things in B<remind>.
If the B<-usetag> option is not used or no C<TAG> is set for a
reminder, B<rem2ics> will synthesize C<UID> properties for each
VEVENT, but the UIDs will be different (and unique) for each run of
B<rem2ics>. If you run rem2ics twice and import the two resulting ICS
streams into your new scheduling program, your appointments will
appear twice. If, however, you have set C<TAG> clauses in your
reminders and activated B<-usetag>, these will be used. The same
applies for tags synthesized by B<remind>'s B<-y> option. Hence, it
is more useful to use the B<-y> option than to let B<rem2ics>
synthesize UIDs, because the UIDs will stay the same across multiple
runs.
=head2 Other iCalendar Perl objects
Why does't B<rem2ics> use any of the iCalendar Perl stuff in CPAN?
Because I don't trust them, and they are too big for this app. One
links to a binary library. Another hasn't been maintained since 1991,
and is full of notes as to how buggy and incomplete it is. And so
forth. I am not at this moment interested in groveling around in
L<Net::iCal>, L<DateTime::Format::iCal>, L<Tie::iCal>,
L<iCal::Parser>, or C<libical>.
=head2 Previous implementation
There is a working quick & dirty rem2ics written in awk
by Anthony J. Chivetta E<lt>achivetta@gmail.comE<gt>.
But it has the following problems: it doesn't escape the text, it
doesn't handle events that cross over midnight, it doesn't do
timezones, it doesn't enforce the correct EOL sequence, and it doesn't
fold long lines. This is a replacement for that script.
=head1 TODO
If TZ not set, grab out of system config somewhere
Detect recurring events.
If I'm REALLY smart, derive RRULE
Handle characters not in US-ASCII. Latin1? UTF8?
=head1 VERSION HISTORY
=over 8
=item version 0.1 2007-02-08
First cut.
=item version 0.2 2007-02-09
Reorg into multipass over a data structure.
=item version 0.3 2007-02-10
Collapse repeating events. Fold output lines.
=item version 0.9 2007-02-11
POD. Command line options. First public release.
=item version 0.91 2007-02-14
Bug fix, error message for non-recurring events
=item version 0.92 2008-01-28
Bug fix,
rem2ics 0.91 chokes on timed reminders with
duration using `remind -s` as it functions in remind-03.01.03.
Remind 3.01 changed how the -s data is formated for events that have a duration
Patch by Paul Hinze E<lt>paul dot t dot hinze at gmail dot comE<gt>
and Michael Schultz E<lt>mjschultz at gmail dot comE<gt>
=item version 0.93 2009-06-25
Add B<-usetag> option to allow for UIDs to stay the same across multiple runs
by using the remind TAG clause.
Patch by Tim Weber E<lt>scy at scytale dot nameE<gt>
=back
=head1 SEE ALSO
L<http://mark.atwood.name/code/rem2ics>
L<http://en.wikipedia.org/wiki/ICalendar>
L<http://tools.ietf.org/html/rfc2445>
L<http://www.roaringpenguin.com/en/penguin/openSourceProducts/remind>
L<remind(1)>
=head1 AUTHOR
Copyright 2007,2008,2009 by Mark Atwood E<lt>me+rem2ics@mark.atwood.nameE<gt>. L<http://mark.atwood.name/>.
Please report bugs (with patches, if possible).
Inspired by Anthony J. Chivetta E<lt>achivetta@gmail.comE<gt>'s
rem2ics in awk.
Thank you to David Skoll E<lt>dfs@roaringpengiun.com<gt> for Remind,
and to the IETF calsch wg for the iCalendar specification.
=cut
use Getopt::Long;
use Pod::Usage;
my $app_name = "rem2ics";
my $app_version = "0.93";
# process the command line
my %options;
GetOptions(\%options, qw(man do norecurr usetag)) || pod2usage(2);
pod2usage(-verbose => 2) if ($options{man});