#!/usr/bin/env ruby
#
# $Id: mycal,v 1.36 2004/12/14 03:13:56 ianmacd Exp $
#
# simple program to retrieve one's calendar entries for the coming seven days
#
# Copyright (C) 2002-2004 Ian Macdonald
#
#   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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

begin
  require 'password'
rescue LoadError
  $stderr.puts "This program requires Ruby/Password: http://www.caliban.org/ruby/"
  exit 1
end

require 'ctime'
require 'date'
require 'getoptlong'

def usage(code = 0)
  prog_name = File::basename($0)
  $stderr.print "
Usage: #{prog_name} [-d|--days <days>] [-c|--calendar <calendar>]
                    [-u|--user <user>]
       #{prog_name} -h|--help

-c, --calendar	Retrieve this person's calendar instead of your own
-d, --days	Retrieve calendar for this number of days (default: 7)
-i, --ics	Display output as raw iCalendar stream
-h, --help	Show this usage message
-u, --user	Log on as this user (overrides ~/.mycal)
"
  exit code
end

DEFAULT_PORT = 5730

server = nil; line_nr = __LINE__
calendar = nil
user = nil
passwd = nil
days = 7	# default number of days to retrieve events for
ics = false

# read ~/.mycal if it exists
dot_mycal = ENV['HOME'] + '/.mycal'

if FileTest.readable?(dot_mycal)
  if File.stat(dot_mycal).mode & 2 == 2
    $stderr.printf("%s is writable by others. Please fix this.\n", dot_mycal)
    exit 1
  end

  File.open(dot_mycal) do |file|
    while line = file.gets
      eval line
    end
  end
end

if server.nil?
  $stderr.puts "Please define a CorporateTime server in either line " +
	       "#{line_nr} of this program or a ~/.mycal file."
  exit 1
end

server.sub!(/:?$/, ':' + DEFAULT_PORT.to_s) unless server =~ /:\d+/

opt = GetoptLong.new(
  ['--calendar',	'-c', GetoptLong::REQUIRED_ARGUMENT],
  ['--days',		'-d', GetoptLong::REQUIRED_ARGUMENT],
  ['--help',		'-h', GetoptLong::NO_ARGUMENT],
  ['--ics',		'-i', GetoptLong::NO_ARGUMENT],
  ['--user',		'-u', GetoptLong::REQUIRED_ARGUMENT])

begin
  opt.each_option do |name,arg|
    case name
    when '--calendar'
      calendar = arg
    when '--days'
      days = arg.to_i
    when '--help'
      usage
    when '--ics'
      ics = true
    when '--user'
      user = arg
    end
  end
rescue
  usage 1
end

user ||= ( print "Username: "; gets.chomp ) 
passwd ||= Password.getc("Calendar password: ")

start_date = DateTime.now
end_date = start_date + days

begin
  ct = CTime.new.connect(server, user, passwd)
rescue
  printf("Failed to connect to %s as user %s\n", server, user)
  exit 2
end

ct.open_agenda(calendar ? calendar : user) do |agenda|

  if ics
    puts "BEGIN:VCALENDAR\r"
    puts "VERSION:1.0\r"
  else
    puts "Calendar for user #{user}:\n\n"
  end

  agenda.get_events(start_date, end_date) do |e|

    start_time = e.start_time.localtime
    end_time = e.end_time.localtime

    if ics
      puts e.ics.gsub(/^BEGIN:VALARM.+^END:VALARM\n/m, '').gsub(/$/, "\r")
      next
    end

    printf("%s until %s\n", start_time.strftime("%A, %B %d, %Y at %H:%M"),
           end_time.strftime("%H:%M"))

    unless e.summary.nil?
      e.summary.gsub!(/\\,/, ',')
      printf("  %s\n", e.summary)
    end

    unless e.description.nil?
      e.description.gsub!(/\\n/, "\n")
      e.description.gsub!(/\\,/, ',')
      printf("  %s\n", e.description)
    end

    unless e.location.nil?
      e.location.gsub!(/\\,/, ',')
      printf("  %s\n", e.location)
    end

    puts

  end

  puts "END:VCALENDAR\r" if ics
end

ct.quit
