* released 1.1.18
* Haproxy can be compiled with PCRE regex instead of libc regex, by setting
  REGEX=pcre on the make command line.
* HTTP health-checks now use "OPTIONS *" instead of "OPTIONS /".
* when explicit source address binding is required, it is now also used for
  health-checks.
* added 'reqpass' and 'reqipass' to allow certain headers but not the request
  itself.
* factored several strings to reduce binary size by about 2 kB.
* replaced setreuid() and setregid() with more standard setuid() and setgid().
* added 4 status flags to the log line indicating who ended the connection
  first, the sessions state, the validity of the cookie, and action taken on
  the set-cookie header.
* rearranged the changelog and removed it from haproxy.c
* large documentation updates
diff --git a/haproxy.c b/haproxy.c
index e343460..42e9e87 100644
--- a/haproxy.c
+++ b/haproxy.c
@@ -1,6 +1,6 @@
 /*
  * HA-Proxy : High Availability-enabled HTTP/TCP proxy
- * 2000-2002 - Willy Tarreau - willy AT meta-x DOT org.
+ * 2000-2003 - Willy Tarreau - willy AT meta-x DOT org.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -15,151 +15,7 @@
  *     related to missing setsid() (fixed in 1.1.15)
  *   - a proxy with an invalid config will prevent the startup even if disabled.
  *
- * ChangeLog :
- *
- * 2002/10/18 : 1.1.17
- *   - add the notion of "backup" servers, which are used only when all other
- *     servers are down.
- *   - make Set-Cookie return "" instead of "(null)" when the server has no
- *     cookie assigned (useful for backup servers).
- *   - "log" now supports an optionnal level name (info, notice, err ...) above
- *     which nothing is sent.
- *   - replaced some strncmp() with memcmp() for better efficiency.
- *   - added "capture cookie" option which logs client and/or server cookies
- *   - cleaned up/down messages and dump servers states upon SIGHUP
- *   - added a redirection feature for errors : "errorloc <errnum> <url>"
- *   - now we won't insist on connecting to a dead server, even with a cookie,
- *     unless option "persist" is specified.
- *   - added HTTP/408 response for client request time-out and HTTP/50[234] for
- *     server reply time-out or errors.
- * 2002/09/01 : 1.1.16
- *   - implement HTTP health checks when option "httpchk" is specified.
- * 2002/08/07 : 1.1.15
- *   - replaced setpgid()/setpgrp() with setsid() for better portability, because
- *     setpgrp() doesn't have the same meaning under Solaris, Linux, and OpenBSD.
- * 2002/07/20 : 1.1.14
- *   - added "postonly" cookie mode
- * 2002/07/15 : 1.1.13
- *   - tv_diff used inverted parameters which led to negative times !
- * 2002/07/13 : 1.1.12
- *   - fixed stats monitoring, and optimized some tv_* for most common cases.
- *   - replaced temporary 'newhdr' with 'trash' to reduce stack size
- *   - made HTTP errors more HTML-fiendly.
- *   - renamed strlcpy() to strlcpy2() because of a slightly difference between
- *     their behaviour (return value), to avoid confusion.
- *   - restricted HTTP messages to HTTP proxies only
- *   - added a 502 message when the connection has been refused by the server,
- *     to prevent clients from believing this is a zero-byte HTTP 0.9 reply.
- *   - changed 'Cache-control:' from 'no-cache="set-cookie"' to 'private' when
- *     inserting a cookie, because some caches (apache) don't understand it.
- *   - fixed processing of server headers when client is in SHUTR state
- * 2002/07/04 :
- *   - automatically close fd's 0,1 and 2 when going daemon ; setpgrp() after
- *     setpgid()
- * 2002/06/04 : 1.1.11
- *   - fixed multi-cookie handling in client request to allow clean deletion
- *     in insert+indirect mode. Now, only the server cookie is deleted and not
- *     all the header. Should now be compliant to RFC2109.
- *   - added a "nocache" option to "cookie" to specify that we explicitly want
- *     to add a "cache-control" header when we add a cookie.
- *     It is also possible to add an "Expires: <old-date>" to keep compatibility
- *     with old/broken caches.
- * 2002/05/10 : 1.1.10
- *   - if a cookie is used in insert+indirect mode, it's desirable that the
- *     the servers don't see it. It was not possible to remove it correctly
- *     with regexps, so now it's removed automatically.
- * 2002/04/19 : 1.1.9
- *   - don't use snprintf()'s return value as an end of message since it may
- *     be larger. This caused bus errors and segfaults in internal libc's
- *     getenv() during localtime() in send_log().
- *   - removed dead insecure send_syslog() function and all references to it.
- *   - fixed warnings on Solaris due to buggy implementation of isXXXX().
- * 2002/04/18 : 1.1.8
- *   - option "dontlognull"
- *   - fixed "double space" bug in config parser
- *   - fixed an uninitialized server field in case of dispatch
- *     with no existing server which could cause a segfault during
- *     logging.
- *   - the pid logged was always the father's, which was wrong for daemons.
- *   - fixed wrong level "LOG_INFO" for message "proxy started".
- * 2002/04/13 :
- *   - http logging is now complete :
- *     - ip:port, date, proxy, server
- *     - req_time, conn_time, hdr_time, tot_time
- *     - status, size, request
- *   - source address
- * 2002/04/12 : 1.1.7
- *   - added option forwardfor
- *   - added reqirep, reqidel, reqiallow, reqideny, rspirep, rspidel
- *   - added "log global" in "listen" section.
- * 2002/04/09 :
- *   - added a new "global" section :
- *     - logs
- *     - debug, quiet, daemon modes
- *     - uid, gid, chroot, nbproc, maxconn
- * 2002/04/08 : 1.1.6
- *   - regex are now chained and not limited anymore.
- *   - unavailable server now returns HTTP/502.
- *   - increased per-line args limit to 40
- *   - added reqallow/reqdeny to block some request on matches
- *   - added HTTP 400/403 responses
- * 2002/04/03 : 1.1.5
- *   - connection logging displayed incorrect source address.
- *   - added proxy start/stop and server up/down log events.
- *   - replaced log message short buffers with larger trash.
- *   - enlarged buffer to 8 kB and replace buffer to 4 kB.
- * 2002/03/25 : 1.1.4
- *   - made rise/fall/interval time configurable
- * 2002/03/22 : 1.1.3
- *   - fixed a bug : cr_expire and cw_expire were inverted in CL_STSHUT[WR]
- *     which could lead to loops.
- * 2002/03/21 : 1.1.2
- *   - fixed a bug in buffer management where we could have a loop
- *     between event_read() and process_{cli|srv} if R==BUFSIZE-MAXREWRITE.
- *     => implemented an adjustable buffer limit.
- *   - fixed a bug : expiration of tasks in wait queue timeout is used again,
- *     and running tasks are skipped.
- *   - added some debug lines for accept events.
- *   - send warnings for servers up/down.
- * 2002/03/12 : 1.1.1
- *   - fixed a bug in total failure handling
- *   - fixed a bug in timestamp comparison within same second (tv_cmp_ms)
- * 2002/03/10 : 1.1.0
- *   - fixed a few timeout bugs
- *   - rearranged the task scheduler subsystem to improve performance,
- *     add new tasks, and make it easier to later port to librt ;
- *   - allow multiple accept() for one select() wake up ;
- *   - implemented internal load balancing with basic health-check ;
- *   - cookie insertion and header add/replace/delete, with better strings
- *     support.
- * 2002/03/08
- *   - reworked buffer handling to fix a few rewrite bugs, and
- *     improve overall performance.
- *   - implement the "purge" option to delete server cookies in direct mode.
- * 2002/03/07
- *   - fixed some error cases where the maxfd was not decreased.
- * 2002/02/26
- *   - now supports transparent proxying, at least on linux 2.4.
- * 2002/02/12
- *   - soft stop works again (fixed select timeout computation).
- *   - it seems that TCP proxies sometimes cannot timeout.
- *   - added a "quiet" mode.
- *   - enforce file descriptor limitation on socket() and accept().
- * 2001/12/30 : release of version 1.0.2 : fixed a bug in header processing
- * 2001/12/19 : release of version 1.0.1 : no MSG_NOSIGNAL on solaris
- * 2001/12/16 : release of version 1.0.0.
- * 2001/12/16 : added syslog capability for each accepted connection.
- * 2001/11/19 : corrected premature end of files and occasional SIGPIPE.
- * 2001/10/31 : added health-check type servers (mode health) which replies OK then closes.
- * 2001/10/30 : added the ability to support standard TCP proxies and HTTP proxies
- * 		with or without cookies (use keyword http for this).
- * 2001/09/01 : added client/server header replacing with regexps.
- * 		eg:
- *			cliexp ^(Host:\ [^:]*).* Host:\ \1:80
- *			srvexp ^Server:\ .* Server:\ Apache
- * 2000/11/29 : first fully working release with complete FSMs and timeouts.
- * 2000/11/28 : major rewrite
- * 2000/11/26 : first write
+ * ChangeLog has moved to the CHANGELOG file.
  *
  * TODO:
  *   - handle properly intermediate incomplete server headers. Done ?
@@ -191,8 +47,8 @@
 #include <linux/netfilter_ipv4.h>
 #endif
 
-#define HAPROXY_VERSION "1.1.17"
-#define HAPROXY_DATE	"2002/10/18"
+#define HAPROXY_VERSION "1.1.18"
+#define HAPROXY_DATE	"2003/04/02"
 
 /* this is for libc5 for example */
 #ifndef TCP_NODELAY
