$OpenBSD: patch-lib_agcaldav_client_rb,v 1.2 2013/03/18 21:45:41 jasper Exp $

commit c13ea74da87d56c526f0187abe30e9d185f43374
Author: Geoff Evans <gbeevans@me.com>
Date:   Wed Feb 20 11:01:50 2013 +1300
Subject:Adds Digest Authentication

commit 20687529a3c3554d0f51dabd81e06b172a96b940
Author: Geoff Evans <gbeevans@me.com>
Date:   Wed Mar 6 12:34:46 2013 +1300
Subject:Fix Digest to work over ssl.

commit 7b411e884b3884ca1f49338e1e2f12925c58ae0d
Author: Geoff Evans <gbeevans@me.com>
Date:   Tue Mar 19 10:08:31 2013 +1300
Subject:Fix find_events for pure ruby

--- lib/agcaldav/client.rb.orig	Thu Jan  1 01:00:00 1970
+++ lib/agcaldav/client.rb	Mon Mar 18 22:31:42 2013
@@ -17,6 +17,7 @@ module AgCalDAV
         @proxy_host = proxy_uri.host
         @proxy_port = proxy_uri.port.to_i
       end
+      
       uri = URI(data[:uri])
       @host     = uri.host
       @port     = uri.port.to_i
@@ -24,6 +25,24 @@ module AgCalDAV
       @user     = data[:user]
       @password = data[:password]
       @ssl      = uri.scheme == 'https'
+      
+      unless data[:authtype].nil?
+      	@authtype = data[:authtype]
+      	if @authtype == 'digest'
+      	
+      		@digest_auth = Net::HTTP::DigestAuth.new
+      		@duri = URI.parse data[:uri]
+      		@duri.user = @user
+      		@duri.password = @password
+      		
+      	elsif @authtype == 'basic'
+	    	#Don't Raise or do anything else
+	    else
+	    	raise "Authentication Type Specified Is Not Valid. Please use basic or digest"
+	    end
+      else
+      	@authtype = 'basic'
+      end
     end
 
     def __create_http
@@ -44,14 +63,26 @@ module AgCalDAV
       events = []
       res = nil
       __create_http.start {|http|
+      	
         req = Net::HTTP::Report.new(@url, initheader = {'Content-Type'=>'application/xml'} )
-        req.basic_auth @user, @password
-        req.body = AgCalDAV::Request::ReportVEVENT.new(DateTime.parse(data[:start]).strftime("%Y%m%dT%H%M"), 
-                                                       DateTime.parse(data[:end]).strftime("%Y%m%dT%H%M") ).to_xml
+        
+		if not @authtype == 'digest'
+			req.basic_auth @user, @password
+		else
+			req.add_field 'Authorization', digestauth('REPORT')
+		end
+		    if data[:start].is_a? Integer
+          req.body = AgCalDAV::Request::ReportVEVENT.new(Time.at(data[:start]).utc.strftime("%Y%m%dT%H%M%S"), 
+                                                        Time.at(data[:end]).utc.strftime("%Y%m%dT%H%M%S") ).to_xml
+        else
+          req.body = AgCalDAV::Request::ReportVEVENT.new(DateTime.parse(data[:start]).utc.strftime("%Y%m%dT%H%M%S"), 
+                                                        DateTime.parse(data[:end]).utc.strftime("%Y%m%dT%H%M%S") ).to_xml
+        end
         res = http.request(req)
       } 
         errorhandling res
         result = ""
+        
         xml = REXML::Document.new(res.body)
         REXML::XPath.each( xml, '//c:calendar-data/', {"c"=>"urn:ietf:params:xml:ns:caldav"} ){|c| result << c.text}
         r = Icalendar.parse(result)      
@@ -70,16 +101,21 @@ module AgCalDAV
     def find_event uuid
       res = nil
       __create_http.start {|http|
-        req = Net::HTTP::Get.new("#{@url}/#{uuid}.ics")
-        req.basic_auth @user, @password
+        req = Net::HTTP::Get.new("#{@url}/#{uuid}.ics")        
+        if not @authtype == 'digest'
+        	req.basic_auth @user, @password
+        else
+        	req.add_field 'Authorization', digestauth('GET')
+        end
         res = http.request( req )
       }  
       errorhandling res
