summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoe <bousset.rudy@gmail.com>2022-05-16 21:40:28 +0200
committerJoe <bousset.rudy@gmail.com>2022-05-16 21:40:28 +0200
commit7e7c35d24f6b20ffffaea701196b98a1500bc5d8 (patch)
tree0bbb60bfb2249008b08a312f172894e7e195a1bf
parentupdate (diff)
downloaddotfiles-bsd-7e7c35d24f6b20ffffaea701196b98a1500bc5d8.tar.gz
dotfiles-bsd-7e7c35d24f6b20ffffaea701196b98a1500bc5d8.tar.bz2
dotfiles-bsd-7e7c35d24f6b20ffffaea701196b98a1500bc5d8.tar.xz
dotfiles-bsd-7e7c35d24f6b20ffffaea701196b98a1500bc5d8.tar.zst
dotfiles-bsd-7e7c35d24f6b20ffffaea701196b98a1500bc5d8.zip
Can read cals now
-rw-r--r--.config/mbsync/mbsyncrc26
-rw-r--r--.config/mutt/accounts/6-exploitation@secuserve.com.muttrc39
-rw-r--r--.config/mutt/mailcap3
-rw-r--r--.config/mutt/muttrc1
-rwxr-xr-x.local/bin/vcal969
5 files changed, 971 insertions, 67 deletions
diff --git a/.config/mbsync/mbsyncrc b/.config/mbsync/mbsyncrc
index 8ebf628..ff59167 100644
--- a/.config/mbsync/mbsyncrc
+++ b/.config/mbsync/mbsyncrc
@@ -102,29 +102,3 @@ SyncState *
MaxMessages 0
ExpireUnread no
# End profile
-
-IMAPStore exploitation@secuserve.com-remote
-Host next.optimails.com
-Port 993
-User exploitation@secuserve.com
-PassCmd "pass show mutt/exploitation@secuserve.com"
-AuthMechs LOGIN
-SSLType IMAPS
-CertificateFile /etc/ssl/cert.pem
-
-MaildirStore exploitation@secuserve.com-local
-Subfolders Verbatim
-Path /home/jozan/.local/share/mail/exploitation@secuserve.com/
-Inbox /home/jozan/.local/share/mail/exploitation@secuserve.com/INBOX
-Flatten .
-
-Channel exploitation@secuserve.com
-Expunge Both
-Far :exploitation@secuserve.com-remote:
-Near :exploitation@secuserve.com-local:
-Patterns *
-Create Both
-SyncState *
-MaxMessages 0
-ExpireUnread no
-# End profile
diff --git a/.config/mutt/accounts/6-exploitation@secuserve.com.muttrc b/.config/mutt/accounts/6-exploitation@secuserve.com.muttrc
deleted file mode 100644
index d78d1d4..0000000
--- a/.config/mutt/accounts/6-exploitation@secuserve.com.muttrc
+++ /dev/null
@@ -1,39 +0,0 @@
-# vim: filetype=neomuttrc
-# muttrc file for account exploitation@secuserve.com
-set realname = "SecuServe - Exploitation"
-set from = "exploitation@secuserve.com"
-set sendmail = "msmtp -a exploitation@secuserve.com"
-alias me Exploitation <exploitation@secuserve.com>
-set folder = "/home/jozan/.local/share/mail/exploitation@secuserve.com"
-set header_cache = /home/jozan/.cache/mutt-wizard/exploitation@secuserve.com/headers
-set message_cachedir = /home/jozan/.cache/mutt-wizard/exploitation@secuserve.com/bodies
-set mbox_type = Maildir
-
-bind index,pager gg noop
-bind index,pager g noop
-bind index,pager M noop
-bind index,pager C noop
-bind index gg first-entry
-macro index o "<shell-escape>mbsync -c /usr/home/jozan/.config/mbsync/mbsyncrc -a<enter>" "run mbsync to sync exploitation@secuserve.com"
-unmailboxes *
-
-mailboxes "=INBOX" "=INBOX.- Secuserve" "=INBOX.Altospam" "=INBOX.BAT" "=INBOX.DEBUG" "=INBOX.Erreurs (boite recept)" "=INBOX.Erreurs (boite recept).Erreur diverses" "=Sent" "=Drafts" "=Trash" "=NEWS"
-macro index,pager gi "<change-folder>=INBOX<enter>" "go to inbox" # mw-autogenerated
-macro index,pager Mi ";<save-message>=INBOX<enter>" "move mail to inbox" # mw-autogenerated
-macro index,pager Ci ";<copy-message>=INBOX<enter>" "copy mail to inbox" # mw-autogenerated
-set spoolfile = "+INBOX" # mw-autogenerated
-set postponed = "+Drafts" # mw-autogenerated
-macro index,pager gd "<change-folder>=Drafts<enter>" "go to drafts" # mw-autogenerated
-macro index,pager Md ";<save-message>=Drafts<enter>" "move mail to drafts" # mw-autogenerated
-macro index,pager Cd ";<copy-message>=Drafts<enter>" "copy mail to drafts" # mw-autogenerated
-set record = "+Sent" # mw-autogenerated
-macro index,pager gs "<change-folder>=Sent<enter>" "go to sent" # mw-autogenerated
-macro index,pager Ms ";<save-message>=Sent<enter>" "move mail to sent" # mw-autogenerated
-macro index,pager Cs ";<copy-message>=Sent<enter>" "copy mail to sent" # mw-autogenerated
-macro index,pager gt "<change-folder>=Trash<enter>" "go to trash" # mw-autogenerated
-macro index,pager Mt ";<save-message>=Trash<enter>" "move mail to trash" # mw-autogenerated
-macro index,pager Ct ";<copy-message>=Trash<enter>" "copy mail to trash" # mw-autogenerated
-macro index,pager gn "<change-folder>=NEWS<enter>" "go to sent" # mw-autogenerated
-macro index,pager Mn ";<save-message>=NEWS<enter>" "move mail to sent" # mw-autogenerated
-macro index,pager Cn ";<copy-message>=NEWS<enter>" "copy mail to sent" # mw-autogenerated
-set trash = "+Trash" # mw-autogenerated
diff --git a/.config/mutt/mailcap b/.config/mutt/mailcap
index 97a5395..750cbc1 100644
--- a/.config/mutt/mailcap
+++ b/.config/mutt/mailcap
@@ -1,7 +1,8 @@
text/plain; $EDITOR %s ;
text/html; w3m -o display_link_number=1 -I %{charset} -T text/html; copiousoutput;
+text/calendar; vcal -all %s; copiousoutput;
image/*; nsxiv -abf %s ;
-video/*; mpv --quiet %s &; copiousoutput
+video/*; mpv --quiet %s &; copiousoutput;
audio/*; mpv %s ;
application/pdf; zathura %s ;
application/pgp-encrypted; gpg -d '%s'; copiousoutput;
diff --git a/.config/mutt/muttrc b/.config/mutt/muttrc
index 5423178..db61864 100644
--- a/.config/mutt/muttrc
+++ b/.config/mutt/muttrc
@@ -5,4 +5,3 @@ macro index,pager i1 '<sync-mailbox><enter-command>source /home/jozan/.config/mu
macro index,pager i2 '<sync-mailbox><enter-command>source /home/jozan/.config/mutt/accounts/2-olsen.oyvind.nor@gmail.com.muttrc<enter><change-folder>!<enter>;<check-stats>' "switch to olsen.oyvind.nor@gmail.com" # mw-autogenerated
macro index,pager i3 '<sync-mailbox><enter-command>source /home/jozan/.config/mutt/accounts/3-towerofsilence777@gmail.com.muttrc<enter><change-folder>!<enter>;<check-stats>' "switch to towerofsilence777@gmail.com" # mw-autogenerated
macro index,pager i5 '<sync-mailbox><enter-command>source /home/jozan/.config/mutt/accounts/5-rbousset@secuserve.com.muttrc<enter><change-folder>!<enter>;<check-stats>' "switch to rbousset@secuserve.com" # mw-autogenerated
-macro index,pager i6 '<sync-mailbox><enter-command>source /home/jozan/.config/mutt/accounts/6-exploitation@secuserve.com.muttrc<enter><change-folder>!<enter>;<check-stats>' "switch to exploitation@secuserve.com" # mw-autogenerated
diff --git a/.local/bin/vcal b/.local/bin/vcal
new file mode 100755
index 0000000..542fc67
--- /dev/null
+++ b/.local/bin/vcal
@@ -0,0 +1,969 @@
+#!/usr/local/bin/perl
+#
+# vcal
+# This script searches a file and displays records in a VCALENDAR
+# (ICALENDAR) entry.
+#
+# Written by: Wayne Morrison (wayne@waynemorrison.com)
+#
+# Revision History:
+# 1.0 Initial version.
+# 2.0 Added -mh and -version options.
+# 2.1 Modified the ordering of name lists.
+# Aligned name list columns.
+# 2.2 Changed -version to -Version. 100530
+# 2.3 Case-insensitive checking for "mailto". 120721
+# Suggestion from Dr.-Ing. Torsten Finke.
+# (torsten.finke@igh-essen.com)
+# 2.4 Parse location field. 150521
+# Suggestion and patch from Beat Vontobel.
+# (b.vontobel@meteonews.ch)
+# 2.5 A file of '-' reads from STDIN. 150605
+# Suggestion and patch from Ivo Ihrke.
+# (ivo.ihrke@inria.fr)
+# 2.6 parsetime() changes for UTC and timezone. 150605
+# Suggestion and patch from Matthias Gay.
+# (gay.matthias@gmail.com)
+# 2.7 Fixed duplicated summary error. 150606
+# Removed carriage returns and language
+# markers from the lines.
+# 2.8 Added license sections. 180526
+#
+# Copyright 2009-2018 Wayne Morrison
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+use strict;
+
+use Getopt::Long qw(:config no_ignore_case_always);
+
+#
+# Version information.
+#
+my $NAME = "vcal";
+my $VERS = "$NAME version: 2.7";
+
+#----------------------------------------------------------------------
+#
+# Data required for command line options.
+#
+my %options = (); # Filled option array.
+my @opts =
+(
+ "all", # Display all records.
+ "chair", # Display meeting chair.
+ "description", # Display description.
+ "end", # Display end time.
+ "location", # Display location.
+ "optional", # Display required participants.
+ "organizer", # Display organizer.
+ "participants", # Display participants.
+ "raw", # Display raw data.
+ "required", # Display required participants.
+ "scheduled", # Display scheduled time.
+ "start", # Display start time.
+ "summary", # Display summary.
+
+ "mh", # Examine a file in the MH directory.
+
+ "help", # Help request.
+ "Version", # Version request.
+);
+
+my $allflag = 0;
+my $chairflag = 0;
+my $descrflag = 0;
+my $endflag = 0;
+my $orgflag = 0;
+my $locflag = 0;
+my $partoptflag = 0;
+my $partreqflag = 0;
+my $partsflag = 0;
+my $rawflag = 0;
+my $schedflag = 0;
+my $startflag = 0;
+my $summaryflag = 0;
+
+my $mhflag = 0;
+
+my $numopts = 0; # Count of specific-field options.
+
+#
+# Command used by -mh.
+#
+my $MHPATH = "/usr/local/nmh/bin/mhpath";
+
+#---------------------------------------------
+
+#
+# All our vcalendar/icalendar data.
+#
+my @vcalend = ();
+
+#
+# Parsed vcalendar/icalendar data.
+#
+my @chairs = (); # Event chairs.
+my @descrs = (); # Descriptions.
+my @locations = (); # Locations.
+my @organizers = (); # CEvent organizers.
+my @partopts = (); # Optional participants.
+my @partreqs = (); # Required participants.
+my @summaries = (); # Summaries.
+
+my $starter = ""; # Event start.
+my $ender = ""; # Event end.
+my $scheduled = ""; # Event schedule time.
+
+my $longaddrlen = -1; # Length of longest email address.
+
+#---------------------------------------------
+
+#
+# Let 'er rip.
+#
+main();
+exit(0);
+
+#------------------------------------------------------------------------
+# Routine: main()
+#
+sub main
+{
+ my $fcnt = 0; # Files left to check.
+ my $ind; # Loop index.
+
+ #
+ # Check our options.
+ #
+ doopts();
+
+ #
+ # Give a usage message if there aren't any input files.
+ #
+ $fcnt = @ARGV;
+ usage() if($fcnt < 1);
+
+ #
+ # Check the input files for vcalendar data.
+ #
+ for($ind=0; $ind < $fcnt; $ind++)
+ {
+ my $fn = shift @ARGV; # Get the next file.
+
+ #
+ # Initialize a bunch of data.
+ #
+ @vcalend = ();
+ @chairs = ();
+ @descrs = ();
+ @locations = ();
+ @organizers = ();
+ @partopts = ();
+ @partreqs = ();
+ @summaries = ();
+ $ender = "";
+ $scheduled = "";
+ $starter = "";
+
+ #
+ # Parse the file.
+ #
+ dofile($fn);
+
+ if(@ARGV > 0)
+ {
+ print "\n--------------------------------\n\n";
+ }
+ }
+}
+
+#-----------------------------------------------------------------------------
+# Routine: doopts()
+#
+# Purpose: This routine deals with the command's options.
+#
+sub doopts
+{
+ #
+ # Check our options.
+ #
+ GetOptions(\%options,@opts) || usage();
+ $allflag = $options{'all'};
+ $chairflag = $options{'chair'};
+ $descrflag = $options{'description'};
+ $locflag = $options{'location'};
+ $orgflag = $options{'organizer'};
+ $partsflag = $options{'participants'};
+ $partreqflag = $options{'required'};
+ $partoptflag = $options{'optional'};
+ $schedflag = $options{'scheduled'};
+ $startflag = $options{'start'};
+ $summaryflag = $options{'summary'};
+ $endflag = $options{'end'};
+ $rawflag = $options{'raw'};
+
+ $mhflag = $options{'mh'};
+
+ #
+ # Show the usage message if requested.
+ #
+ usage() if(defined($options{'help'}));
+
+ #
+ # Show the usage message if requested.
+ #
+ version() if(defined($options{'Version'}));
+
+ #
+ # If -all was given, set all the flags (except rawflag.)
+ #
+ if($allflag)
+ {
+ $chairflag = 1;
+ $descrflag = 1;
+ $endflag = 1;
+ $locflag = 1;
+ $orgflag = 1;
+ $partoptflag = 1;
+ $partreqflag = 1;
+ $schedflag = 1;
+ $startflag = 1;
+ $summaryflag = 1;
+ }
+
+ #
+ # If -participants was given, we'll set the two specific
+ # participants flags.
+ #
+ if($partsflag)
+ {
+ $partreqflag = 1;
+ $partoptflag = 1;
+ }
+
+ #
+ # Figure out how many field-specific options were set.
+ #
+ $numopts = $chairflag + $descrflag + $orgflag +
+ $partreqflag + $partoptflag + $schedflag +
+ $startflag + $summaryflag + $endflag +
+ $locflag;
+
+ #
+ # Set our default display if no options were given.
+ #
+ if($numopts == 0)
+ {
+ $startflag = 1;
+ $endflag = 1;
+ $summaryflag = 1;
+ }
+}
+
+#------------------------------------------------------------------------
+# Routine: dofile()
+#
+sub dofile
+{
+ my $fn = shift;
+
+ #
+ # If -mh was given, we'll get the file from the MH directory.
+ #
+ if($mhflag)
+ {
+ my $out; # Command output.
+ my $ret; # Command return code.
+
+ #
+ # Ensure the file exists in the MH directory. We'll use this
+ # quiet version in case the file doesn't exist.
+ #
+ `MHPATH $fn > /dev/null 2>&1`;
+ if($? != 0)
+ {
+ print "error: unable to read \"$fn\" from MH directory\n";
+ return(-1);
+ }
+
+ #
+ # Get the file's actual path.
+ #
+ $out =`$MHPATH $fn`;
+
+ #
+ # Adjust the name of the input file.
+ #
+ chomp $out;
+ $fn = $out;
+ }
+
+ #
+ # Get the vcalendar data from the file.
+ #
+ return if(getvcalend($fn) < 0);
+
+ #
+ # Print requested data.
+ #
+ if($rawflag)
+ {
+ listraw();
+ }
+ else
+ {
+ listfields();
+ }
+}
+
+#------------------------------------------------------------------------
+# Routine: getvcalend()
+#
+sub getvcalend
+{
+ my $fn = shift; # Input file.
+
+ my @vctmp = (); # Temporary vcalendar data.
+ my $contents = ""; # File contents.
+ my $linecnt; # Count of lines.
+ my $ind; # Loop index.
+
+ my $found = 0; # Vcalendar-found flag.
+
+ #
+ # Get the vcalendar data. If a dash was given as the filename,
+ # we'll read the data from stdin instead of a file.
+ #
+ if($fn eq '-')
+ {
+ @vctmp = <STDIN>;
+ }
+ else
+ {
+ #
+ # Make sure the file exists and is readable.
+ #
+ if((! -f $fn) || (! -r $fn))
+ {
+ print "error: unable to read \"$fn\"\n";
+ return(-1);
+ }
+
+ #
+ # Get the contents of the file.
+ #
+ open(VCARD,"<$fn");
+ @vctmp = <VCARD>;
+ close(VCARD);
+ }
+
+ #
+ # Save the line count of the vcalendar data.
+ #
+ $linecnt = @vctmp;
+
+ #
+ # Plop all the file's lines into a single line. We'll mess around
+ # with some of the lines a bit:
+ # - unfold the split lines into single lines
+ # - delete the X-LOTUS lines
+ #
+ $contents = join("", @vctmp);
+ $contents =~ s/\n[ \t]//gm;
+ $contents =~ s/^X-LOTUS.*\n//gm;
+
+ #
+ # Build a new array filled with vcalendar goodness.
+ #
+ @vctmp = split /\n/, $contents;
+
+ #
+ # Copy the vcalendar data to our real vcalendar array.
+ #
+ $linecnt = @vctmp;
+ for($ind=0; $ind < $linecnt; $ind++)
+ {
+ #
+ # Set a found flag if we've found the start of the vcalendar.
+ #
+ if($vctmp[$ind] =~ /BEGIN\:VCALENDAR/)
+ {
+ $found = 1;
+ }
+
+ #
+ # Drop out if we're at the end of the vcalendar data.
+ #
+ if($vctmp[$ind] =~ /END\:VCALENDAR/)
+ {
+ push @vcalend, $vctmp[$ind];
+ last;
+ }
+
+ #
+ # Save this line if we're in the vcalendar data.
+ #
+ push @vcalend, $vctmp[$ind] if($found);
+ }
+
+ #
+ # Make sure we found some vcalendar data.
+ #
+ if($found == 0)
+ {
+ print "error: no vcalendar data in \"$fn\"\n";
+ return(-1);
+ }
+
+ return(0);
+}
+
+#------------------------------------------------------------------------
+# Routine: listraw()
+#
+sub listraw
+{
+ foreach my $line (@vcalend)
+ {
+ print "$line\n";
+ }
+}
+
+#------------------------------------------------------------------------
+# Routine: listfields()
+#
+sub listfields
+{
+ foreach my $line (@vcalend)
+ {
+ my $txt = "";
+
+ #
+ # To start, we'll remove carriage returns and language
+ # markers from the line.
+ #
+ $line =~ s/ //g;
+ $line =~ s/LANGUAGE=(.*?)://g;
+
+ if($chairflag &&
+ ($line =~ /^ATTENDEE/) &&
+ ($line =~ /ROLE=CHAIR/))
+ {
+ $txt = getname($line);
+ push @chairs, $txt;
+ }
+
+ if($orgflag && ($line =~ /^ORGANIZER/))
+ {
+ $txt = getname($line);
+ push @organizers, $txt;
+ }
+
+ if($locflag && ($line =~ /^LOCATION/))
+ {
+ $txt = getdescr($line);
+ push @locations, $txt;
+ }
+
+ if($partoptflag && ($line =~ /ROLE=OPT-PARTICIPANT/))
+ {
+ $txt = getname($line);
+ push @partopts, $txt;
+ }
+
+ if($partreqflag && ($line =~ /ROLE=REQ-PARTICIPANT/))
+ {
+ $txt = getname($line);
+ push @partreqs, $txt;
+ }
+
+ if($descrflag && ($line =~ /^DESCRIPTION/))
+ {
+ $txt = getdescr($line);
+ push @descrs, $txt;
+ }
+
+ if($startflag && ($line =~ /^DTSTART/))
+ {
+ $starter = parsetime($line);
+ }
+
+ if($endflag && ($line =~ /^DTEND/))
+ {
+ $ender = parsetime($line);
+ }
+
+ if($schedflag && ($line =~ /^DTSTAMP/))
+ {
+ $scheduled = parsetime($line);
+ }
+
+ if($summaryflag && ($line =~ /^SUMMARY/))
+ {
+ $txt = getsumm($line);
+ push @summaries, $txt;
+ }
+
+ }
+
+ if($startflag)
+ {
+ print "event start: $starter\n";
+ }
+
+ if($endflag)
+ {
+ print "event end: $ender\n";
+ }
+
+ if($schedflag)
+ {
+ print "event scheduled: $scheduled\n";
+ }
+
+ print "\n" if($startflag || $endflag || $schedflag);
+
+ if($summaryflag)
+ {
+ print "summary: $scheduled\n";
+ foreach my $sum (@summaries)
+ {
+ my @lines;
+
+ @lines = split /\\n/, $sum;
+ foreach my $ln (@lines)
+ {
+ print "\t$ln\n";
+ }
+ print "\n";
+ }
+ }
+
+ if($locflag && (@locations > 0))
+ {
+ print "event location:\n";
+ foreach my $desc (@locations)
+ {
+ my @lines;
+
+ @lines = split /\\n/, $desc;
+ foreach my $ln (@lines)
+ {
+ print "\t$ln\n";
+ }
+ print "\n";
+ }
+ print "\n";
+ }
+
+ if($chairflag && (@chairs > 0))
+ {
+ print "event chair:\n";
+ foreach my $name (sort(@chairs))
+ {
+ dispname($name);
+ }
+ print "\n";
+ }
+
+ if($orgflag && (@organizers > 0))
+ {
+ print "event organizer:\n";
+ foreach my $name (sort(@organizers))
+ {
+ dispname($name);
+ }
+ print "\n";
+ }
+
+ if($partreqflag && (@partreqs > 0))
+ {
+ print "required participants:\n";
+ foreach my $name (sort(@partreqs))
+ {
+ dispname($name);
+ }
+ print "\n";
+ }
+
+ if($partoptflag && (@partopts > 0))
+ {
+ print "optional participants:\n";
+ foreach my $name (sort(@partopts))
+ {
+ dispname($name);
+ }
+ print "\n";
+ }
+
+ if($descrflag && (@descrs > 0))
+ {
+ print "description:\n";
+ foreach my $desc (@descrs)
+ {
+ my @lines;
+
+ @lines = split /\\n/, $desc;
+ foreach my $ln (@lines)
+ {
+ print "\t$ln\n";
+ }
+ print "\n";
+ }
+ }
+
+}
+
+#------------------------------------------------------------------------
+# Routine: dispname()
+#
+sub dispname
+{
+ my $namestr = shift; # Name/addr string.
+ my $name; # Real name.
+ my $addr; # Email address.
+ my $len; # Length of address.
+ my $spaces = 0; # Number of spaces to add.
+
+# print "\t$name\n";
+
+ #
+ # Dig the name and email address out of the name string.
+ #
+ $namestr =~ /^\((.*)\)\t\t(.*)$/;
+ $addr = $1;
+ $name = $2;
+ $name =~ s/[ \t]*$//;
+ $len = length($addr);
+
+ #
+ # Figure out how many spaces are needed between the name and address.
+ #
+ $spaces = $longaddrlen - $len + 8;
+
+ print "\t$addr" . (' ' x $spaces) . "$name\n";
+}
+
+#------------------------------------------------------------------------
+# Routine: getname()
+#
+sub getname
+{
+ my $ln = shift; # Data line.
+ my $name; # Name from data line.
+ my $email; # Email address from data line.
+ my $retstr; # Return string.
+
+ #
+ # Dig the name and email address from the line.
+ #
+ $ln =~ /CN=\"(.+?)\"/i;
+ $name = $1;
+
+ #
+ # Dig the name and email address from the line.
+ #
+ $ln =~ /:mailto:(.+)$/i;
+ $email = $1;
+
+ #
+ # Save the length of the longest email address.
+ #
+ if(length($email) > $longaddrlen)
+ {
+ $longaddrlen = length($email);
+ }
+
+ #
+ # Build our return string.
+ #
+ if(($name eq "") && ($email eq ""))
+ {
+ $retstr = '';
+ }
+ else
+ {
+ $retstr = "($email)\t\t$name";
+ }
+
+ return($retstr);
+}
+
+#------------------------------------------------------------------------
+# Routine: getdescr()
+#
+sub getdescr
+{
+ my $line = shift;
+
+ $line =~ s/^DESCRIPTION//;
+ $line =~ s/ALTREP=".*"//;
+ $line =~ s/^[;:]*//;
+ $line =~ s/\\,/,/g;
+ $line =~ s/\\\\/\//g;
+
+ return($line);
+}
+
+#------------------------------------------------------------------------
+# Routine: getsumm()
+#
+sub getsumm
+{
+ my $line = shift;
+ my $val;
+
+ $line =~ /^SUMMARY:(.*)$/;
+
+ $line =~ s/\\,/,/g;
+ $line =~ s/\\;/;/g;
+ $line =~ s/\\\\/\//g;
+
+ return($line);
+}
+
+#------------------------------------------------------------------------
+# Routine: parsetime()
+#
+sub parsetime
+{
+ my $line = shift; # Time line.
+ my $key; # Key from line.
+ my $val; # Value from line.
+ my $retstr; # Return string.
+ my @chron = (); # Time fields.
+
+ #
+ # Dig out the values from the line.
+ #
+ $line =~ /(.*?):(.*)/;
+ $key = $1;
+ $val = $2;
+
+ #
+ # Get the time values.
+ #
+ $val =~ s/[<>]//g;
+ @chron = split /T/, $val;
+# $chron[0] =~ s/(..)(..)(..)(..)/$3\/$4\/$2/;
+ $chron[0] =~ s/(....)(..)(..)/$1\-$2\-$3/; # ISO date format
+ $chron[1] =~ s/(..)(..)(.*)/$1:$2/;
+
+ #
+ # Deal with the time zone, if present.
+ #
+ if($key =~ /TZID/)
+ {
+# $key =~ /TZID="(.*)"/;
+ $key =~ /TZID=(.*)/;
+ $chron[2] = $1;
+ }
+
+ #
+ # Use UTC time if 'Z' is appended to the DATE-TIME string.
+ #
+ if($val =~ /Z/)
+ {
+ $chron[2] = 'UTC';
+ }
+
+ #
+ # Build and return the return string.
+ #
+ $retstr = "$chron[0]\t$chron[1]\t$chron[2]";
+ return($retstr);
+}
+
+#------------------------------------------------------------------------
+# Routine: usage()
+#
+sub usage
+{
+ print "usage: vcal [options] <file1 ... fileN>\n";
+ print "\toptions:\n";
+ print "\t\t-all show all calendar data\n";
+ print "\t\t-chair show meeting chair\n";
+ print "\t\t-description show event description\n";
+ print "\t\t-end show event end time\n";
+ print "\t\t-location show meeting locations\n";
+ print "\t\t-optional show optional participants\n";
+ print "\t\t-organizer show meeting organizer\n";
+ print "\t\t-participants show participants\n";
+ print "\t\t-required show required participants\n";
+ print "\t\t-scheduled show event scheduled time\n";
+ print "\t\t-start show event start time\n";
+ print "\t\t-summary show summary information\n";
+ print "\n";
+ print "\t\t-raw show raw vcalendar data\n";
+ print "\n";
+ print "\t\t-mh files are taken from the current MH mailbox\n";
+ print "\n";
+ print "\t\t-help display this message\n";
+ print "\t\t-Version display the program version and exit\n";
+ exit(1);
+}
+
+#------------------------------------------------------------------------
+# Routine: version()
+#
+sub version
+{
+ print "$VERS\n";
+ exit(0);
+}
+
+1;
+
+##############################################################################
+#
+
+=pod
+
+=head1 NAME
+
+B<vcal> - Display the data in a I<vcalendar> or I<icalendar> file
+
+=head1 SYNOPSIS
+
+ vcal [options] <files>
+
+=head1 DESCRIPTION
+
+B<vcal> parses a file for a I<vcalendar> or I<icalendar> record and displays
+the selected fields from the record.
+
+Normally, B<vcal> uses the specified files as absolute or relative paths,
+depending on how they are given on the command line. However, if the B<-mh>
+flag is given, the current MH mailbox is searched for the specified files.
+The B<mhpath> command is used to determine the absolute path to the files.
+If a single dash is given as a filename, then the I<vcalendar> data will be
+read from standard input.
+
+B<vcal> takes options to allow selective display of the calendar data.
+If no options are given, then it is as if the B<-start>, B<-end>, and
+B<-summary> options are given.
+
+=head1 OPTIONS
+
+B<vcal> takes the following options:
+
+=over 4
+
+=item B<-all>
+
+Show all calendar data. This differs from B<-raw> in that the data are
+formatted, while B<-raw> gives the data as they are read from the file.
+
+=item B<-chair>
+
+Show the meeting chair.
+
+=item B<-description>
+
+Show the event description.
+
+=item B<-end>
+
+Show the event end time.
+
+=item B<-location>
+
+Show the meeting locations.
+
+=item B<-optional>
+
+Show the optional participants.
+
+=item B<-organizer>
+
+Show the meeting organizer.
+
+=item B<-participants>
+
+Show the required and optional participants. The participants are displayed
+in these two groups.
+
+=item B<-required>
+
+Show the required participants.
+
+=item B<-scheduled>
+
+Show the event scheduled time.
+
+=item B<-start>
+
+Show the event start time.
+
+=item B<-summary>
+
+Show the event summary information.
+
+=item B<-raw>
+
+Show all calendar data. This differs from B<-all> in that the data are
+data displayed as they are read from the file, while B<-all> formats the data.
+
+=item B<-mh>
+
+The current MH mailbox is searched for the specified files.
+
+=item B<-help>
+
+Display a usage message and exit.
+
+=item B<-Version>
+
+Display the program version and exit.
+
+=back
+
+=head1 ACKNOWLEDGMENTS
+
+Thanks to Dr.-Ing. Torsten Finke (torsten.finke@igh-essen.com) for suggesting
+the case-insensitive checking for "mailto". This was added in version 2.3.
+
+Thanks to Beat Vontobel (b.vontobel@meteonews.ch) for the patch for the
+B<-location> option. The patch (used by permission) was added in version 2.4.
+
+Thanks to Ivo Ihrke (ivo.ihrke@inria.fr) for the patch for reading the
+calendar data if the input file is a dash. The patch (used by permission)
+was added in version 2.5.
+
+Thanks to Matthias Gay (gay.matthias@gmail.com) for the UTC and timezone
+patches. These patches (used by permission) were added in version 2.6.
+
+=head1 AUTHOR
+
+Wayne Morrison, wayne@waynemorrison.com
+
+=head1 LICENSE
+
+Copyright 2009-2018 Wayne Morrison
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+=cut
+