@@ -364,12 +220,43 @@
 
 
 /* various session flags */
-#define SN_DIRECT	1	/* connection made on the server matching the client cookie */
-#define SN_CLDENY	2	/* a client header matches a deny regex */
-#define SN_CLALLOW	4	/* a client header matches an allow regex */
-#define SN_SVDENY	8	/* a server header matches a deny regex */
-#define SN_SVALLOW	16	/* a server header matches an allow regex */
-#define	SN_POST		32	/* the request was an HTTP POST */
+#define SN_DIRECT	0x00000001	/* connection made on the server matching the client cookie */
+#define SN_CLDENY	0x00000002	/* a client header matches a deny regex */
+#define SN_CLALLOW	0x00000004	/* a client header matches an allow regex */
+#define SN_SVDENY	0x00000008	/* a server header matches a deny regex */
+#define SN_SVALLOW	0x00000010	/* a server header matches an allow regex */
+#define	SN_POST		0x00000020	/* the request was an HTTP POST */
+
+#define	SN_CK_NONE	0x00000000	/* this session had no cookie */
+#define	SN_CK_INVALID	0x00000040	/* this session had a cookie which matches no server */
+#define	SN_CK_DOWN	0x00000080	/* this session had cookie matching a down server */
+#define	SN_CK_VALID	0x000000C0	/* this session had cookie matching a valid server */
+#define	SN_CK_MASK	0x000000C0	/* mask to get this session's cookie flags */
+#define SN_CK_SHIFT	6		/* bit shift */
+
+#define SN_ERR_CLITO	0x00000100	/* client time-out */
+#define SN_ERR_CLICL	0x00000200	/* client closed (read/write error) */
+#define SN_ERR_SRVTO	0x00000300	/* server time-out, connect time-out */
+#define SN_ERR_SRVCL	0x00000400	/* server closed (connect/read/write error) */
+#define SN_ERR_PRXCOND	0x00000500	/* the proxy decided to close (deny...) */
+#define SN_ERR_MASK	0x00000700	/* mask to get only session error flags */
+#define SN_ERR_SHIFT	8		/* bit shift */
+
+#define SN_FINST_R	0x00001000	/* session ended during client request */
+#define SN_FINST_C	0x00002000	/* session ended during server connect */
+#define SN_FINST_H	0x00003000	/* session ended during server headers */
+#define SN_FINST_D	0x00004000	/* session ended during data phase */
+#define SN_FINST_L	0x00005000	/* session ended while pushing last data to client */
+#define SN_FINST_MASK	0x00007000	/* mask to get only final session state flags */
+#define	SN_FINST_SHIFT	12		/* bit shift */
+
+#define	SN_SCK_NONE	0x00000000	/* no set-cookie seen for the server cookie */
+#define	SN_SCK_DELETED	0x00010000	/* existing set-cookie deleted or changed */
+#define	SN_SCK_INSERTED	0x00020000	/* new set-cookie inserted or changed existing one */
+#define	SN_SCK_SEEN	0x00040000	/* set-cookie seen for the server cookie */
+#define	SN_SCK_MASK	0x00070000	/* mask to get the set-cookie field */
+#define	SN_SCK_SHIFT	16		/* bit shift */
+
 
 /* different possible states for the client side */
 #define CL_STHEADERS	0
@@ -409,6 +296,7 @@
 #define ACT_REPLACE	1	/* replace the matching header */
 #define ACT_REMOVE	2	/* remove the matching header */
 #define ACT_DENY	3	/* deny the request */
+#define ACT_PASS	4	/* pass this header without allowing or denying the request */
 
 /* configuration sections */
 #define CFG_NONE	0
@@ -630,7 +518,7 @@
 static char trash[BUFSIZE];
 
 /*
- * Syslog facilities and levels
+ * Syslog facilities and levels. Conforming to RFC3164.
  */
 
 #define MAX_SYSLOG_LEN		1024
