diff -u cadaver-0.22.2/libneon/ne_cookies.c cadaver-0.22.2-head/libneon/ne_cookies.c
--- cadaver-0.22.2/libneon/ne_cookies.c	Sun Sep 21 19:00:34 2003
+++ cadaver-0.22.2-head/libneon/ne_cookies.c	Thu Jul 14 19:33:20 2005
@@ -1,136 +1,752 @@
-/* 
-   Basic cookie support for neon
-   Copyright (C) 1999-2003, Joe Orton <joe@manyfish.co.uk>
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public
-   License as published by the Free Software Foundation; either
-   version 2 of the License, or (at your option) any later version.
-   
-   This library 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
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with this library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
-   MA 02111-1307, USA
-
-*/
-
-/* A nice demo of hooks, since it doesn't need any external
- * interface to muck with the stored states.
- */
-
-#include "config.h"
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
+#include "ne_cookies.h"
+#include <ne_private.h>
 
-#include <time.h>
+char *append( char *buf , const char *src , int grow , int *size ){
+	buf = ne_realloc( buf , *size + grow + 1 ) ;
+	memcpy( buf + *size , src , (int)grow ) ;
+	*size = *size + grow ;
+	buf[ *size ] = 0 ;
+	return buf ;
+}
 
-#include "ne_cookies.h"
+/* check if host match cookie's domain */
+int cookie_domain_match( char *domain , char *host ){
+	int s ;
+	char *ptr_host , *ptr_domain ;
+
+	if ( domain != 0 && host != 0 ){
+		ptr_host = host ;
+		ptr_domain = domain ;
+
+		/* if the domain attribute starts with dot, then ignore the dot so, for instance,
+			nytimes.com match .nytimes.com; this is not RFC like, but I think its ok
+			to be acceptable */
+		if ( *ptr_domain == '.' ){
+			ptr_domain++ ;
+		}
+
+		s = strlen( ptr_host ) - strlen( ptr_domain ) ;
+		/* if the cookie's domain is bigger than host, then this will never match; reject */
+		if ( s >= 0 ){
+			/* adjust host to the domain size */
+			ptr_host += s ;
+
+			if ( strcmp( ptr_domain , ptr_host ) == 0 ){
+				return 1 ;
+			}
+		}
+	}
+
+	return 0 ;
+}
+
+void cookie_response( jar *jar , char *host , char *uri ){
+    ne_buffer *header = ne_buffer_create() ;
+	int size ;
+	cookie *c ;
+	size = 0 ;
+
+	/* check using there rules:
+	   Domain Selection
+			The origin server's fully-qualified host name must domain-match
+			the Domain attribute of the cookie.
+
+	   Path Selection
+			The Path attribute of the cookie must match a prefix of the
+			request-URI.
+
+	   Max-Age Selection
+			Cookies that have expired should have been discarded and thus
+			are not forwarded to an origin server.
+	*/
+
+	c = jar->cookie ;
+	while( c != 0 ){
+		/* max-age/expires */
+		if ( c->expires == 0 || difftime( c->expires, time(0) ) > 0 ){
+			/* domain */
+			if ( c->domain == 0 || cookie_domain_match( c->domain , host ) ){
+				/* path */
+				if ( uri != 0 && strlen( uri ) >= strlen( c->path ) && strncmp( c->path , uri , strlen( uri ) ) ){
+					if ( header->used == 1 ){
+						ne_buffer_append( header , "Cookie: $Version=\"1\"; " , 22 ) ;
+					}
+					else{
+						ne_buffer_append( header , " ;" , 2 ) ;
+					}
+
+					ne_buffer_append( header , c->name , strlen( c->name ) ) ;
+					ne_buffer_append( header , "=" , 1 ) ;
+					ne_buffer_append( header , c->value , strlen( c->value ) ) ;
+
+					if ( c->path != 0 && c->request_path ){
+						ne_buffer_append( header , "; $Path=\"" , 9 ) ;
+						ne_buffer_append( header , c->path , strlen( c->path ) ) ;
+						ne_buffer_append( header , "\"" , 1 ) ;
+					}
+
+					if ( c->domain != 0 && c->request_domain ){
+						ne_buffer_append( header , "; $Domain=\"" , 11 ) ;
+						ne_buffer_append( header , c->domain , strlen( c->domain ) ) ;
+						ne_buffer_append( header , "\"" , 1 ) ;
+					}
+				}
+			}
+		}
+		c = (cookie *)c->next ;
+	}
+
+	if ( jar->response != 0 ){
+		ne_free( jar->response ) ;
+		jar->response = 0 ;
+	}
+
+	if ( header->used > 1 ){
+		ne_buffer_append( header , "\n" , 1 ) ;
+
+		jar->response = ne_malloc( header->used ) ;
+		strcpy( jar->response , header->data ) ;
+		jar->response[ header->used ] = 0 ;
+	}
+	ne_buffer_destroy( header ) ;
+}
+
+jar* ne_create_jar( void ){
+	jar *j ;
+	j = (jar *)ne_malloc( sizeof( jar ) ) ;
+	j->cookie = 0 ;
+	j->response = 0 ;
+	return j ;
+}
+
+void cookie_dump( cookie *c ){
+	if ( c->name ){
+		printf( "Name: %s\n" , c->name ) ;
+	}
+	if ( c->value ){
+		printf( "Value: %s\n" , c->value ) ;
+	}
+	if ( c->comment ){
+		printf( "Comment: %s\n" , c->comment ) ;
+	}
+	if ( c->path ){
+		printf( "Path: %s\n" , c->path ) ;
+	}
+	if ( c->domain ){
+		printf( "Domain: %s\n" , c->domain ) ;
+	}
+	if ( c->version ){
+		printf( "Version: %s\n" , c->version ) ;
+	}
+	if ( c->expires ){
+		printf( "Delta: %s\n" , ne_rfc1123_date( c->expires ) ) ;
+	}
+	if ( c->secure ){
+		printf( "Secure: yes\n" ) ;
+	}
+}
+
+void ne_remove_jar( jar *jar ){
+	cookie *c ;
+	c = jar->cookie ;
+	while ( c != 0 ){
+		c = ne_cookie_remove( c ) ;
+	}
+	if ( jar->response != 0 ){
+		ne_free( jar->response ) ;
+	}
+	ne_free( jar ) ;
+}
+
+/* remove a chain; return the next chain or prev if next doesnt exist or NULL if both doesnt exist */
+cookie *ne_cookie_remove( cookie *c ){
+	cookie *s_cookie , *prev , *next ;
+	if ( c != 0 ){
+		/* do not break the chain */
+		if ( c->prev != 0 ){
+			prev = (cookie *)c->prev ;
+			prev->next = (struct cookie *)c->next ;
+			s_cookie = (cookie *)c->prev ;
+		}
+
+		if ( c->next != 0 ){
+			next = (cookie *)c->next ;
+			next->prev = (struct cookie*)c->prev ;
+			s_cookie = (cookie *)c->next ;
+		}
+
+		s_cookie = (cookie *)c->next ;
+		if ( c->name ){
+			ne_free( c->name ) ;
+		}
+		if ( c->value ){
+			ne_free( c->value ) ;
+		}
+		if ( c->comment ){
+			ne_free( c->comment ) ;
+		}
+		if ( c->path ){
+			ne_free( c->path ) ;
+		}
+		if ( c->version ){
+			ne_free( c->version ) ;
+		}
+		if ( c->domain ){
+			ne_free( c->domain ) ;
+		}
+		ne_free( c ) ;
+	}
+	return s_cookie ;
+}
+
+int has_tspecials( char *s , int size ){
+	char *ptr = s ;
+	int i = size ;
+	while( i > 0 && s != 0 && strchr( "()<>@,;:\\\"/[]?={} \t" , *ptr++ ) == NULL ){
+		i-- ;
+	}
+	return i ;
+}
+
+int has_whitespace( char *s , int size ){
+	char *ptr = s ;
+	int i = size ;
+	while( i > 0 && s != 0 && strchr( " \t\r\n" , *ptr++ ) == NULL ){
+		i-- ;
+	}
+	return i ;
+}
+
+int ne_cookie_set_domain( cookie *c , char *value ){
+	char *ptr ;
+	char *phost ;
+	char *pre ;
+	int size ;
+
+	ptr = value ;
+
+	/* trim value */
+	while( *ptr != 0 && *ptr == ' ' ){
+		ptr++;
+	}
+
+	/* check if value starts with dot; discards if doesnt start  */
+	if ( *ptr != '.' ){
+		return 0 ;
+	}
+	else{
+		/* ignore first dot and the next char; excludes domains like "..com" */
+		ptr += 2 ;
+		/* check if theres an embeded dot */
+		while( *ptr != 0 ){
+			if ( *ptr == '.' ){
+				break ;
+			}
+			ptr++ ;
+		}
+
+		if ( *ptr == 0 ){
+			/* no dot found. discard cookie */
+			return 0 ;
+		}
+		else{
+			/* discard domains like ".com." */
+			if ( *(ptr + 1 ) == 0 ){
+				return 0 ;
+			}
+
+			/* check these conditions:
+				Reject if the value for the request-host does not
+					domain-match the Domain attribute.
+
+				Reject if the request-host is a FQDN (not IP address) and has
+					the form HD, where D is the value of the Domain attribute,
+					and H is a string that contains one or more dots
+	       */
+			if ( c->host != 0 ){
+				ptr = value ; /* restart domain value */
+				/* trim value */
+				while( *ptr != 0 && *ptr == ' ' ){
+					ptr++;
+				}
+
+				/* compare domain value with host */
+				phost = c->host ;
+				if ( strlen( ptr ) > strlen( phost ) ){
+					/* If domain is bigger than host, the only exception acceptable is when:
+						Domain: .a.com
+						Host: a.com
+
+						Then, variable pre should have size 1 and be a dot.
+					*/
+
+					size = strlen( ptr ) - strlen( phost ) ;
+					if ( *ptr != '.' || size != 1 ){
+						/* discard cookie */
+						return 0 ;
+					}
+					ptr += size ;
+				}
+				else{
+					size = strlen( phost ) - strlen( ptr ) ;
+					pre = phost ;
+					phost += size ;
+
+					/* pre should have the difference from host and domain; this difference
+						should not have dots.
+
+						Example:
+						Domain: .b.com
+						Host: a.b.com
+
+						Difference is "a". "a" has no dots. The domain is acceptable
+
+						Another:
+						Domain: .c.com
+						Host: a.b.c.com
+
+						Difference is "a.b". "a.b" has dots. The domain is not acceptable
+
+					*/
+					for ( ; size > 0 ; size-- ){
+						if ( *( pre + size ) == '.' ){
+							return 0 ;
+						}
+					}
+				}
+
+				/* Host and domain should match; otherwise, the cookie is not acceptable */
+				if ( strcmp( phost , ptr ) != 0 ){
+					return 0 ;
+				}
+			}
+			return 1 ;
+		}
+	}
+}
+
+/*  Check if header has a valid cookie name; return the number of bytes read from header  */
+int ne_cookie_set_name( cookie *c , char* header ){
+	char *ptr ;
+	int i , j ;
+	j = 0 ;
+
+	if ( c != 0 && header != 0 ){
+		/* strip leading whitespace until find the cookie name */
+		while( *header != 0 && *header == ' ' ){
+			header++ ;
+			j++ ;
+		}
+
+		/* anything left */
+		if ( header != 0 ){
+			ptr = index( header , '=' ) ;
+
+			/* Okie; try to set the name atribute */
+			if ( ptr != 0 ){
+				i = ( ptr - header ) ;
+				c->name = (char *)ne_malloc( i + 1 ) ;
+				strncpy( c->name , header , i ) ;
+				c->name[ i ] = 0 ;
+
+				/* check if the cookie name is valid; if not, null cookie name and return false */
+				if ( !has_whitespace( c->name , i ) && !has_tspecials( c->name , i ) ){
+					return i + j + 1 ;
+				}
+
+				ne_free( c->name ) ;
+				c->name = 0 ;
+			}
+		}
+	}
+	return 0 ;
+}
+
+/* check if the header has a cookie value; return the number of bytes read from header */
+int ne_cookie_set_value( cookie *c , char *header ){
+	char *ptr ;
+	int i , j ;
+	j = 0 ;
+
+	if ( c != 0 && header != 0 ){
+		/* strip leading whitespace until find the cookie value */
+		while( *header != 0 && *header == ' ' ){
+			header++;
+			j++ ;
+		}
+
+		if ( header != 0 ){
+			ptr = index( header , ';' ) ;
+			if ( ptr == 0 ){
+				/* oops, if theres no ';', then, try to find eof */
+				ptr = index( header , '\0' ) ;
+			}
+
+			if ( ptr != 0 ){
+				i = ptr - header ;
+				c->value = (char *)ne_malloc( i + 1 ) ;
+				/* cookie value is opaque, so we don't do any consistency check here */
+				strncpy( c->value , header , i ) ;
+				c->value[ i ] = 0 ;
+				header = ptr ;
+				return i + j ;
+			}
+		}
+	}
+	return 0 ;
+}
+
+/* add a cookie to the end of chain */
+cookie *ne_cookie_add( cookie *c ){
+	cookie *next ;
+	if ( c != 0 ){
+		while( c->next != 0 ){
+			c = (cookie *)c->next ;
+		}
+		c->next = (struct cookie *)ne_malloc( sizeof( cookie ) ) ;
+
+		next = (cookie *)c->next ;
+		next->prev = (struct cookie *)c ;
+		c = (cookie *)c->next ;
+	}
+	else{
+		c = (cookie *)ne_malloc( sizeof( cookie ) ) ;
+		c->prev = 0 ;
+	}
+	c->next = 0 ;
+	c->path = 0 ;
+	c->domain = 0 ;
+	c->expires = 0 ;
+	c->comment = 0 ;
+	c->version = 0 ;
+	c->request_path = 1 ;
+	c->request_domain = 1 ;
+	return c ;
+}
+
+int is_cookie_header( char *h ){
+	/* search for header name; get everything before double colon */
+	char *ptr , *buf ;
+	int i ;
+	ptr = index( h , ':' ) ;
+
+	if ( ptr != 0 ){
+		i = ptr - h ;
+		buf = (char *)calloc( 1 , i ) ;
+		strncpy( buf , h , i ) ;
+		/* be nice to server sending set-cookie directive with trailling whitespaces */
+		ptr = ne_shave( buf , " \t\r\n" ) ;
+		i = strcasecmp( ptr , "set-cookie" ) ;
+		ne_free( buf ) ;
+		if ( i == 0 ){
+			return 1 ;
+		}
+	}
+	return 0 ;
+}
+
+int search_cookie_attributes( cookie *c , char *header ){
+	char *ptr , *value , *name ;
+	int size ;
+	ptr = 0 ;
+
+	do{
+		name = 0 ; value = 0 ;
+		/* remove leading whitespace */
+		while( *header != 0 && *header == ' ' ){
+			header++;
+		}
+
+		/* search for '=' to bound the attribute name */
+		ptr = index( header , '=' ) ;
+
+		if ( ptr == 0 ){
+			/* if '=' doesnt exist, then search for ';' (end of attr)*/
+			ptr = index( header , ';' ) ;
+			if ( ptr == 0 ){
+				/* if theres ';', then search for eof */
+				ptr = index( header , '\0' ) ;
+				if ( ptr == 0 ){
+					/* if theres no eof, then discard cookie */
+					return 0 ;
+				}
+			}
+		}
+		size = ptr - header ;
+
+		/* check if I have a non empty attribute name; */
+		if ( size > 0 ){
+			name = (char *)ne_malloc( size + 1 ) ;
+			strncpy( name , header , size ) ;
+			name[ size ] = 0 ;
+			header = ++ptr ;
+
+			/* parsing value */
+			/* theres value only if a '=' was match */
+			if ( *( ptr - 1 ) == '=' ){
+				/* Ok, it's safe to parse a value */
+
+				ptr = index( header , ';' ) ;
+				if ( ptr == 0 ){
+					ptr = index( header , '\0' ) ;
+					if ( ptr == 0 ){
+						/* strange things happens all the time... discard cookie */
+						ne_free( name ) ;
+						return 0 ;
+					}
+				}
+
+				size = ptr - header ;
+				value = (char *)ne_malloc( size + 1 ) ;
+				strncpy( value , header , size ) ;
+				value[ size ] = 0 ;
+				header = ++ptr ;
+			}
+
+			if ( strcasecmp( name , "path" ) == 0 && value != 0 ){
+				c->path = value ;
+			}
+			else if ( strcasecmp( name , "max-age" ) == 0 && value != 0 ){
+				int i = atoi( value ) ;
+				c->expires = time(0) + (time_t)i ;
+				ne_free( value ) ;
+			}
+			else if ( strcasecmp( name , "expires" ) == 0 && value != 0 ){
+				c->expires = ne_rfc1123_parse( value ) ;
+				ne_free( value ) ;
+			}
+			else if ( strcasecmp( name , "comment" ) == 0 && value != 0 ){
+				c->comment = value ;
+			}
+			else if ( strcasecmp( name , "version" ) == 0 && value != 0 ){
+				c->version = value ;
+			}
+			else if ( strcasecmp( name , "domain" ) == 0 && value != 0 ){
+				/* check if is a valid domain name */
+				if ( ne_cookie_set_domain( c , value ) == 0 ){
+					ne_free( value ) ;
+					ne_free( name ) ;
+					return 0 ;
+				}
+				else{
+					c->domain = value ;
+				}
+			}
+			else if ( strcasecmp( name , "secure" ) == 0 && value == 0 ){
+				c->secure = 1 ;
+			}
+			else{
+				if ( value != 0 ){
+					ne_free( value ) ;
+				}
+			}
+			ne_free( name ) ;
+
+			/* if theres nothing else to read */
+			if ( strlen( header ) == 0 ){
+				break ;
+			}
+		}
+		else{
+			/* add on step and see if theres is anything left */
+			ptr++ ;
+		}
+
+		/* finish this */
+		if ( ptr != 0 && *ptr == 0 ){
+			ptr = 0 ;
+		}
+	} while( ptr != 0 ) ;
+	return 1 ;
+}
+
+/* receives cookie header; should parse data and add a new cookie if the cookie not exists */
+/* jar is necessary to see if the cookie already exists (sess->server.hostname) */
+void parse_ne_cookie( jar *jar , char *host , char *uri , char *h ){
+	char *ptr ;
+	int i ;
+	cookie *c , *buf ;
+	c = 0 ;
+
+	/* create an isolated cookie */
+	c = ne_cookie_add( c ) ;
+	ptr = h ;
+
+//	/* if reaches here, then presume the header name is valid and go fot the first double colon  */
+//	ptr = index( h , ':' ) ;
+//	if ( ptr == 0 ){
+//		return ;
+//	}
+//	ptr++ ; /* ignore double colon */
+
+	/* use hostname from session; should use this information to check if cookie domain
+		was set correctly and to check cookie dups */
+	if ( host != 0 && uri != 0 ){
+		c->host = host ;
+	}
+	else{
+		/* if session doesn't have a hostname, then discard cookie */
+		return ;
+	}
 
-#include "ne_request.h"
-#include "ne_string.h"
-#include "ne_alloc.h"
-
-#define COOKIE_ID "http://www.webdav.org/neon/hooks/cookies"
-
-static void set_cookie_hdl(void *userdata, const char *value)
-{
-    char **pairs = pair_string(value, ';', '=', "\"'", " \r\n\t");
-    ne_cookie *cook;
-    ne_cookie_cache *cache = userdata;
-    int n;
-
-    /* Check sanity */
-    if (pairs[0] == NULL || pairs[1] == NULL) {
-	/* yagaboo */
-	return;
-    }
-
-    NE_DEBUG(NE_DBG_HTTP, "Got cookie name=%s\n", pairs[0]);
-
-    /* Search for a cookie of this name */
-    NE_DEBUG(NE_DBG_HTTP, "Searching for existing cookie...\n");
-    for (cook = cache->cookies; cook != NULL; cook = cook->next) {
-	if (strcasecmp(cook->name, pairs[0]) == 0) {
-	    break;
-	}
-    }
-    
-    if (cook == NULL) {
-	NE_DEBUG(NE_DBG_HTTP, "New cookie.\n");
-	cook = ne_malloc(sizeof *cook);
-	memset(cook, 0, sizeof *cook);
-	cook->name = ne_strdup(ne_shave(pairs[0], " \t\r\n"));
-	cook->next = cache->cookies;
-	cache->cookies = cook;
-    } else {
-	/* Free the old value */
-	ne_free(cook->value);
-    }
-
-    cook->value = ne_strdup(ne_shave(pairs[1], " \t\r\n"));
-
-    for (n = 2; pairs[n] != NULL; n+=2) {
-        if (!pairs[n+1]) continue;
-	NE_DEBUG(NE_DBG_HTTP, "Cookie parm %s=%s\n", pairs[n], pairs[n+1]);
-	if (strcasecmp(pairs[n], "path") == 0) {
-	    cook->path = ne_strdup(pairs[n+1]);
-	} else if (strcasecmp(pairs[n], "max-age") == 0) {
-	    int t = atoi(pairs[n+1]);
-	    cook->expiry = time(NULL) + (time_t)t;
-	} else if (strcasecmp(pairs[n], "domain") == 0) {
-	    cook->domain = ne_strdup(pairs[n+1]);
-	}
-    }
-
-    NE_DEBUG(NE_DBG_HTTP, "End of parms.\n");
-
-    pair_string_free(pairs);
-}
-
-static void create(ne_request *req, void *session,
-		   const char *method, const char *uri)
-{
-    ne_cookie_cache *cache = session;
-    ne_add_response_header_handler(req, "Set-Cookie", set_cookie_hdl, cache);
-}
-
-/* Just before sending the request: let them add headers if they want */
-static void pre_send(ne_request *req, void *session, ne_buffer *request)
-{
-    ne_cookie_cache *cache = session;
-    ne_cookie *cook;
-    
-    if (cache->cookies == NULL) {
-	return;
-    }
-    
-    ne_buffer_zappend(request, "Cookie: ");
-
-    for (cook = cache->cookies; cook != NULL; cook=cook->next) {
-	ne_buffer_concat(request, cook->name, "=", cook->value, NULL);
-	if (cook->next != NULL) {
-	    ne_buffer_zappend(request, "; ");
-	}
-    }
-    
-    ne_buffer_zappend(request, "\r\n");
-}
-
-/* Register cookie handling for given session using given cache. */
-void ne_cookie_register(ne_session *sess, ne_cookie_cache *cache)
-{
-    ne_hook_create_request(sess, create, cache);
-    ne_hook_pre_send(sess, pre_send, cache);
+	i = ne_cookie_set_name( c , ptr ) ;
+	if ( i == 0 ){
+		return ;
+	}
+	ptr += i ;
+
+	i = ne_cookie_set_value( c , ptr ) ;
+	if ( i == 0 ){
+		/* no value, and value is required */
+		return ;
+	}
+	ptr += i + 1 ;
+
+	/* search for other values (version, comment, domain, max-age, path, secure, expires) */
+	if ( search_cookie_attributes( c , ptr ) == 0 ){
+		/* ooops, search found something wrong with this cookie */
+		ne_cookie_remove( c ) ;
+		c = 0 ;
+	}
+
+	/* if domain not specified, then defaults to request-host */
+	if ( c != 0 && c->domain == 0 ){
+		i = strlen( c->host ) ;
+		c->domain = (char *)ne_malloc( i + 1 ) ;
+		strcpy( c->domain , c->host ) ;
+		c->domain[ i ] = 0 ;
+		c->request_domain = 0 ;
+	}
+
+	/* if path not specified, then defaults to request-uri but
+		not including, the right-most '/' */
+	if ( c != 0 && c->path == 0 && uri != 0 ){
+		i = strlen( uri ) ;
+		if ( uri[ i - 1 ] == '/' ){
+			i-- ;
+		}
+		c->path = (char *)ne_malloc( i + 1 ) ;
+		strncpy( c->path , uri , i ) ;
+		c->path[ i ] = 0 ;
+		c->request_path = 0 ;
+	}
+
+	/* if cookie doesnt exist then add to jar */
+	if ( c != 0 && ne_cookie_exists( jar , c ) == 0 ){
+		/* add to jar */
+		if ( jar->cookie == 0 ){
+			jar->cookie = (cookie *)c ;
+		}
+		else{
+			buf = (cookie *)jar->cookie ;
+			while( buf->next != 0 ){
+				buf = (cookie*)buf->next ;
+			}
+			c->prev = (struct cookie *)buf ;
+			buf->next = (struct cookie *)c ;
+		}
+	}
 }
+
+void ne_cookie_replace( cookie *old_cookie , cookie *new_cookie ){
+	cookie *buf ;
+
+	if ( old_cookie != 0 && new_cookie != 0 ){
+		new_cookie->prev = old_cookie->prev ;
+		new_cookie->next = old_cookie->next ;
+
+		buf = (cookie *)new_cookie->prev ;
+		if ( buf != 0 ){
+			buf->next = (struct cookie *)new_cookie ;
+		}
+		buf = (cookie *)new_cookie->next ;
+		if ( buf != 0 ){
+			buf->prev = (struct cookie *)new_cookie ;
+		}
+
+		old_cookie->prev = 0 ;
+		old_cookie->next = 0 ;
+		ne_cookie_remove( old_cookie ) ;
+	}
+}
+
+
+/* check in cookie jar if theres a cookie with the same name and same host and same path */
+int ne_cookie_exists( jar *jar , cookie *c ){
+	cookie *chain ;
+	chain = (cookie *)jar->cookie ;
+
+	while( chain != 0 ){
+		/* check if name, path, domain and host are equals, if so, then replace the cookie */
+		if ( strcasecmp( c->name , chain->name ) == 0 &&
+			( ( c->path != 0 && chain->path != 0 && strcasecmp( c->path , chain->path ) == 0 ) || ( c->path == 0 && chain->path == 0 ) ) &&
+			( ( c->host != 0 && chain->host != 0 && strcasecmp( c->host , chain->host ) == 0 ) || ( c->host == 0 && chain->host == 0 ) ) &&
+			( ( c->domain != 0 && chain->domain != 0 && strcasecmp( c->domain , chain->domain ) == 0 ) || ( c->domain == 0 && chain->domain == 0 ) )
+		){
+			/* replace old cookie by new cookie */
+			ne_cookie_replace( chain , c ) ;
+
+			/* move first and reset jar->cookie */
+			while( c->prev != 0 ){
+				c = (cookie *)c->prev ;
+			}
+
+			jar->cookie = (cookie *)c ;
+			return 1 ;
+		}
+		chain = (cookie *)chain->next ;
+	}
+	return 0 ;
+}
+
+
+// int main( void ){
+// 	/* sounds strange.. */
+// 	jar *jar ;
+// 	cookie *c ;
+// 	/* for debugging purposes will not use dynamic allocation */
+// 	char header[MAX_COOKIE_DATA_LENGTH] ;
+// 	int i ;
+//
+// 	c = 0 ;
+// 	jar = ne_create_jar() ;
+//
+// 	while( 1 ){
+// 		memset( header , 0 , strlen( header ) ) ;
+// 		fgets( header , 256 , stdin ) ;
+//
+// 		if ( *header == '\n' ){
+// 			break ;
+// 		}
+// 		else{
+// 			if ( is_cookie_header( header ) ){
+// 				/* Ok, this is a cookie header; let's parse the content */
+// 				parse_ne_cookie( jar , header ) ;
+// 			}
+// 		}
+// 	}
+//
+// 	i = 1 ;
+// 	while( 1 ){
+// 		cookie_response( jar ) ;
+// 		if ( jar->response != 0 ){
+// 			printf( "%s\n" , jar->response ) ;
+// 		}
+//
+// 		if ( i % 100 == 0 ){
+// 			getchar() ;
+// 		}
+// 		i++ ;
+// 	}
+//
+// //	if ( jar != 0 ){
+// //		/* move first */
+// //		c = (cookie *)jar->cookie ;
+// //		while ( c != 0 ){
+// //			cookie_dump( c ) ;
+// //			c = (cookie *)c->next ;
+// //		}
+// //	}
+// 	return 1 ;
+// }
 
diff -u cadaver-0.22.2/libneon/ne_cookies.h cadaver-0.22.2-head/libneon/ne_cookies.h
--- cadaver-0.22.2/libneon/ne_cookies.h	Thu Jan  3 12:24:17 2002
+++ cadaver-0.22.2-head/libneon/ne_cookies.h	Thu Jul 14 18:16:04 2005
@@ -1,51 +1,78 @@
-/* 
-   HTTP Request Handling
-   Copyright (C) 1999-2002, Joe Orton <joe@manyfish.co.uk>
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public
-   License as published by the Free Software Foundation; either
-   version 2 of the License, or (at your option) any later version.
-   
-   This library 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
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with this library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
-   MA 02111-1307, USA
-
-*/
-
-#ifndef NE_COOKIES_H
-#define NE_COOKIES_H
-
-#include "ne_request.h"
-#include "ne_defs.h"
-
-BEGIN_NEON_DECLS
-
-struct ne_cookie_s;
-typedef struct ne_cookie_s ne_cookie;
-
-struct ne_cookie_s {
-    char *name, *value;
-    unsigned int secure:1;
-    unsigned int discard:1;
-    char *domain, *path;
-    time_t expiry; /* time at which the cookie expires */
-    ne_cookie *next;
-};
+#ifndef COOKIES_H
+#define COOKIES_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include "ne_alloc.h"
+#include "ne_string.h"
+#include "ne_dates.h"
+#include "ne_alloc.h"
 
-typedef struct {
-    ne_cookie *cookies;
-} ne_cookie_cache;
 
-/* Register cookie handling for given session using given cache. */
-void ne_cookie_register(ne_session *sess, ne_cookie_cache *cache);
+#define MAX_COOKIE_DATA_LENGTH 4096
 
-END_NEON_DECLS
+typedef struct {
+	char *name ;
+	char *value ;
+	char *comment ;
+	char *path ;
+	char *version ;
+	char *domain ;
+	time_t expires ;
+	unsigned int secure:1;
+
+	/*	point to hostname from ne_session;
+		used to check if cookie domain is valid and to
+		avoid cookie dups; */
+	char *host ;
+
+	/* these flags indicate if the request cookie header should use domain and
+		path attributes. Excerpt from rfc 2109
+
+		The value for the path attribute must be the value
+		from the Path attribute, if any, of the
+		corresponding Set-Cookie response header.
+		Otherwise the attribute should be omitted from the
+		Cookie request header.  The value for the domain
+		attribute must be the value from the Domain
+		attribute, if any, of the corresponding Set-Cookie
+		response header. Otherwise the attribute should be
+		omitted from the Cookie request header.
+	*/
+	unsigned int request_domain:1;
+	unsigned int request_path:1;
+
+	struct cookie *next ;
+	struct cookie *prev ;
+} cookie ;
+
+typedef struct{
+	cookie *cookie ;
+
+	/* buffer used to store the cookie's response header; freed on jar remove */
+	char *response ;
+
+} jar ;
+
+jar *ne_create_jar( void ) ;
+void ne_remove_jar( jar *jar ) ;
+cookie *ne_cookie_add( cookie * c ) ;
+cookie *ne_cookie_remove( cookie *c ) ;
+void parse_ne_cookie( jar *c , char *host , char *uri , char *h ) ;
+int ne_cookie_set_name( cookie *c , char* name ) ;
+int ne_cookie_set_value( cookie *c , char *name ) ;
+int ne_cookie_set_domain( cookie *c , char *value ) ;
+int ne_cookie_exists( jar *jar , cookie *c ) ;
+void ne_cookie_replace( cookie *old_cookie , cookie *new_cookie ) ;
+int is_cookie_header( char *h ) ;
+int has_whitespace( char *s , int size );
+int has_tspecials( char *s , int size );
+int search_cookie_attributes( cookie *c , char *header ) ;
+void cookie_dump( cookie *c ) ;
+void cookie_response( jar *jar , char *host, char *uri ) ;
+char *append( char *buf , const char *src , int grow , int *size );
+int cookie_domain_match( char *domain , char *host ) ;
 
-#endif /* NE_COOKIES_H */
+#endif /* COOKIES_H */
diff -u cadaver-0.22.2/libneon/ne_private.h cadaver-0.22.2-head/libneon/ne_private.h
--- cadaver-0.22.2/libneon/ne_private.h	Thu Sep  4 17:37:14 2003
+++ cadaver-0.22.2-head/libneon/ne_private.h	Thu Jul 14 17:20:01 2005
@@ -28,6 +28,7 @@
 #include "ne_request.h"
 #include "ne_socket.h"
 #include "ne_ssl.h"
+#include "ne_cookies.h"
 
 struct host_info {
     char *hostname;
@@ -87,6 +88,9 @@
     struct hook *destroy_req_hooks, *destroy_sess_hooks, *private;
 
     char *user_agent; /* full User-Agent: header field */
+
+    /* 11/07/2005 18:53 - fnemec */
+    jar *jar ;
 
 #ifdef NEON_SSL
     ne_ssl_client_cert *client_cert;
diff -u cadaver-0.22.2/libneon/ne_request.c cadaver-0.22.2-head/libneon/ne_request.c
--- cadaver-0.22.2/libneon/ne_request.c	Thu Nov 13 18:39:23 2003
+++ cadaver-0.22.2-head/libneon/ne_request.c	Thu Jul 14 17:20:01 2005
@@ -492,6 +492,12 @@
     }
 }
 