-      r = Icalendar.parse(res.body)
-      unless r.empty?
-        r.first.events.first 
+      begin
+      	r = Icalendar.parse(res.body)
+      rescue
+      	return false
       else
-        return false
+      	r.first.events.first 
       end
 
       
@@ -89,7 +125,11 @@ module AgCalDAV
       res = nil
       __create_http.start {|http|
         req = Net::HTTP::Delete.new("#{@url}/#{uuid}.ics")
-        req.basic_auth @user, @password
+        if not @authtype == 'digest'
+        	req.basic_auth @user, @password
+        else
+        	req.add_field 'Authorization', digestauth('DELETE')
+        end
         res = http.request( req )
       }
       errorhandling res
@@ -126,7 +166,11 @@ module AgCalDAV
       __create_http.start { |http|
         req = Net::HTTP::Put.new("#{@url}/#{uuid}.ics")
         req['Content-Type'] = 'text/calendar'
-        req.basic_auth @user, @password
+        if not @authtype == 'digest'
+        	req.basic_auth @user, @password
+        else
+        	req.add_field 'Authorization', digestauth('PUT')
+        end
         req.body = cstring
         res = http.request( req )
       }
@@ -147,19 +191,15 @@ module AgCalDAV
     
     end
 
-   
-
-
-
-
-
-
-
     def find_todo uuid
       res = nil
       __create_http.start {|http|
         req = Net::HTTP::Get.new("#{@url}/#{uuid}.ics")
-        req.basic_auth @user, @password
+        if not @authtype == 'digest'
+        	req.basic_auth @user, @password
+        else
+        	req.add_field 'Authorization', digestauth('GET')
+        end
         res = http.request( req )
       }  
       errorhandling res
@@ -196,7 +236,11 @@ module AgCalDAV
       __create_http.start { |http|
         req = Net::HTTP::Put.new("#{@url}/#{uuid}.ics")
         req['Content-Type'] = 'text/calendar'
-        req.basic_auth @user, @password
+        if not @authtype == 'digest'
+        	req.basic_auth @user, @password
+        else
+        	req.add_field 'Authorization', digestauth('PUT')
+        end
         req.body = cstring
         res = http.request( req )
       }
@@ -210,7 +254,11 @@ module AgCalDAV
 
       __create_http.start {|http|
         req = Net::HTTP::Report.new(@url, initheader = {'Content-Type'=>'application/xml'} )
-        req.basic_auth @user, @password
+        if not @authtype == 'digest'
+        	req.basic_auth @user, @password
+        else
+        	req.add_field 'Authorization', digestauth('REPORT')
+        end
         req.body = AgCalDAV::Request::ReportVTODO.new.to_xml
         res = http.request( req )
       }
@@ -219,29 +267,52 @@ module AgCalDAV
     end
 
     private
+    
+    def digestauth method
+		
+	    h = Net::HTTP.new @duri.host, @duri.port
+	    if @ssl
+	    	h.use_ssl = @ssl
+	    	h.verify_mode = OpenSSL::SSL::VERIFY_NONE
+	    end
+	    req = Net::HTTP::Get.new @duri.request_uri
+	    
+	    res = h.request req
+	    # res is a 401 response with a WWW-Authenticate header
+	    
+	    auth = @digest_auth.auth_header @duri, res['www-authenticate'], method
+	    
+    	return auth
+    end
+    
     def entry_with_uuid_exists? uuid
       res = nil
+      
       __create_http.start {|http|
         req = Net::HTTP::Get.new("#{@url}/#{uuid}.ics")
-        req.basic_auth @user, @password
+        if not @authtype == 'digest'
+        	req.basic_auth @user, @password
+        else
+        	req.add_field 'Authorization', digestauth('GET')
+        end
+        
         res = http.request( req )
-      }      
-      if res.body.empty?
-        return false
+      	
+      }
+      begin
+      	Icalendar.parse(res.body)
+      rescue
+      	return false
       else
-        return true
+      	return true
       end
     end
-
     def  errorhandling response   
       raise AuthenticationError if response.code.to_i == 401
       raise NotExistError if response.code.to_i == 410 
       raise APIError if response.code.to_i >= 500
     end
   end
-
-
-
 
 
   class AgCalDAVError < StandardError