@@ -655,6 +543,14 @@
 
 const char *monthname[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
 			     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+const char sess_term_cond[8]  = "-cCsSP67";	/* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, unknown */
+const char sess_fin_state[8]  = "-RCHDL67";	/* cliRequest, srvConnect, srvHeader, Data, Last, unknown */
+const char sess_cookie[4]     = "NIDV";		/* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
+const char sess_set_cookie[8] = "N1I3PD5R";	/* No set-cookie, unknown, Set-Cookie Inserted, unknown,
+					    	   Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
+						   unknown, Set-cookie Rewritten */
+
 #define MAX_HOSTNAME_LEN	32
 static char hostname[MAX_HOSTNAME_LEN] = "";
 
@@ -869,7 +765,7 @@
 	struct hostent *he;
 
 	if ((he = gethostbyname(str)) == NULL) {
-	    Alert("Invalid server name: <%s>\n", str);
+	    Alert("Invalid server name: '%s'\n", str);
 	}
 	else
 	    sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
@@ -1958,7 +1854,7 @@
     if (p->to_log & LW_DATE) {
 	struct tm *tm = localtime(&s->logs.tv_accept.tv_sec);
 
-	send_log(p, LOG_INFO, "%d.%d.%d.%d:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%d %d %lld %s %s \"%s\"\n",
+	send_log(p, LOG_INFO, "%d.%d.%d.%d:%d [%02d/%s/%04d:%02d:%02d:%02d] %s %s %d/%d/%d/%d %d %lld %s %s %c%c%c%c \"%s\"\n",
 		 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
 		 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
 		 tm->tm_hour, tm->tm_min, tm->tm_sec,
@@ -1970,10 +1866,14 @@
 		 s->logs.status, s->logs.bytes,
 		 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
 		 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
+		 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
+		 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
+		 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
+		 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
 		 uri);
     }
     else {
-	send_log(p, LOG_INFO, "%d.%d.%d.%d:%d %s %s %d/%d/%d/%d %d %lld %s %s \"%s\"\n",
+	send_log(p, LOG_INFO, "%d.%d.%d.%d:%d %s %s %d/%d/%d/%d %d %lld %s %s %c%c%c%c \"%s\"\n",
 		 pn[0], pn[1], pn[2], pn[3], ntohs(s->cli_addr.sin_port),
 		 pxid, srv,
 		 s->logs.t_request,
@@ -1983,6 +1883,10 @@
 		 s->logs.status, s->logs.bytes,
 		 s->logs.cli_cookie ? s->logs.cli_cookie : "-",
 		 s->logs.srv_cookie ? s->logs.srv_cookie : "-",
+		 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
+		 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
+		 (p->options & PR_O_COOK_ANY) ? sess_cookie[(s->flags & SN_CK_MASK) >> SN_CK_SHIFT] : '-',
+		 (p->options & PR_O_COOK_ANY) ? sess_set_cookie[(s->flags & SN_SCK_MASK) >> SN_SCK_SHIFT] : '-',
 		 uri);
     }
 
@@ -2188,13 +2092,13 @@
     else {
 	if (s->proxy->options & PR_O_HTTP_CHK) {
 	    int ret;
-	    /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
+	    /* we want to check if this host replies to "OPTIONS * HTTP/1.0"
 	     * so we'll send the request, and won't wake the checker up now.
 	     */
 #ifndef MSG_NOSIGNAL
-	    ret = send(fd, "OPTIONS / HTTP/1.0\r\n\r\n", 22, MSG_DONTWAIT);
+	    ret = send(fd, "OPTIONS * HTTP/1.0\r\n\r\n", 22, MSG_DONTWAIT);
 #else
-	    ret = send(fd, "OPTIONS / HTTP/1.0\r\n\r\n", 22, MSG_DONTWAIT | MSG_NOSIGNAL);
+	    ret = send(fd, "OPTIONS * HTTP/1.0\r\n\r\n", 22, MSG_DONTWAIT | MSG_NOSIGNAL);
 #endif
 	    if (ret == 22) {
 		FD_SET(fd, StaticReadEvent);   /* prepare for reading reply */
@@ -2390,6 +2294,10 @@
 		    /* no need to go further */
 		    t->logs.status = 403;
 		    client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
+		    if (!(t->flags & SN_ERR_MASK))
+			t->flags |= SN_ERR_PRXCOND;
+		    if (!(t->flags & SN_FINST_MASK))
+			t->flags |= SN_FINST_R;
 		    return 1;
 		}
 
@@ -2454,6 +2362,10 @@
 		    Alert("HTTP logging : out of memory.\n");
 		    t->logs.status = 500;
 		    client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
+		    if (!(t->flags & SN_ERR_MASK))
+			t->flags |= SN_ERR_PRXCOND;
+		    if (!(t->flags & SN_FINST_MASK))
+			t->flags |= SN_FINST_R;
 		    return 1;
 		}
 		
@@ -2508,6 +2420,8 @@
 			    if (!(t->flags & SN_CLALLOW))
 				t->flags |= SN_CLDENY;
 			    break;
+			case ACT_PASS: /* we simply don't deny this one */
+			    break;
 			}
 			break;
 		    }
@@ -2606,12 +2520,21 @@
 				srv = srv->next;
 			    }
 
-			    if (srv &&
-				(srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST)) {
+			    if (!srv) {
+				t->flags &= ~SN_CK_MASK;
+				t->flags |= SN_CK_INVALID;
+			    }
+			    else if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
 				/* we found the server and it's usable */
-				t->flags |= SN_DIRECT;
+				t->flags &= ~SN_CK_MASK;
+				t->flags |= SN_CK_VALID | SN_DIRECT;
 				t->srv = srv;
 			    }
+			    else {
+				t->flags &= ~SN_CK_MASK;
+				t->flags |= SN_CK_DOWN;
+			    }
+
 			    /* if this cookie was set in insert+indirect mode, then it's better that the
 			     * server never sees it.
 			     */
@@ -2693,16 +2616,21 @@
 	if (req->l >= req->rlim - req->data) {
 	    t->logs.status = 400;
 	    client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_PRXCOND;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_R;
 	    return 1;
 	}
 	else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
-	    /* read error, or last read : give up.
-	     * since we are in header mode, if there's no space left for headers, we
-	     * won't be able to free more later, so the session will never terminate.
-	     */
+	    /* read error, or last read : give up.  */
 	    tv_eternity(&t->crexpire);
 	    fd_delete(t->cli_fd);
 	    t->cli_state = CL_STCLOSE;
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_CLICL;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_R;
 	    return 1;
 	}
 	else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
@@ -2711,6 +2639,10 @@
 	     */
 	    t->logs.status = 408;
 	    client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_CLITO;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_R;
 	    return 1;
 	}
 
@@ -2723,11 +2655,14 @@
 	    tv_eternity(&t->cwexpire);
 	    fd_delete(t->cli_fd);
 	    t->cli_state = CL_STCLOSE;
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_CLICL;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_D;
 	    return 1;
 	}
-	/* read timeout, last read, or end of server write */
-	else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE
-		 || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
+	/* last read, or end of server write */
+	else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
 	    FD_CLR(t->cli_fd, StaticReadEvent);
 	    //	    if (req->l == 0) /* nothing to write on the server side */
 	    //		FD_CLR(t->srv_fd, StaticWriteEvent);