+/* Handler for the "Cookie" response header */
+static void cookie_hdr_handler(void *userdata, const char *value){
+    ne_request *req = userdata;
+    parse_ne_cookie( req->session->jar , req->session->server.hostname , req->uri , (char *)value ) ;
+}
+
 ne_request *ne_request_create(ne_session *sess,
 			      const char *method, const char *path) 
 {
@@ -516,6 +522,8 @@
 				   te_hdr_handler, &req->resp);
     ne_add_response_header_handler(req, "Connection", 
 				   connection_hdr_handler, req);
+    ne_add_response_header_handler(req, "Set-Cookie",
+				   cookie_hdr_handler, req);
 
     /* Only use an absoluteURI here when absolutely necessary: some
      * servers can't parse them. */
@@ -825,6 +833,12 @@
     
     /* Add custom headers: */
     ne_buffer_append(buf, req->headers->data, ne_buffer_size(req->headers));
+    cookie_response( req->session->jar , req->session->server.hostname , req->uri ) ;
+    /* 11/07/2005 20:18 - fnemec */
+    if ( req->session->jar->response ){
+	    ne_buffer_append(buf , req->session->jar->response , strlen(req->session->jar->response));
+    }
+
 
 #define E100 "Expect: 100-continue" EOL
     if (req->use_expect100)
diff -u cadaver-0.22.2/libneon/ne_session.c cadaver-0.22.2-head/libneon/ne_session.c
--- cadaver-0.22.2/libneon/ne_session.c	Thu Sep  4 17:37:14 2003
+++ cadaver-0.22.2-head/libneon/ne_session.c	Thu Jul 14 17:20:01 2005
@@ -40,6 +40,7 @@
 #include "ne_string.h"
 
 #include "ne_private.h"
+#include "ne_cookies.h"
 
 /* Destroy a a list of hooks. */
 static void destroy_hooks(struct hook *hooks)
@@ -95,6 +96,11 @@
         ne_ssl_clicert_free(sess->client_cert);
 #endif
 
+    /* 11/07/2005 18:53 - fnemec */
+	if (sess->jar){
+		ne_remove_jar( sess->jar ) ;
+	}
+
     ne_free(sess);
 }
 
@@ -146,6 +152,8 @@
 #endif
 
     sess->scheme = ne_strdup(scheme);
+    /* 11/07/2005 18:53 - fnemec */
+    sess->jar = ne_create_jar() ;
 
     /* Default expect-100 to OFF. */
     sess->expect100_works = -1;