@@ -2736,15 +2671,40 @@
 	    t->cli_state = CL_STSHUTR;
 	    return 1;
 	}	
-	/* write timeout, or last server read and buffer empty */
-	else if (((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
-		 ||(tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
+	/* last server read and buffer empty */
+	else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
 	    FD_CLR(t->cli_fd, StaticWriteEvent);
 	    tv_eternity(&t->cwexpire);
 	    shutdown(t->cli_fd, SHUT_WR);
 	    t->cli_state = CL_STSHUTW;
 	    return 1;
 	}
+	/* read timeout */
+	else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
+	    FD_CLR(t->cli_fd, StaticReadEvent);
+	    //	    if (req->l == 0) /* nothing to write on the server side */
+	    //		FD_CLR(t->srv_fd, StaticWriteEvent);
+	    tv_eternity(&t->crexpire);
+	    shutdown(t->cli_fd, SHUT_RD);
+	    t->cli_state = CL_STSHUTR;
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_CLITO;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_D;
+	    return 1;
+	}	
+	/* write timeout */
+	else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
+	    FD_CLR(t->cli_fd, StaticWriteEvent);
+	    tv_eternity(&t->cwexpire);
+	    shutdown(t->cli_fd, SHUT_WR);
+	    t->cli_state = CL_STSHUTW;
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_CLICL;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_D;
+	    return 1;
+	}
 
 	if (req->l >= req->rlim - req->data) {
 	    /* no room to read more data */
@@ -2784,14 +2744,32 @@
 	return 0; /* other cases change nothing */
     }
     else if (c == CL_STSHUTR) {
-	if ((t->res_cw == RES_ERROR) ||
-	    ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0))
-	    || (tv_cmp2_ms(&t->cwexpire, &now) <= 0)) {
+	if (t->res_cw == RES_ERROR) {
+	    tv_eternity(&t->cwexpire);
+	    fd_delete(t->cli_fd);
+	    t->cli_state = CL_STCLOSE;
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_CLICL;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_D;
+	    return 1;
+	}
+	else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
 	    tv_eternity(&t->cwexpire);
 	    fd_delete(t->cli_fd);
 	    t->cli_state = CL_STCLOSE;
 	    return 1;
 	}
+	else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
+	    tv_eternity(&t->cwexpire);
+	    fd_delete(t->cli_fd);
+	    t->cli_state = CL_STCLOSE;
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_CLITO;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_D;
+	    return 1;
+	}
 	else if ((rep->l == 0) ||
 		 ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
 	    if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
@@ -2811,13 +2789,32 @@
 	return 0;
     }
     else if (c == CL_STSHUTW) {
-	if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL || s == SV_STSHUTW ||
-	    s == SV_STCLOSE || tv_cmp2_ms(&t->crexpire, &now) <= 0) {
+	if (t->res_cr == RES_ERROR) {
 	    tv_eternity(&t->crexpire);
 	    fd_delete(t->cli_fd);
 	    t->cli_state = CL_STCLOSE;
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_CLICL;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_D;
 	    return 1;
 	}
+	else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
+	    tv_eternity(&t->crexpire);
+	    fd_delete(t->cli_fd);
+	    t->cli_state = CL_STCLOSE;
+	    return 1;
+	}
+	else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
+	    tv_eternity(&t->crexpire);
+	    fd_delete(t->cli_fd);
+	    t->cli_state = CL_STCLOSE;
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_CLITO;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_D;
+	    return 1;
+	}
 	else if (req->l >= req->rlim - req->data) {
 	    /* no room to read more data */
 	    if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
@@ -2875,6 +2872,10 @@
 		 (c == CL_STSHUTR && t->req->l == 0)) { /* give up */
 	    tv_eternity(&t->cnexpire);
 	    t->srv_state = SV_STCLOSE;
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_CLICL;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_C;
 	    return 1;
 	}
 	else { /* go to SV_STCONN */
@@ -2887,6 +2888,10 @@
 		    if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
 			t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
 			t->srv = NULL; /* it's left to the dispatcher to choose a server */
+			if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
+			    t->flags &= ~SN_CK_MASK;
+			    t->flags |= SN_CK_DOWN;
+			}
 		    }
 
 		    if (connect_server(t) == 0) {
@@ -2901,6 +2906,10 @@
 		    t->logs.status = 503;
 		    if (t->proxy->mode == PR_MODE_HTTP)
 			client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
+		    if (!(t->flags & SN_ERR_MASK))
+			t->flags |= SN_ERR_SRVCL;
+		    if (!(t->flags & SN_FINST_MASK))
+			t->flags |= SN_FINST_C;
 		}
 	    }
 	    return 1;
@@ -2922,6 +2931,10 @@
 		    if ((t->proxy->options & PR_O_REDISP) && (t->conn_retries == 0)) {
 			t->flags &= ~SN_DIRECT; /* ignore cookie and force to use the dispatcher */
 			t->srv = NULL; /* it's left to the dispatcher to choose a server */
+			if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
+			    t->flags &= ~SN_CK_MASK;
+			    t->flags |= SN_CK_DOWN;
+			}
 		    }
 		    if (connect_server(t) == 0)
 			return 0; /* no state changed */
@@ -2932,6 +2945,10 @@
 	    t->logs.status = 503;
 	    if (t->proxy->mode == PR_MODE_HTTP)
 		client_return(t, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_SRVCL;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_C;
 	    return 1;
 	}
 	else { /* no error or write 0 */
@@ -2962,7 +2979,6 @@
 	}
     }
     else if (s == SV_STHEADERS) { /* receiving server headers */
-
 	/* now parse the partial (or complete) headers */
 	while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
 	    char *ptr;
@@ -2990,6 +3006,8 @@
 				  t->proxy->cookie_name,
 				  t->srv->cookie ? t->srv->cookie : "");
 
+		    t->flags |= SN_SCK_INSERTED;
+
 		    /* Here, we will tell an eventual cache on the client side that we don't
 		     * want it to cache this reply because HTTP/1.0 caches also cache cookies !
 		     * Some caches understand the correct form: 'no-cache="set-cookie"', but
@@ -3088,6 +3106,8 @@
 			    if (!(t->flags & SN_SVALLOW))
 				t->flags |= SN_SVDENY;
 			    break;
+			case ACT_PASS: /* we simply don't deny this one */
+			    break;
 			}
 			break;
 		    }
@@ -3153,6 +3173,7 @@
 		    if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
 			(memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
 			/* Cool... it's the right one */
+			t->flags |= SN_SCK_SEEN;
 			
 			/* If the cookie is in insert mode on a known server, we'll delete
 			 * this occurrence because we'll insert another one later.
@@ -3162,12 +3183,14 @@
 			    ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
 			    /* this header must be deleted */
 			    delete_header = 1;
+			    t->flags |= SN_SCK_DELETED;
 			}
 			else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
 			    /* replace bytes p3->p4 with the cookie name associated
 			     * with this server since we know it.
 			     */
 			    buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
+			    t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
 			}
 			break;
 		    }
@@ -3211,6 +3234,10 @@
 	    t->srv_state = SV_STCLOSE;
 	    t->logs.status = 502;
 	    client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_SRVCL;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_H;
 	    return 1;
 	}
 	/* end of client write or end of server read.
@@ -3233,22 +3260,44 @@
 	    t->srv_state = SV_STCLOSE;
 	    t->logs.status = 504;
 	    client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_SRVTO;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_H;
 	    return 1;
 	    
 	}	
-	/* write timeout, or last client read and buffer empty */
+	/* last client read and buffer empty */
 	/* FIXME!!! here, we don't want to switch to SHUTW if the
 	 * client shuts read too early, because we may still have
 	 * some work to do on the headers.
+	 * The side-effect is that if the client completely closes its
+	 * connection during SV_STHEADER, the connection to the server
+	 * is kept until a response comes back or the timeout is reached.
 	 */
-	else if (((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) ||
-		 (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
+	else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
 	    FD_CLR(t->srv_fd, StaticWriteEvent);
 	    tv_eternity(&t->swexpire);
 	    shutdown(t->srv_fd, SHUT_WR);
 	    t->srv_state = SV_STSHUTW;
 	    return 1;
 	}
+	/* write timeout */
+	/* FIXME!!! here, we don't want to switch to SHUTW if the
+	 * client shuts read too early, because we may still have
+	 * some work to do on the headers.
+	 */
+	else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
+	    FD_CLR(t->srv_fd, StaticWriteEvent);
+	    tv_eternity(&t->swexpire);
+	    shutdown(t->srv_fd, SHUT_WR);
+	    t->srv_state = SV_STSHUTW;
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_SRVTO;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_H;
+	    return 1;
+	}
 
 	if (req->l == 0) {
 	    if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
@@ -3281,25 +3330,42 @@
 	    tv_eternity(&t->swexpire);
 	    fd_delete(t->srv_fd);
 	    t->srv_state = SV_STCLOSE;
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_SRVCL;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_D;
 	    return 1;
 	}
-	/* read timeout, last read, or end of client write */
-	else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE
-		 || tv_cmp2_ms(&t->srexpire, &now) <= 0) {
+	/* last read, or end of client write */
+	else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
 	    FD_CLR(t->srv_fd, StaticReadEvent);
 	    tv_eternity(&t->srexpire);
 	    shutdown(t->srv_fd, SHUT_RD);
 	    t->srv_state = SV_STSHUTR;
 	    return 1;
-	    
+	}	
+	/* read timeout */
+	else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
+	    FD_CLR(t->srv_fd, StaticReadEvent);
+	    tv_eternity(&t->srexpire);
+	    shutdown(t->srv_fd, SHUT_RD);
+	    t->srv_state = SV_STSHUTR;
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_SRVTO;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_D;
+	    return 1;
 	}	
-	/* write timeout, or last client read and buffer empty */
-	else if (((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0))
-		 || (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
+	/* write timeout */
+	else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
 	    FD_CLR(t->srv_fd, StaticWriteEvent);
 	    tv_eternity(&t->swexpire);
 	    shutdown(t->srv_fd, SHUT_WR);
 	    t->srv_state = SV_STSHUTW;
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_SRVTO;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_D;
 	    return 1;
 	}
 	else if (req->l == 0) {
@@ -3337,9 +3403,19 @@
 	return 0; /* other cases change nothing */
     }
     else if (s == SV_STSHUTR) {
-	if ((t->res_sw == RES_ERROR) ||
-	    ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) ||
-	    (tv_cmp2_ms(&t->swexpire, &now) <= 0)) {
+	if (t->res_sw == RES_ERROR) {
+	    //FD_CLR(t->srv_fd, StaticWriteEvent);
+	    tv_eternity(&t->swexpire);
+	    fd_delete(t->srv_fd);
+	    //close(t->srv_fd);
+	    t->srv_state = SV_STCLOSE;
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_SRVCL;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_D;
+	    return 1;
+	}
+	else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
 	    //FD_CLR(t->srv_fd, StaticWriteEvent);
 	    tv_eternity(&t->swexpire);
 	    fd_delete(t->srv_fd);
@@ -3347,6 +3423,18 @@
 	    t->srv_state = SV_STCLOSE;
 	    return 1;
 	}
+	else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
+	    //FD_CLR(t->srv_fd, StaticWriteEvent);
+	    tv_eternity(&t->swexpire);
+	    fd_delete(t->srv_fd);
+	    //close(t->srv_fd);
+	    t->srv_state = SV_STCLOSE;
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_SRVTO;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_D;
+	    return 1;
+	}
 	else if (req->l == 0) {
 	    if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
 		FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
@@ -3365,16 +3453,38 @@
 	return 0;
     }
     else if (s == SV_STSHUTW) {
-	if (t->res_sr == RES_ERROR || t->res_sr == RES_NULL ||
-	    c == CL_STSHUTW || c == CL_STCLOSE ||
-	    tv_cmp2_ms(&t->srexpire, &now) <= 0) {
+	if (t->res_sr == RES_ERROR) {
 	    //FD_CLR(t->srv_fd, StaticReadEvent);
 	    tv_eternity(&t->srexpire);
 	    fd_delete(t->srv_fd);
 	    //close(t->srv_fd);
 	    t->srv_state = SV_STCLOSE;
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_SRVCL;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_D;
 	    return 1;
 	}
+	else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
+	    //FD_CLR(t->srv_fd, StaticReadEvent);
+	    tv_eternity(&t->srexpire);
+	    fd_delete(t->srv_fd);
+	    //close(t->srv_fd);
+	    t->srv_state = SV_STCLOSE;
+	    return 1;
+	}
+	else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
+	    //FD_CLR(t->srv_fd, StaticReadEvent);
+	    tv_eternity(&t->srexpire);
+	    fd_delete(t->srv_fd);
+	    //close(t->srv_fd);
+	    t->srv_state = SV_STCLOSE;
+	    if (!(t->flags & SN_ERR_MASK))
+		t->flags |= SN_ERR_SRVTO;
+	    if (!(t->flags & SN_FINST_MASK))
+		t->flags |= SN_FINST_D;
+	    return 1;
+	}
 	else if (rep->l == BUFSIZE) { /* no room to read more data */
 	    if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
 		FD_CLR(t->srv_fd, StaticReadEvent);
@@ -3489,7 +3599,14 @@
 		(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
 		//fprintf(stderr, "process_chk: 3\n");
 
-		if ((connect(fd, (struct sockaddr *)&s->addr, sizeof(s->addr)) != -1) || (errno == EINPROGRESS)) {
+		/* allow specific binding */
+		if (s->proxy->options & PR_O_BIND_SRC &&
+		    bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
+		    Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id);
+		    close(fd);
+		    s->result = -1;
+		}
+		else if ((connect(fd, (struct sockaddr *)&s->addr, sizeof(s->addr)) != -1) || (errno == EINPROGRESS)) {
 		    /* OK, connection in progress or established */
 
 		    //fprintf(stderr, "process_chk: 4\n");
@@ -3963,55 +4080,55 @@
     }
     else if (!strcmp(args[0], "uid")) {
 	if (global.uid != 0) {
-	    Alert("parsing [%s:%d] : <uid> already specified. Continuing.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
 	    return 0;
 	}
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <uid> expects an integer argument.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
 	    return -1;
 	}
 	global.uid = atol(args[1]);
     }
     else if (!strcmp(args[0], "gid")) {
 	if (global.gid != 0) {
-	    Alert("parsing [%s:%d] : <gid> already specified. Continuing.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
 	    return 0;
 	}
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <gid> expects an integer argument.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
 	    return -1;
 	}
 	global.gid = atol(args[1]);
     }
     else if (!strcmp(args[0], "nbproc")) {
 	if (global.nbproc != 0) {
-	    Alert("parsing [%s:%d] : <nbproc> already specified. Continuing.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
 	    return 0;
 	}
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <gid> expects an integer argument.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
 	    return -1;
 	}
 	global.nbproc = atol(args[1]);
     }
     else if (!strcmp(args[0], "maxconn")) {
 	if (global.maxconn != 0) {
-	    Alert("parsing [%s:%d] : <maxconn> already specified. Continuing.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
 	    return 0;
 	}
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
 	    return -1;
 	}
 	global.maxconn = atol(args[1]);
     }
     else if (!strcmp(args[0], "chroot")) {
 	if (global.chroot != NULL) {
-	    Alert("parsing [%s:%d] : <chroot> already specified. Continuing.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
 	    return 0;
 	}
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <chroot> expects a directory as an argument.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects a directory as an argument.\n", file, linenum, args[0]);
 	    return -1;
 	}
 	global.chroot = strdup(args[1]);
@@ -4021,7 +4138,7 @@
 	int facility, level;
 	
 	if (*(args[1]) == 0 || *(args[2]) == 0) {
-	    Alert("parsing [%s:%d] : <log> expects <address> and <facility> as arguments.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
 	    return -1;
 	}
 	
@@ -4030,7 +4147,7 @@
 		break;
 	
 	if (facility >= NB_LOG_FACILITIES) {
-	    Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
+	    Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
 	    exit(1);
 	}
 
@@ -4039,7 +4156,7 @@
 	    while (level >= 0 && strcmp(log_levels[level], args[3]))
 		level--;
 	    if (level < 0) {
-		Alert("parsing [%s:%d] : unknown optionnal log level <%s>\n", file, linenum, args[3]);
+		Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
 		exit(1);
 	    }
 	}
@@ -4065,7 +4182,7 @@
 	
     }
     else {
-	Alert("parsing [%s:%d] : unknown keyword <%s> in <global> section\n", file, linenum, args[0]);
+	Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
 	return -1;
     }
     return 0;
@@ -4081,13 +4198,13 @@
 
     if (!strcmp(args[0], "listen")) {  /* new proxy */
 	if (strchr(args[2], ':') == NULL) {
-	    Alert("parsing [%s:%d] : <listen> expects <id> and <addr:port> as arguments.\n",
-		  file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects <id> and <addr:port> as arguments.\n",
+		  file, linenum, args[0]);
 	    return -1;
 	}
 	
 	if ((curproxy = (struct proxy *)calloc(1, sizeof(struct proxy))) == NULL) {
-	    Alert("parsing [%s:%d] : out of memory\n", file, linenum);
+	    Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
 	    return -1;
 	}
 	curproxy->next = proxy;
@@ -4106,7 +4223,7 @@
 	return 0;
     }
     else if (curproxy == NULL) {
-	Alert("parsing [%s:%d] : <listen> expected.\n", file, linenum);
+	Alert("parsing [%s:%d] : 'listen' expected.\n", file, linenum);
 	return -1;
     }
     
@@ -4115,7 +4232,7 @@
 	else if (!strcmp(args[1], "tcp")) curproxy->mode = PR_MODE_TCP;
 	else if (!strcmp(args[1], "health")) curproxy->mode = PR_MODE_HEALTH;
 	else {
-	    Alert("parsing [%s:%d] : unknown proxy mode <%s>.\n", file, linenum, args[1]);
+	    Alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
 	    return -1;
 	}
     }
@@ -4131,8 +4248,8 @@
 	}
 	
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <cookie> expects <cookie_name> as argument.\n",
-		  file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects <cookie_name> as argument.\n",
+		  file, linenum, args[0]);
 	    return -1;
 	}
 	curproxy->cookie_name = strdup(args[1]);
@@ -4156,28 +4273,28 @@
 		curproxy->options |= PR_O_COOK_POST;
 	    }
 	    else {
-		Alert("parsing [%s:%d] : <cookie> supports 'rewrite', 'insert', 'indirect', 'nocache' and 'postonly' options.\n",
-		      file, linenum);
+		Alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'indirect', 'nocache' and 'postonly' options.\n",
+		      file, linenum, args[0]);
 		return -1;
 	    }
 	    cur_arg++;
 	}
 	if ((curproxy->options & (PR_O_COOK_RW|PR_O_COOK_IND)) == (PR_O_COOK_RW|PR_O_COOK_IND)) {
-	    Alert("parsing [%s:%d] : <cookie> 'rewrite' and 'indirect' mode are incompatibles.\n",
+	    Alert("parsing [%s:%d] : cookie 'rewrite' and 'indirect' mode are incompatibles.\n",
 		  file, linenum);
 	    return -1;
 	}
     }
     else if (!strcmp(args[0], "capture")) {  /* name of a cookie to capture */
 	if (curproxy->capture_name != NULL) {
-	    Alert("parsing [%s:%d] : capture already specified. Continuing.\n",
-		  file, linenum);
+	    Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
+		  file, linenum, args[0]);
 	    return 0;
 	}
 	
 	if (*(args[4]) == 0) {
-	    Alert("parsing [%s:%d] : <capture> expects 'cookie' <cookie_name> 'len' <len>.\n",
-		  file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects 'cookie' <cookie_name> 'len' <len>.\n",
+		  file, linenum, args[0]);
 	    return -1;
 	}
 	curproxy->capture_name = strdup(args[2]);
@@ -4191,52 +4308,52 @@
     }
     else if (!strcmp(args[0], "contimeout")) {  /* connect timeout */
 	if (curproxy->contimeout != 0) {
-	    Alert("parsing [%s:%d] : contimeout already specified. Continuing.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
 	    return 0;
 	}
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <contimeout> expects an integer <time_in_ms> as argument.\n",
-		  file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
+		  file, linenum, args[0]);
 	    return -1;
 	}
 	curproxy->contimeout = atol(args[1]);
     }
     else if (!strcmp(args[0], "clitimeout")) {  /*  client timeout */
 	if (curproxy->clitimeout != 0) {
-	    Alert("parsing [%s:%d] : clitimeout already specified. Continuing.\n",
-		  file, linenum);
+	    Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n",
+		  file, linenum, args[0]);
 	    return 0;
 	}
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <clitimeout> expects an integer <time_in_ms> as argument.\n",
-		  file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
+		  file, linenum, args[0]);
 	    return -1;
 	}
 	curproxy->clitimeout = atol(args[1]);
     }
     else if (!strcmp(args[0], "srvtimeout")) {  /*  server timeout */
 	if (curproxy->srvtimeout != 0) {
-	    Alert("parsing [%s:%d] : srvtimeout already specified. Continuing.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
 	    return 0;
 	}
 	if (*(args[1]) == 0) {
-		Alert("parsing [%s:%d] : <srvtimeout> expects an integer <time_in_ms> as argument.\n",
-		      file, linenum);
+		Alert("parsing [%s:%d] : '%s' expects an integer <time_in_ms> as argument.\n",
+		      file, linenum, args[0]);
 		return -1;
 	}
 	curproxy->srvtimeout = atol(args[1]);
     }
     else if (!strcmp(args[0], "retries")) {  /* connection retries */
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <retries> expects an integer argument (dispatch counts for one).\n",
-		  file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects an integer argument (dispatch counts for one).\n",
+		  file, linenum, args[0]);
 	    return -1;
 	}
 	curproxy->conn_retries = atol(args[1]);
     }
     else if (!strcmp(args[0], "option")) {
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <option> expects an option name.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects an option name.\n", file, linenum, args[0]);
 	    return -1;
 	}
 	if (!strcmp(args[1], "redispatch"))
@@ -4270,7 +4387,7 @@
 	    curproxy->options |= PR_O_PERSIST;
 	}
 	else {
-	    Alert("parsing [%s:%d] : unknown option <%s>.\n", file, linenum, args[1]);
+	    Alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
 	    return -1;
 	}
 	return 0;
@@ -4287,32 +4404,32 @@
 #endif
     else if (!strcmp(args[0], "maxconn")) {  /* maxconn */
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <maxconn> expects an integer argument.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
 	    return -1;
 	}
 	curproxy->maxconn = atol(args[1]);
     }
     else if (!strcmp(args[0], "grace")) {  /* grace time (ms) */
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <grace> expects a time in milliseconds.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]);
 	    return -1;
 	}
 	curproxy->grace = atol(args[1]);
     }
     else if (!strcmp(args[0], "dispatch")) {  /* dispatch address */
 	if (strchr(args[1], ':') == NULL) {
-	    Alert("parsing [%s:%d] : <dispatch> expects <addr:port> as argument.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n", file, linenum, args[0]);
 	    return -1;
 	}
 	curproxy->dispatch_addr = *str2sa(args[1]);
     }
-    else if (!strcmp(args[0], "balance")) {  /* set balancing with optionnal algorithm */
+    else if (!strcmp(args[0], "balance")) {  /* set balancing with optional algorithm */
 	if (*(args[1])) {
 	    if (!strcmp(args[1], "roundrobin")) {
 		curproxy->options |= PR_O_BALANCE_RR;
 	    }
 	    else {
-		Alert("parsing [%s:%d] : <balance> supports 'roundrobin' options.\n", file, linenum);
+		Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
 		return -1;
 	    }
 	}
@@ -4323,8 +4440,8 @@
 	int cur_arg;
 
 	if (strchr(args[2], ':') == NULL) {
-	    Alert("parsing [%s:%d] : <server> expects <name> and <addr:port> as arguments.\n",
-		  file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects <name> and <addr:port> as arguments.\n",
+		  file, linenum, args[0]);
 	    return -1;
 	}
 	if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
@@ -4389,7 +4506,7 @@
 		cur_arg += 1;
 	    }
 	    else {
-		Alert("parsing [%s:%d] : server %s only supports options 'cookie' and 'check'.\n",
+		Alert("parsing [%s:%d] : server %s only supports options 'cookie', 'check', 'inter', 'rise' and 'fall'.\n",
 		      file, linenum, newsrv->id);
 		return -1;
 	    }
@@ -4416,7 +4533,7 @@
 		    break;
 	
 	    if (facility >= NB_LOG_FACILITIES) {
-		Alert("parsing [%s:%d] : unknown log facility <%s>\n", file, linenum, args[2]);
+		Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
 		exit(1);
 	    }
 	    
@@ -4425,7 +4542,7 @@
 		while (level >= 0 && strcmp(log_levels[level], args[3]))
 		     level--;
 		if (level < 0) {
-		    Alert("parsing [%s:%d] : unknown optionnal log level <%s>\n", file, linenum, args[3]);
+		    Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
 		    exit(1);
 		}
 	    }
@@ -4450,15 +4567,15 @@
 	    }
 	}
 	else {
-	    Alert("parsing [%s:%d] : <log> expects either <address[:port]> and <facility> or 'global' as arguments.\n",
+	    Alert("parsing [%s:%d] : 'log' expects either <address[:port]> and <facility> or 'global' as arguments.\n",
 		  file, linenum);
 	    return -1;
 	}
     }
     else if (!strcmp(args[0], "source")) {  /* address to which we bind when connecting */
 	if (strchr(args[1], ':') == NULL) {
-	    Alert("parsing [%s:%d] : <source> expects <addr:port> as argument.\n",
-		  file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects <addr:port> as argument.\n",
+		  file, linenum, "source");
 	    return -1;
 	}
 	
@@ -4469,14 +4586,14 @@
 	regex_t *preg;
 	
 	if (*(args[1]) == 0 || *(args[2]) == 0) {
-	    Alert("parsing [%s:%d] : <reqrep> expects <search> and <replace> as arguments.\n",
-		  file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
+		  file, linenum, args[0]);
 	    return -1;
 	}
 	
 	preg = calloc(1, sizeof(regex_t));
 	if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
-	    Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
+	    Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
 	    return -1;
 	}
 	
@@ -4486,13 +4603,13 @@
 	regex_t *preg;
 	
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <reqdel> expects <regex> as an argument.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
 	    return -1;
 	}
 	
 	preg = calloc(1, sizeof(regex_t));
 	if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
-	    Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
+	    Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
 	    return -1;
 	}
 	
@@ -4502,29 +4619,45 @@
 	regex_t *preg;
 	
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <reqdeny> expects <regex> as an argument.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
 	    return -1;
 	}
 	
 	preg = calloc(1, sizeof(regex_t));
 	if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
-	    Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
+	    Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
 	    return -1;
 	}
 	
 	chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
     }
+    else if (!strcmp(args[0], "reqpass")) {  /* pass this header without allowing or denying the request */
+	regex_t *preg;
+	
+	if (*(args[1]) == 0) {
+	    Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
+	    return -1;
+	}
+	
+	preg = calloc(1, sizeof(regex_t));
+	if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
+	    Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
+	    return -1;
+	}
+	
+	chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
+    }
     else if (!strcmp(args[0], "reqallow")) {  /* allow a request if a header matches this regex */
 	regex_t *preg;
 	
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <reqallow> expects <regex> as an argument.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
 	    return -1;
 	}
 	
 	preg = calloc(1, sizeof(regex_t));
 	if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
-	    Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
+	    Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
 	    return -1;
 	}
 	
@@ -4534,14 +4667,14 @@
 	regex_t *preg;
 	
 	if (*(args[1]) == 0 || *(args[2]) == 0) {
-	    Alert("parsing [%s:%d] : <reqirep> expects <search> and <replace> as arguments.\n",
-		  file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
+		  file, linenum, args[0]);
 	    return -1;
 	}
 	
 	preg = calloc(1, sizeof(regex_t));
 	if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
-	    Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
+	    Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
 	    return -1;
 	}
 	
@@ -4551,13 +4684,13 @@
 	regex_t *preg;
 	
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <reqidel> expects <regex> as an argument.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
 	    return -1;
 	}
 	
 	preg = calloc(1, sizeof(regex_t));
 	if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
-	    Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
+	    Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
 	    return -1;
 	}
 	
@@ -4567,29 +4700,45 @@
 	regex_t *preg;
 	
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <reqideny> expects <regex> as an argument.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
 	    return -1;
 	}
 	
 	preg = calloc(1, sizeof(regex_t));
 	if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
-	    Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
+	    Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
 	    return -1;
 	}
 	
 	chain_regex(&curproxy->req_exp, preg, ACT_DENY, NULL);
     }
+    else if (!strcmp(args[0], "reqipass")) {  /* pass this header without allowing or denying the request */
+	regex_t *preg;
+	
+	if (*(args[1]) == 0) {
+	    Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
+	    return -1;
+	}
+	
+	preg = calloc(1, sizeof(regex_t));
+	if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
+	    Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
+	    return -1;
+	}
+	
+	chain_regex(&curproxy->req_exp, preg, ACT_PASS, NULL);
+    }
     else if (!strcmp(args[0], "reqiallow")) {  /* allow a request if a header matches this regex ignoring case */
 	regex_t *preg;
 	
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <reqiallow> expects <regex> as an argument.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects <regex> as an argument.\n", file, linenum, args[0]);
 	    return -1;
 	}
 	
 	preg = calloc(1, sizeof(regex_t));
 	if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
-	    Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
+	    Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
 	    return -1;
 	}
 	
@@ -4597,12 +4746,12 @@
     }
     else if (!strcmp(args[0], "reqadd")) {  /* add request header */
 	if (curproxy->nb_reqadd >= MAX_NEWHDR) {
-	    Alert("parsing [%s:%d] : too many `reqadd'. Continuing.\n", file, linenum);
+	    Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
 	    return 0;
 	}
 	
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <reqadd> expects <header> as an argument.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
 	    return -1;
 	}
 	
@@ -4612,14 +4761,14 @@
 	    regex_t *preg;
 
 	    if (*(args[1]) == 0 || *(args[2]) == 0) {
-		Alert("parsing [%s:%d] : <rsprep> expects <search> and <replace> as arguments.\n",
-		      file, linenum);
+		Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
+		      file, linenum, args[0]);
 		return -1;
 	    }
 
 	    preg = calloc(1, sizeof(regex_t));
 	    if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
-		Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
+		Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
 		return -1;
 	    }
 	    
@@ -4629,13 +4778,13 @@
 	regex_t *preg;
 	
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <rspdel> expects <search> as an argument.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
 	    return -1;
 	}
 
 	preg = calloc(1, sizeof(regex_t));
 	if (regcomp(preg, args[1], REG_EXTENDED) != 0) {
-	    Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
+	    Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
 	    return -1;
 	}
 	
@@ -4645,14 +4794,14 @@
 	    regex_t *preg;
 
 	    if (*(args[1]) == 0 || *(args[2]) == 0) {
-		Alert("parsing [%s:%d] : <rspirep> expects <search> and <replace> as arguments.\n",
-		      file, linenum);
+		Alert("parsing [%s:%d] : '%s' expects <search> and <replace> as arguments.\n",
+		      file, linenum, args[0]);
 		return -1;
 	    }
 
 	    preg = calloc(1, sizeof(regex_t));
 	    if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
-		Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
+		Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
 		return -1;
 	    }
 	    
@@ -4662,13 +4811,13 @@
 	regex_t *preg;
 	
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <rspidel> expects <search> as an argument.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects <search> as an argument.\n", file, linenum, args[0]);
 	    return -1;
 	}
 
 	preg = calloc(1, sizeof(regex_t));
 	if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
-	    Alert("parsing [%s:%d] : bad regular expression <%s>.\n", file, linenum, args[1]);
+	    Alert("parsing [%s:%d] : bad regular expression '%s'.\n", file, linenum, args[1]);
 	    return -1;
 	}
 	
@@ -4676,12 +4825,12 @@
     }
     else if (!strcmp(args[0], "rspadd")) {  /* add response header */
 	if (curproxy->nb_rspadd >= MAX_NEWHDR) {
-	    Alert("parsing [%s:%d] : too many `rspadd'. Continuing.\n", file, linenum);
+	    Alert("parsing [%s:%d] : too many '%s'. Continuing.\n", file, linenum, args[0]);
 	    return 0;
 	}
 	
 	if (*(args[1]) == 0) {
-	    Alert("parsing [%s:%d] : <rspadd> expects <header> as an argument.\n", file, linenum);
+	    Alert("parsing [%s:%d] : '%s' expects <header> as an argument.\n", file, linenum, args[0]);
 	    return -1;
 	}
 	
@@ -4762,7 +4911,7 @@
 	}
     }
     else {
-	Alert("parsing [%s:%d] : unknown keyword <%s> in <listen> section\n", file, linenum, args[0]);
+	Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "listen");
 	return -1;
     }
     return 0;
@@ -4880,7 +5029,7 @@
 		return -1;
 	    break;
 	default:
-	    Alert("parsing [%s:%d] : unknown keyword <%s> out of section.\n", file, linenum, args[0]);
+	    Alert("parsing [%s:%d] : unknown keyword '%s' out of section.\n", file, linenum, args[0]);
 	    return -1;
 	}
 	    
@@ -5227,12 +5376,12 @@
     }
 
     /* setgid / setuid */
-    if (global.gid && setregid(global.gid, global.gid) == -1) {
+    if (global.gid && setgid(global.gid) == -1) {
 	Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
 	exit(1);
     }
 
-    if (global.uid && setreuid(global.uid, global.uid) == -1) {
+    if (global.uid && setuid(global.uid) == -1) {
 	Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
 	exit(1);
     }
@@ -5273,4 +5422,3 @@
 
     exit(0);
 }
-