diff -Naur tinyproxy-1.6.2-orig/configure tinyproxy-1.6.2/configure
--- tinyproxy-1.6.2-orig/configure	2003-10-17 17:39:46.000000000 +0200
+++ tinyproxy-1.6.2/configure	2009-08-28 10:48:00.000000000 +0200
@@ -2513,7 +2513,7 @@
   CFLAGS=$ac_save_CFLAGS
 elif test $ac_cv_prog_cc_g = yes; then
   if test "$GCC" = yes; then
-    CFLAGS="-g -O2"
+    CFLAGS="-g"
   else
     CFLAGS="-g"
   fi
@@ -4023,13 +4023,13 @@
   CFLAGS=$ac_save_CFLAGS
 elif test $ac_cv_prog_cc_g = yes; then
   if test "$GCC" = yes; then
-    CFLAGS="-g -O2"
+    CFLAGS="-g"
   else
     CFLAGS="-g"
   fi
 else
   if test "$GCC" = yes; then
-    CFLAGS="-O2"
+    CFLAGS=""
   else
     CFLAGS=
   fi
@@ -23062,7 +23062,7 @@
         LEX_FLAGS="--warn --debug"
     fi
 else
-        CFLAGS="-O2 -DNDEBUG $CFLAGS"
+        CFLAGS="-DNDEBUG $CFLAGS"
     YFLAGS="-d"
 fi
 
diff -Naur tinyproxy-1.6.2-orig/doc/default.html tinyproxy-1.6.2/doc/default.html
--- tinyproxy-1.6.2-orig/doc/default.html	2003-03-13 22:35:58.000000000 +0100
+++ tinyproxy-1.6.2/doc/default.html	2009-08-28 10:48:00.000000000 +0200
@@ -1,7 +1,176 @@
-<html><head><title>{cause}</title></head>
-<body>
-<font size=\+2\>Cache Error!</font><br>
-The following error has occured: {detail}
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns='http://www.w3.org/1999/xhtml'>
+<head>
+<style type="text/css">
+<!--
+html {
+	height: 100%;
+}
+
+body, td {
+	font-size: 12px;
+	font-family: sans-serif;
+}
+
+body {
+	padding: 0px 0px 0px 0px;
+	margin: 0px 0px 0px 0px;
+	width: 100%;
+	height: 100%;
+}
+
+#pageLayout {
+	width: 800px;
+	height: 100%;
+	border-spacing: 0px;
+}
+
+#footCell {
+	vertical-align: bottom;
+}
+
+#foot {
+	background-color:#9EB9CE;
+	border-bottom:2px solid #000000;
+	border-top:2px solid #000000;
+	height:20px;
+}
+
+
+#infoBoxCell {
+	padding-top: 50px;
+	vertical-align: top;
+}
+
+#pageHead {
+	width: 100%;
+	height: 60px;
+	background: transparent url(/squid-internal-static/icons/fec-utm-bg1.jpg) repeat scroll 0 0;
+	border-spacing: 0px;
+}
+
+#pageHeadCell {
+	vertical-align: top;
+}
+
+#productCell {
+	vertical-align: middle;
+	padding-left: 15px;
+	color: #ffffff;
+	font-size: 16px;
+	font-weight: bold;
+}
+
+#logoCell {
+	text-align: right;
+	vertical-align: middle;
+	padding-right: 15px;
+}
+
+#infoBox {
+	border: 2px #cc3333 solid;
+	width: 600px;
+	/* border-collapse: collapse; */
+	margin-left: auto;
+	margin-right: auto;
+	background-color: #e0e0e0;
+}
+
+#errorHead {
+	color: #cc3333;
+	font-weight: bold;
+	font-size: 14px;
+	padding: 4px;
+}
+
+#errorDetail {
+	border: 2px #e0e0e0 inset;
+	font-size: 12px;
+	padding: 4px;
+	margin: 4px;
+}
+
+.de {
+	display: none;
+}
+
+h2 {
+	font-size: 14px;
+	padding: 0px;
+	margin: 5px 0px 5px 0px;
+}
+-->
+</style>
+
+<script type="text/javascript">
+
+function start() {
+	var lang = "en";
+	var language;
+	if(navigator.appName == 'Netscape')
+        language = navigator.language;
+    else
+        language = navigator.browserLanguage;
+    if(language.indexOf("de") > -1)
+        lang = "de";
+	showLang(document, lang);
+}
+
+function showLang(ele, lang) {
+	for(var i = 0; i < ele.childNodes.length; i++) {
+		var c = ele.childNodes[i];
+		if(c.nodeType == 1) {
+			if(typeof(c.className) == "string") {
+				if(c.className == "en") {
+					c.style.display= "none";
+				}
+				if(c.className == lang) {
+					c.style.display = "block";
+				}
+			}
+			showLang(ele.childNodes[i], lang);
+		}
+	}
+}
+
+</script>
+
+<title>HTTP Proxy Error</title>
+</head>
+<body onload="start();">
+<table id="pageLayout">
+<tbody>
+<tr><td id="pageHeadCell">
+	<table id="pageHead">
+	<tr>
+		<td id='productCell'>packetalarm UTM</td>
+		<td id='logoCell'><img src='/squid-internal-static/icons/fec-utm-logo1.gif'/></td>
+	</tr>
+	</table>
+</tr></td>
+<tr><td id="infoBoxCell">
+<table id="infoBox">
+<tbody>
+<tr><td>
+<div id="errorHead">
+<div class="en">HTTP Proxy Error</div>
+<div class="de">HTTP Proxy Fehler</div>
+</div>
+<div id="errorDetail">
+{detail}
 <hr>
-<font size=\-1\><em>Generated by {package} ({version})</em></font>
-</body></html>
+</tr></td>
+</tbody>
+</table>
+</td></tr>
+<tr><td><!-- fill --></tr></td>
+<tr><td id="footCell"><div id="foot"></div></td></tr>
+</tbody>
+</table>
+<div id="debug">Debug-Output:<br/></div>
+</body>
+</html>
+<!--
+vim:ts=4:sw=4
+-->
diff -Naur tinyproxy-1.6.2-orig/doc/tinyproxy.conf tinyproxy-1.6.2/doc/tinyproxy.conf
--- tinyproxy-1.6.2-orig/doc/tinyproxy.conf	2003-06-23 23:14:32.000000000 +0200
+++ tinyproxy-1.6.2/doc/tinyproxy.conf	2009-08-28 10:48:00.000000000 +0200
@@ -64,8 +64,8 @@
 # Where to log the information. Either LogFile or Syslog should be set,
 # but not both.
 #
-Logfile "/var/log/tinyproxy.log"
-# Syslog On
+# Logfile "/var/log/tinyproxy.log"
+Syslog On
 
 #
 # Set the logging level. Allowed settings are:
@@ -85,7 +85,7 @@
 # PidFile: Write the PID of the main tinyproxy thread to this file so it
 # can be used for signalling purposes.
 #
-PidFile "/var/run/tinyproxy.pid"
+PidFile "/tmp/tinyproxy.pid"
 
 #
 # Include the X-Tinyproxy header, which has the client's IP address when
@@ -226,3 +226,5 @@
 #
 ConnectPort 443
 ConnectPort 563
+
+CCheckErrFile "/tmp/ccheck.html"
diff -Naur tinyproxy-1.6.2-orig/src/buffer.c tinyproxy-1.6.2/src/buffer.c
--- tinyproxy-1.6.2-orig/src/buffer.c	2002-05-24 06:45:32.000000000 +0200
+++ tinyproxy-1.6.2/src/buffer.c	2009-08-28 10:48:00.000000000 +0200
@@ -312,3 +312,63 @@
 		}
 	}
 }
+
+
+ssize_t
+write_buffer_fd(int fd, struct buffer_s * buffptr)
+{
+	ssize_t bytessent;
+	struct bufline_s *line;
+
+	assert(fd >= 0);
+	assert(buffptr != NULL);
+
+	if (buffptr->size == 0)
+		return 0;
+
+	/* Sanity check. It would be bad to be using a NULL pointer! */
+	assert(BUFFER_HEAD(buffptr) != NULL);
+	line = BUFFER_HEAD(buffptr);
+
+	bytessent =
+	    write(fd, line->string + line->pos, line->length - line->pos);
+
+	if (bytessent >= 0) {
+		/* bytes sent, adjust buffer */
+		line->pos += bytessent;
+		if (line->pos == line->length)
+			free_line(remove_from_buffer(buffptr));
+		return bytessent;
+	}
+	return(0);
+}
+
+
+unsigned char *peek_buffer(struct buffer_s *buffptr)
+{
+	int				idx;
+	unsigned char	*peek;
+	struct bufline_s *line;
+
+	assert(buffptr != NULL);
+
+	if (buffptr->size == 0)
+		return NULL;
+
+	if ((peek = malloc(buffptr->size)) == NULL) {
+		return (NULL);
+	}
+
+	idx = 0;
+
+	assert(BUFFER_HEAD(buffptr) != NULL);
+	line = BUFFER_HEAD(buffptr);
+
+	while (line != NULL) {
+		memcpy(&peek[idx], line->string + line->pos, line->length - line->pos);
+		idx += (line->length - line->pos);
+		line = line->next;
+	}
+
+	return (peek);
+}
diff -Naur tinyproxy-1.6.2-orig/src/buffer.h tinyproxy-1.6.2/src/buffer.h
--- tinyproxy-1.6.2-orig/src/buffer.h	2002-05-14 02:43:38.000000000 +0200
+++ tinyproxy-1.6.2/src/buffer.h	2009-08-28 10:48:00.000000000 +0200
@@ -33,5 +33,6 @@
 
 extern ssize_t read_buffer(int fd, struct buffer_s *buffptr);
 extern ssize_t write_buffer(int fd, struct buffer_s *buffptr);
+extern unsigned char *peek_buffer(struct buffer_s *buffptr);
 
 #endif				/* __BUFFER_H_ */
diff -Naur tinyproxy-1.6.2-orig/src/child.c tinyproxy-1.6.2/src/child.c
--- tinyproxy-1.6.2-orig/src/child.c	2003-10-14 20:01:05.000000000 +0200
+++ tinyproxy-1.6.2/src/child.c	2009-08-28 10:48:00.000000000 +0200
@@ -436,3 +436,35 @@
 {
 	close(listenfd);
 }
+
+void
+remove_child(pid_t pid)
+{
+	int i;
+	int ok = 0;
+
+	SERVER_COUNT_LOCK();
+	*servers_waiting = 0;
+	for (i = 0; i != child_config.maxclients; i++) {
+		if(pid == child_ptr[i].tid) {
+			child_ptr[i].status = T_EMPTY;
+			child_ptr[i].connects = 0;
+			log_message(LOG_INFO, "remove_child(): deleted child "
+			  "%d from list", pid);
+			ok = 1;
+		}
+		else
+		{
+			if(child_ptr[i].status == T_WAITING)
+				*servers_waiting += 1;
+		}
+	}
+	SERVER_COUNT_UNLOCK();
+	if(!ok)
+	{
+		log_message(LOG_INFO,
+		  "remove_child(): could not find pid %d", pid);
+	}
+	log_message(LOG_INFO, "remove_child(): set servers_waiting to %d",
+	  *servers_waiting);
+}
diff -Naur tinyproxy-1.6.2-orig/src/child.h tinyproxy-1.6.2/src/child.h
--- tinyproxy-1.6.2-orig/src/child.h	2002-05-26 20:45:26.000000000 +0200
+++ tinyproxy-1.6.2/src/child.h	2009-08-28 10:48:00.000000000 +0200
@@ -34,4 +34,6 @@
 
 extern short int child_configure(child_config_t type, unsigned int val);
 
+extern void remove_child(pid_t pid);
+
 #endif
diff -Naur tinyproxy-1.6.2-orig/src/common.h tinyproxy-1.6.2/src/common.h
--- tinyproxy-1.6.2-orig/src/common.h	2003-06-25 20:20:22.000000000 +0200
+++ tinyproxy-1.6.2/src/common.h	2009-08-28 10:48:00.000000000 +0200
@@ -154,6 +154,7 @@
 #ifdef HAVE_SYS_MMAN_H
 #  include      <sys/mman.h>
 #endif
+#include <pcre.h>
 
 /*
  * If MSG_NOSIGNAL is not defined, define it to be zero so that it doesn't
diff -Naur tinyproxy-1.6.2-orig/src/conns.c tinyproxy-1.6.2/src/conns.c
--- tinyproxy-1.6.2-orig/src/conns.c	2003-06-01 01:02:21.000000000 +0200
+++ tinyproxy-1.6.2/src/conns.c	2009-08-28 10:48:00.000000000 +0200
@@ -77,6 +77,14 @@
 
 	update_stats(STAT_OPEN);
 
+	connptr->server_headers = NULL;
+
+	connptr->forwarded_for = NULL;
+
+	connptr->response_line = NULL;
+	connptr->user_agent = NULL;
+	connptr->host_header = NULL;
+
 	return connptr;
 
 error_exit:
@@ -133,6 +141,21 @@
 	if (connptr->client_string_addr)
 		safefree(connptr->client_string_addr);
 
+	if(connptr->server_headers)
+		hashmap_delete(connptr->server_headers);
+
+	if(connptr->forwarded_for)
+		free(connptr->forwarded_for);
+
+	if (connptr->response_line)
+		safefree(connptr->response_line);
+
+	if (connptr->user_agent)
+		safefree(connptr->user_agent);
+
+	if (connptr->host_header)
+		safefree(connptr->host_header);
+
 	safefree(connptr);
 
 	update_stats(STAT_CLOSE);
diff -Naur tinyproxy-1.6.2-orig/src/conns.h tinyproxy-1.6.2/src/conns.h
--- tinyproxy-1.6.2-orig/src/conns.h	2003-05-04 06:35:10.000000000 +0200
+++ tinyproxy-1.6.2/src/conns.h	2009-08-28 10:48:00.000000000 +0200
@@ -19,6 +19,13 @@
 #define TINYPROXY_CONNS_H
 
 #include "tinyproxy.h"
+#include "hashmap.h"
+#include "pa/spaced.h"
+
+#define CONN_CCHECK_PASSTHRU	0
+#define CONN_CCHECK_SCANONLY	1
+#define CONN_CCHECK_OVERSIZE	2
+#define CONN_CCHECK_REDIRECT	3
 
 /*
  * Connection Definition
@@ -70,6 +77,15 @@
 		unsigned int major;
 		unsigned int minor;
 	} protocol;
+
+	char *response_line;
+	char *user_agent;
+	char *host_header;
+
+	hashmap_t server_headers;
+	int check_content;
+	char *forwarded_for;
+	pasd_handle_t *spacedaemon;     /* Handle for PA-Spacedaemon */
 };
 
 /*
diff -Naur tinyproxy-1.6.2-orig/src/grammar.c tinyproxy-1.6.2/src/grammar.c
--- tinyproxy-1.6.2-orig/src/grammar.c	2003-08-06 22:47:56.000000000 +0200
+++ tinyproxy-1.6.2/src/grammar.c	2009-08-28 10:48:00.000000000 +0200
@@ -1,7 +1,7 @@
-/* A Bison parser, made by GNU Bison 1.875a.  */
+/* A Bison parser, made by GNU Bison 1.875d.  */
 
 /* Skeleton parser for Yacc-like parsing with Bison,
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -83,20 +83,41 @@
      KW_DEFAULT_ERRORPAGE = 285,
      KW_STATPAGE = 286,
      KW_VIA_PROXY_NAME = 287,
-     KW_YES = 288,
-     KW_NO = 289,
-     KW_LOGLEVEL = 290,
-     KW_LOG_CRITICAL = 291,
-     KW_LOG_ERROR = 292,
-     KW_LOG_WARNING = 293,
-     KW_LOG_NOTICE = 294,
-     KW_LOG_CONNECT = 295,
-     KW_LOG_INFO = 296,
-     IDENTIFIER = 297,
-     NUMBER = 298,
-     STRING = 299,
-     NUMERIC_ADDRESS = 300,
-     NETMASK_ADDRESS = 301
+     KW_CLAMAV_PORT = 288,
+     KW_CCHECK_ERR_FILE = 289,
+     KW_ADMIN_EMAIL = 290,
+     KW_CCHECK_MIME_EXCLUDE = 291,
+     KW_CHROOT = 292,
+     KW_CCHECK_MAX_SIZE = 293,
+     KW_CCHECK_MIN_FREE = 294,
+     KW_CCHECK_TEMP_DIR = 295,
+     KW_CCHECK_VIRT_DIR = 296,
+     KW_CCHECK_MAX_SIZE_PASS = 297,
+     KW_CCHECK_REDIRECT_URL = 298,
+     KW_CCHECK_USE_REAL_SIZE = 299,
+     KW_CCHECK_SAFE_URL = 300,
+     KW_CCHECK_PI_THRESH = 301,
+     KW_CCHECK_PEEKBUF_SIZE = 302,
+     KW_CCHECK_SCAN_RETRIES = 303,
+     KW_CCHECK_UPD_INTERVAL = 304,
+     KW_CCHECK_REDIRECT_UA = 305,
+     KW_ADD_ERR_TEXT = 306,
+     KW_YES = 307,
+     KW_NO = 308,
+     KW_LOGLEVEL = 309,
+     KW_LOG_CRITICAL = 310,
+     KW_LOG_ERROR = 311,
+     KW_LOG_WARNING = 312,
+     KW_LOG_NOTICE = 313,
+     KW_LOG_CONNECT = 314,
+     KW_LOG_INFO = 315,
+     IDENTIFIER = 316,
+     NUMBER = 317,
+     STRING = 318,
+     NUMERIC_ADDRESS = 319,
+     NETMASK_ADDRESS = 320,
+     MIME_TYPE = 321,
+     PCRE_STRING = 322
    };
 #endif
 #define KW_PORT 258
@@ -129,20 +150,41 @@
 #define KW_DEFAULT_ERRORPAGE 285
 #define KW_STATPAGE 286
 #define KW_VIA_PROXY_NAME 287
-#define KW_YES 288
-#define KW_NO 289
-#define KW_LOGLEVEL 290
-#define KW_LOG_CRITICAL 291
-#define KW_LOG_ERROR 292
-#define KW_LOG_WARNING 293
-#define KW_LOG_NOTICE 294
-#define KW_LOG_CONNECT 295
-#define KW_LOG_INFO 296
-#define IDENTIFIER 297
-#define NUMBER 298
-#define STRING 299
-#define NUMERIC_ADDRESS 300
-#define NETMASK_ADDRESS 301
+#define KW_CLAMAV_PORT 288
+#define KW_CCHECK_ERR_FILE 289
+#define KW_ADMIN_EMAIL 290
+#define KW_CCHECK_MIME_EXCLUDE 291
+#define KW_CHROOT 292
+#define KW_CCHECK_MAX_SIZE 293
+#define KW_CCHECK_MIN_FREE 294
+#define KW_CCHECK_TEMP_DIR 295
+#define KW_CCHECK_VIRT_DIR 296
+#define KW_CCHECK_MAX_SIZE_PASS 297
+#define KW_CCHECK_REDIRECT_URL 298
+#define KW_CCHECK_USE_REAL_SIZE 299
+#define KW_CCHECK_SAFE_URL 300
+#define KW_CCHECK_PI_THRESH 301
+#define KW_CCHECK_PEEKBUF_SIZE 302
+#define KW_CCHECK_SCAN_RETRIES 303
+#define KW_CCHECK_UPD_INTERVAL 304
+#define KW_CCHECK_REDIRECT_UA 305
+#define KW_ADD_ERR_TEXT 306
+#define KW_YES 307
+#define KW_NO 308
+#define KW_LOGLEVEL 309
+#define KW_LOG_CRITICAL 310
+#define KW_LOG_ERROR 311
+#define KW_LOG_WARNING 312
+#define KW_LOG_NOTICE 313
+#define KW_LOG_CONNECT 314
+#define KW_LOG_INFO 315
+#define IDENTIFIER 316
+#define NUMBER 317
+#define STRING 318
+#define NUMERIC_ADDRESS 319
+#define NETMASK_ADDRESS 320
+#define MIME_TYPE 321
+#define PCRE_STRING 322
 
 
 
@@ -186,7 +228,7 @@
 	char *cptr;
 } YYSTYPE;
 /* Line 191 of yacc.c.  */
-#line 190 "y.tab.c"
+#line 232 "y.tab.c"
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
 # define YYSTYPE_IS_TRIVIAL 1
@@ -198,22 +240,29 @@
 
 
 /* Line 214 of yacc.c.  */
-#line 202 "y.tab.c"
+#line 244 "y.tab.c"
 
 #if ! defined (yyoverflow) || YYERROR_VERBOSE
 
+# ifndef YYFREE
+#  define YYFREE free
+# endif
+# ifndef YYMALLOC
+#  define YYMALLOC malloc
+# endif
+
 /* The parser invokes alloca or malloc; define the necessary symbols.  */
 
-# if YYSTACK_USE_ALLOCA
-#  define YYSTACK_ALLOC alloca
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   define YYSTACK_ALLOC alloca
+#  endif
 # else
-#  ifndef YYSTACK_USE_ALLOCA
-#   if defined (alloca) || defined (_ALLOCA_H)
-#    define YYSTACK_ALLOC alloca
-#   else
-#    ifdef __GNUC__
-#     define YYSTACK_ALLOC __builtin_alloca
-#    endif
+#  if defined (alloca) || defined (_ALLOCA_H)
+#   define YYSTACK_ALLOC alloca
+#  else
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
 #   endif
 #  endif
 # endif
@@ -226,20 +275,20 @@
 #   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
 #   define YYSIZE_T size_t
 #  endif
-#  define YYSTACK_ALLOC malloc
-#  define YYSTACK_FREE free
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
 # endif
 #endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
 
 
 #if (! defined (yyoverflow) \
      && (! defined (__cplusplus) \
-	 || (YYSTYPE_IS_TRIVIAL)))
+	 || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL)))
 
 /* A type that is properly aligned for any stack member.  */
 union yyalloc
 {
-  short yyss;
+  short int yyss;
   YYSTYPE yyvs;
   };
 
@@ -249,13 +298,13 @@
 /* The size of an array large to enough to hold all stacks, each with
    N elements.  */
 # define YYSTACK_BYTES(N) \
-     ((N) * (sizeof (short) + sizeof (YYSTYPE))				\
+     ((N) * (sizeof (short int) + sizeof (YYSTYPE))			\
       + YYSTACK_GAP_MAXIMUM)
 
 /* Copy COUNT objects from FROM to TO.  The source and destination do
    not overlap.  */
 # ifndef YYCOPY
-#  if 1 < __GNUC__
+#  if defined (__GNUC__) && 1 < __GNUC__
 #   define YYCOPY(To, From, Count) \
       __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
 #  else
@@ -291,26 +340,26 @@
 #if defined (__STDC__) || defined (__cplusplus)
    typedef signed char yysigned_char;
 #else
-   typedef short yysigned_char;
+   typedef short int yysigned_char;
 #endif
 
 /* YYFINAL -- State number of the termination state. */
 #define YYFINAL  2
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   83
+#define YYLAST   152
 
 /* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS  49
+#define YYNTOKENS  70
 /* YYNNTS -- Number of nonterminals. */
 #define YYNNTS  9
 /* YYNRULES -- Number of rules. */
-#define YYNRULES  53
+#define YYNRULES  72
 /* YYNRULES -- Number of states. */
-#define YYNSTATES  91
+#define YYNSTATES  129
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   301
+#define YYMAXUTOK   322
 
 #define YYTRANSLATE(YYX) 						\
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -319,11 +368,11 @@
 static const unsigned char yytranslate[] =
 {
        0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-      47,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+      68,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,    48,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    69,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -348,7 +397,9 @@
       15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
       25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
       35,    36,    37,    38,    39,    40,    41,    42,    43,    44,
-      45,    46
+      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+      55,    56,    57,    58,    59,    60,    61,    62,    63,    64,
+      65,    66,    67
 };
 
 #if YYDEBUG
@@ -360,39 +411,49 @@
       24,    27,    30,    33,    36,    39,    42,    45,    48,    51,
       55,    58,    61,    64,    67,    70,    73,    76,    79,    84,
       90,    94,    97,   100,   103,   106,   109,   112,   115,   118,
-     120,   122,   124,   126,   128,   130,   132,   134,   136,   138,
-     140,   142,   144,   146
+     121,   124,   127,   130,   133,   136,   139,   142,   145,   148,
+     151,   154,   157,   160,   163,   166,   169,   172,   175,   177,
+     179,   181,   183,   185,   187,   189,   191,   193,   195,   197,
+     199,   201,   203
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS. */
 static const yysigned_char yyrhs[] =
 {
-      50,     0,    -1,    -1,    50,    51,    -1,    47,    -1,    52,
-      47,    -1,     3,    43,    -1,    13,    43,    -1,     7,    56,
-      -1,     8,    43,    -1,     9,    43,    -1,    10,    43,    -1,
-      11,    43,    -1,    12,    43,    -1,     5,    57,    -1,     6,
-      57,    -1,    14,    57,    -1,    15,    57,    -1,    16,    57,
-      -1,    29,    43,    57,    -1,    30,    57,    -1,    31,    57,
-      -1,    18,    57,    -1,    19,    56,    -1,    20,    56,    -1,
-      22,    56,    -1,    21,    56,    -1,    17,    54,    -1,    23,
-      55,    48,    43,    -1,    23,    55,    48,    43,    44,    -1,
-      34,    23,    44,    -1,     4,    45,    -1,    27,    54,    -1,
-      28,    54,    -1,    35,    53,    -1,    24,    43,    -1,    25,
-      45,    -1,    32,    57,    -1,    26,    57,    -1,    36,    -1,
-      37,    -1,    38,    -1,    39,    -1,    40,    -1,    41,    -1,
-      55,    -1,    46,    -1,    42,    -1,    45,    -1,    33,    -1,
-      34,    -1,    43,    -1,    42,    -1,    44,    -1
+      71,     0,    -1,    -1,    71,    72,    -1,    68,    -1,    73,
+      68,    -1,     3,    62,    -1,    13,    62,    -1,     7,    77,
+      -1,     8,    62,    -1,     9,    62,    -1,    10,    62,    -1,
+      11,    62,    -1,    12,    62,    -1,     5,    78,    -1,     6,
+      78,    -1,    14,    78,    -1,    15,    78,    -1,    16,    78,
+      -1,    29,    62,    78,    -1,    30,    78,    -1,    31,    78,
+      -1,    18,    78,    -1,    19,    77,    -1,    20,    77,    -1,
+      22,    77,    -1,    21,    77,    -1,    17,    75,    -1,    23,
+      76,    69,    62,    -1,    23,    76,    69,    62,    63,    -1,
+      53,    23,    63,    -1,     4,    64,    -1,    27,    75,    -1,
+      28,    75,    -1,    54,    74,    -1,    24,    62,    -1,    25,
+      64,    -1,    32,    78,    -1,    26,    78,    -1,    33,    62,
+      -1,    34,    78,    -1,    35,    78,    -1,    36,    66,    -1,
+      45,    67,    -1,    50,    67,    -1,    37,    78,    -1,    38,
+      62,    -1,    46,    62,    -1,    42,    62,    -1,    44,    62,
+      -1,    39,    62,    -1,    40,    78,    -1,    41,    78,    -1,
+      43,    78,    -1,    47,    62,    -1,    48,    62,    -1,    49,
+      62,    -1,    51,    78,    -1,    55,    -1,    56,    -1,    57,
+      -1,    58,    -1,    59,    -1,    60,    -1,    76,    -1,    65,
+      -1,    61,    -1,    64,    -1,    52,    -1,    53,    -1,    62,
+      -1,    61,    -1,    63,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
-static const unsigned char yyrline[] =
+static const unsigned short int yyrline[] =
 {
-       0,    81,    81,    83,    87,    88,    92,    93,    94,   102,
-     103,   104,   105,   106,   107,   114,   115,   116,   117,   118,
-     119,   120,   121,   129,   137,   145,   153,   162,   170,   178,
-     186,   194,   199,   200,   201,   202,   203,   212,   217,   225,
-     226,   227,   228,   229,   230,   234,   235,   239,   240,   244,
-     245,   246,   250,   251
+       0,    90,    90,    92,    96,    97,   101,   102,   103,   111,
+     112,   113,   114,   115,   116,   123,   124,   125,   126,   127,
+     128,   129,   130,   138,   146,   154,   162,   171,   179,   187,
+     195,   203,   208,   209,   210,   211,   212,   221,   226,   231,
+     232,   233,   234,   236,   238,   240,   241,   242,   243,   244,
+     245,   247,   248,   249,   250,   251,   252,   253,   257,   258,
+     259,   260,   261,   262,   266,   267,   271,   272,   276,   277,
+     278,   282,   283
 };
 #endif
 
@@ -401,45 +462,56 @@
    First, the terminals, then, starting at YYNTOKENS, nonterminals. */
 static const char *const yytname[] =
 {
-  "$end", "error", "$undefined", "KW_PORT", "KW_LISTEN", "KW_LOGFILE", 
-  "KW_PIDFILE", "KW_SYSLOG", "KW_MAXCLIENTS", "KW_MAXSPARESERVERS", 
-  "KW_MINSPARESERVERS", "KW_STARTSERVERS", "KW_MAXREQUESTSPERCHILD", 
-  "KW_TIMEOUT", "KW_USER", "KW_GROUP", "KW_ANONYMOUS", "KW_XTINYPROXY", 
-  "KW_FILTER", "KW_FILTERURLS", "KW_FILTEREXTENDED", 
-  "KW_FILTER_DEFAULT_DENY", "KW_FILTER_CASESENSITIVE", "KW_UPSTREAM", 
-  "KW_CONNECTPORT", "KW_BIND", "KW_STATHOST", "KW_ALLOW", "KW_DENY", 
-  "KW_ERRORPAGE", "KW_DEFAULT_ERRORPAGE", "KW_STATPAGE", 
-  "KW_VIA_PROXY_NAME", "KW_YES", "KW_NO", "KW_LOGLEVEL", 
-  "KW_LOG_CRITICAL", "KW_LOG_ERROR", "KW_LOG_WARNING", "KW_LOG_NOTICE", 
-  "KW_LOG_CONNECT", "KW_LOG_INFO", "IDENTIFIER", "NUMBER", "STRING", 
-  "NUMERIC_ADDRESS", "NETMASK_ADDRESS", "'\\n'", "':'", "$accept", 
-  "start", "line", "statement", "loglevels", "network_address", 
-  "unique_address", "yesno", "string", 0
+  "$end", "error", "$undefined", "KW_PORT", "KW_LISTEN", "KW_LOGFILE",
+  "KW_PIDFILE", "KW_SYSLOG", "KW_MAXCLIENTS", "KW_MAXSPARESERVERS",
+  "KW_MINSPARESERVERS", "KW_STARTSERVERS", "KW_MAXREQUESTSPERCHILD",
+  "KW_TIMEOUT", "KW_USER", "KW_GROUP", "KW_ANONYMOUS", "KW_XTINYPROXY",
+  "KW_FILTER", "KW_FILTERURLS", "KW_FILTEREXTENDED",
+  "KW_FILTER_DEFAULT_DENY", "KW_FILTER_CASESENSITIVE", "KW_UPSTREAM",
+  "KW_CONNECTPORT", "KW_BIND", "KW_STATHOST", "KW_ALLOW", "KW_DENY",
+  "KW_ERRORPAGE", "KW_DEFAULT_ERRORPAGE", "KW_STATPAGE",
+  "KW_VIA_PROXY_NAME", "KW_CLAMAV_PORT", "KW_CCHECK_ERR_FILE",
+  "KW_ADMIN_EMAIL", "KW_CCHECK_MIME_EXCLUDE", "KW_CHROOT",
+  "KW_CCHECK_MAX_SIZE", "KW_CCHECK_MIN_FREE", "KW_CCHECK_TEMP_DIR",
+  "KW_CCHECK_VIRT_DIR", "KW_CCHECK_MAX_SIZE_PASS",
+  "KW_CCHECK_REDIRECT_URL", "KW_CCHECK_USE_REAL_SIZE",
+  "KW_CCHECK_SAFE_URL", "KW_CCHECK_PI_THRESH", "KW_CCHECK_PEEKBUF_SIZE",
+  "KW_CCHECK_SCAN_RETRIES", "KW_CCHECK_UPD_INTERVAL",
+  "KW_CCHECK_REDIRECT_UA", "KW_ADD_ERR_TEXT", "KW_YES", "KW_NO",
+  "KW_LOGLEVEL", "KW_LOG_CRITICAL", "KW_LOG_ERROR", "KW_LOG_WARNING",
+  "KW_LOG_NOTICE", "KW_LOG_CONNECT", "KW_LOG_INFO", "IDENTIFIER", "NUMBER",
+  "STRING", "NUMERIC_ADDRESS", "NETMASK_ADDRESS", "MIME_TYPE",
+  "PCRE_STRING", "'\\n'", "':'", "$accept", "start", "line", "statement",
+  "loglevels", "network_address", "unique_address", "yesno", "string", 0
 };
 #endif
 
 # ifdef YYPRINT
 /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
    token YYLEX-NUM.  */
-static const unsigned short yytoknum[] =
+static const unsigned short int yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
      265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
      275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
      285,   286,   287,   288,   289,   290,   291,   292,   293,   294,
-     295,   296,   297,   298,   299,   300,   301,    10,    58
+     295,   296,   297,   298,   299,   300,   301,   302,   303,   304,
+     305,   306,   307,   308,   309,   310,   311,   312,   313,   314,
+     315,   316,   317,   318,   319,   320,   321,   322,    10,    58
 };
 # endif
 
 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const unsigned char yyr1[] =
 {
-       0,    49,    50,    50,    51,    51,    52,    52,    52,    52,
-      52,    52,    52,    52,    52,    52,    52,    52,    52,    52,
-      52,    52,    52,    52,    52,    52,    52,    52,    52,    52,
-      52,    52,    52,    52,    52,    52,    52,    52,    52,    53,
-      53,    53,    53,    53,    53,    54,    54,    55,    55,    56,
-      56,    56,    57,    57
+       0,    70,    71,    71,    72,    72,    73,    73,    73,    73,
+      73,    73,    73,    73,    73,    73,    73,    73,    73,    73,
+      73,    73,    73,    73,    73,    73,    73,    73,    73,    73,
+      73,    73,    73,    73,    73,    73,    73,    73,    73,    73,
+      73,    73,    73,    73,    73,    73,    73,    73,    73,    73,
+      73,    73,    73,    73,    73,    73,    73,    73,    74,    74,
+      74,    74,    74,    74,    75,    75,    76,    76,    77,    77,
+      77,    78,    78
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
@@ -448,9 +520,11 @@
        0,     2,     0,     2,     1,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     3,
        2,     2,     2,     2,     2,     2,     2,     2,     4,     5,
-       3,     2,     2,     2,     2,     2,     2,     2,     2,     1,
+       3,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     1,     1,
        1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
-       1,     1,     1,     1
+       1,     1,     1
 };
 
 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -461,42 +535,48 @@
        2,     0,     1,     0,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     4,     3,     0,     6,    31,
-      52,    53,    14,    15,    49,    50,    51,     8,     9,    10,
-      11,    12,    13,     7,    16,    17,    18,    47,    48,    46,
-      27,    45,    22,    23,    24,    26,    25,     0,    35,    36,
-      38,    32,    33,     0,    20,    21,    37,     0,    39,    40,
-      41,    42,    43,    44,    34,     5,     0,    19,    30,    28,
-      29
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     4,     3,     0,     6,    31,    71,
+      72,    14,    15,    68,    69,    70,     8,     9,    10,    11,
+      12,    13,     7,    16,    17,    18,    66,    67,    65,    27,
+      64,    22,    23,    24,    26,    25,     0,    35,    36,    38,
+      32,    33,     0,    20,    21,    37,    39,    40,    41,    42,
+      45,    46,    50,    51,    52,    48,    53,    49,    43,    47,
+      54,    55,    56,    44,    57,     0,    58,    59,    60,    61,
+      62,    63,    34,     5,     0,    19,    30,    28,    29
 };
 
 /* YYDEFGOTO[NTERM-NUM]. */
 static const yysigned_char yydefgoto[] =
 {
-      -1,     1,    36,    37,    84,    60,    61,    47,    42
+      -1,     1,    55,    56,   122,    79,    80,    66,    61
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -42
+#define YYPACT_NINF -59
 static const yysigned_char yypact[] =
 {
-     -42,    27,   -42,   -38,   -41,   -21,   -21,   -32,   -24,    17,
-      29,    30,    32,    33,   -21,   -21,   -21,   -39,   -21,   -32,
-     -32,   -32,   -32,    26,    34,    24,   -21,   -39,   -39,    35,
-     -21,   -21,   -21,    -1,   -23,   -42,   -42,    23,   -42,   -42,
-     -42,   -42,   -42,   -42,   -42,   -42,   -42,   -42,   -42,   -42,
-     -42,   -42,   -42,   -42,   -42,   -42,   -42,   -42,   -42,   -42,
-     -42,   -42,   -42,   -42,   -42,   -42,   -42,    31,   -42,   -42,
-     -42,   -42,   -42,   -21,   -42,   -42,   -42,    36,   -42,   -42,
-     -42,   -42,   -42,   -42,   -42,   -42,    38,   -42,   -42,    39,
-     -42
+     -59,    84,   -59,   -43,   -32,   -40,   -40,   -51,   -29,   -26,
+     -20,   -19,   -18,   -16,   -40,   -40,   -40,   -58,   -40,   -51,
+     -51,   -51,   -51,   -34,   -15,   -14,   -40,   -58,   -58,   -13,
+     -40,   -40,   -40,   -11,   -40,   -40,   -44,   -40,   -10,    -9,
+     -40,   -40,    -8,   -40,    -7,    -5,    -4,    -3,    -2,    -1,
+       0,   -40,    25,   -42,   -59,   -59,   -12,   -59,   -59,   -59,
+     -59,   -59,   -59,   -59,   -59,   -59,   -59,   -59,   -59,   -59,
+     -59,   -59,   -59,   -59,   -59,   -59,   -59,   -59,   -59,   -59,
+     -59,   -59,   -59,   -59,   -59,   -59,     1,   -59,   -59,   -59,
+     -59,   -59,   -40,   -59,   -59,   -59,   -59,   -59,   -59,   -59,
+     -59,   -59,   -59,   -59,   -59,   -59,   -59,   -59,   -59,   -59,
+     -59,   -59,   -59,   -59,   -59,     2,   -59,   -59,   -59,   -59,
+     -59,   -59,   -59,   -59,     4,   -59,   -59,     5,   -59
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yysigned_char yypgoto[] =
 {
-     -42,   -42,   -42,   -42,   -42,     1,    59,    44,    -6
+     -59,   -59,   -59,   -59,   -59,   -23,    34,    19,    -6
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
@@ -506,44 +586,61 @@
 #define YYTABLE_NINF -1
 static const unsigned char yytable[] =
 {
-      43,    44,    45,    57,    39,    38,    58,    59,    54,    55,
-      56,    46,    62,    78,    79,    80,    81,    82,    83,    48,
-      70,    40,    77,    41,    74,    75,    76,     2,    71,    72,
-       3,     4,     5,     6,     7,     8,     9,    10,    11,    12,
-      13,    14,    15,    16,    17,    18,    19,    20,    21,    22,
-      23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
-      49,    33,    34,    63,    64,    65,    66,    87,    57,    69,
-      85,    58,    50,    51,    35,    52,    53,    68,    73,    86,
-      88,    89,    67,    90
+      62,    63,    64,    76,    90,    91,    77,    78,    73,    74,
+      75,    65,    81,   116,   117,   118,   119,   120,   121,    57,
+      89,    59,    99,    60,    93,    94,    95,    76,    97,    98,
+      77,   100,    58,    67,   103,   104,    68,   106,    82,    83,
+      84,    85,    69,    70,    71,   114,    72,    87,   115,    92,
+      88,    96,   101,   102,   105,   107,   123,    86,   109,   110,
+     111,   112,   108,     0,     0,   126,   127,   113,   128,     0,
+     124,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     2,     0,   125,     3,     4,     5,
+       6,     7,     8,     9,    10,    11,    12,    13,    14,    15,
+      16,    17,    18,    19,    20,    21,    22,    23,    24,    25,
+      26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
+      36,    37,    38,    39,    40,    41,    42,    43,    44,    45,
+      46,    47,    48,    49,    50,    51,     0,    52,    53,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,    54
 };
 
-static const unsigned char yycheck[] =
+static const yysigned_char yycheck[] =
 {
-       6,    33,    34,    42,    45,    43,    45,    46,    14,    15,
-      16,    43,    18,    36,    37,    38,    39,    40,    41,    43,
-      26,    42,    23,    44,    30,    31,    32,     0,    27,    28,
-       3,     4,     5,     6,     7,     8,     9,    10,    11,    12,
-      13,    14,    15,    16,    17,    18,    19,    20,    21,    22,
-      23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
-      43,    34,    35,    19,    20,    21,    22,    73,    42,    45,
-      47,    45,    43,    43,    47,    43,    43,    43,    43,    48,
-      44,    43,    23,    44
+       6,    52,    53,    61,    27,    28,    64,    65,    14,    15,
+      16,    62,    18,    55,    56,    57,    58,    59,    60,    62,
+      26,    61,    66,    63,    30,    31,    32,    61,    34,    35,
+      64,    37,    64,    62,    40,    41,    62,    43,    19,    20,
+      21,    22,    62,    62,    62,    51,    62,    62,    23,    62,
+      64,    62,    62,    62,    62,    62,    68,    23,    62,    62,
+      62,    62,    67,    -1,    -1,    63,    62,    67,    63,    -1,
+      69,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,     0,    -1,    92,     3,     4,     5,
+       6,     7,     8,     9,    10,    11,    12,    13,    14,    15,
+      16,    17,    18,    19,    20,    21,    22,    23,    24,    25,
+      26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
+      36,    37,    38,    39,    40,    41,    42,    43,    44,    45,
+      46,    47,    48,    49,    50,    51,    -1,    53,    54,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    68
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const unsigned char yystos[] =
 {
-       0,    50,     0,     3,     4,     5,     6,     7,     8,     9,
+       0,    71,     0,     3,     4,     5,     6,     7,     8,     9,
       10,    11,    12,    13,    14,    15,    16,    17,    18,    19,
       20,    21,    22,    23,    24,    25,    26,    27,    28,    29,
-      30,    31,    32,    34,    35,    47,    51,    52,    43,    45,
-      42,    44,    57,    57,    33,    34,    43,    56,    43,    43,
-      43,    43,    43,    43,    57,    57,    57,    42,    45,    46,
-      54,    55,    57,    56,    56,    56,    56,    55,    43,    45,
-      57,    54,    54,    43,    57,    57,    57,    23,    36,    37,
-      38,    39,    40,    41,    53,    47,    48,    57,    44,    43,
-      44
+      30,    31,    32,    33,    34,    35,    36,    37,    38,    39,
+      40,    41,    42,    43,    44,    45,    46,    47,    48,    49,
+      50,    51,    53,    54,    68,    72,    73,    62,    64,    61,
+      63,    78,    78,    52,    53,    62,    77,    62,    62,    62,
+      62,    62,    62,    78,    78,    78,    61,    64,    65,    75,
+      76,    78,    77,    77,    77,    77,    76,    62,    64,    78,
+      75,    75,    62,    78,    78,    78,    62,    78,    78,    66,
+      78,    62,    62,    78,    78,    62,    78,    62,    67,    62,
+      62,    62,    62,    67,    78,    23,    55,    56,    57,    58,
+      59,    60,    74,    68,    69,    78,    63,    62,    63
 };
 
 #if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
@@ -569,7 +666,7 @@
 
 #define YYACCEPT	goto yyacceptlab
 #define YYABORT		goto yyabortlab
-#define YYERROR		goto yyerrlab1
+#define YYERROR		goto yyerrorlab
 
 
 /* Like YYERROR except do call yyerror.  This remains here temporarily
@@ -604,11 +701,11 @@
    are run).  */
 
 #ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N)         \
-  Current.first_line   = Rhs[1].first_line;      \
-  Current.first_column = Rhs[1].first_column;    \
-  Current.last_line    = Rhs[N].last_line;       \
-  Current.last_column  = Rhs[N].last_column;
+# define YYLLOC_DEFAULT(Current, Rhs, N)		\
+   ((Current).first_line   = (Rhs)[1].first_line,	\
+    (Current).first_column = (Rhs)[1].first_column,	\
+    (Current).last_line    = (Rhs)[N].last_line,	\
+    (Current).last_column  = (Rhs)[N].last_column)
 #endif
 
 /* YYLEX -- calling `yylex' with the right arguments.  */
@@ -652,17 +749,17 @@
 
 /*------------------------------------------------------------------.
 | yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (cinluded).                                                   |
+| TOP (included).                                                   |
 `------------------------------------------------------------------*/
 
 #if defined (__STDC__) || defined (__cplusplus)
 static void
-yy_stack_print (short *bottom, short *top)
+yy_stack_print (short int *bottom, short int *top)
 #else
 static void
 yy_stack_print (bottom, top)
-    short *bottom;
-    short *top;
+    short int *bottom;
+    short int *top;
 #endif
 {
   YYFPRINTF (stderr, "Stack now");
@@ -692,9 +789,9 @@
 #endif
 {
   int yyi;
-  unsigned int yylineno = yyrline[yyrule];
+  unsigned int yylno = yyrline[yyrule];
   YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
-             yyrule - 1, yylineno);
+             yyrule - 1, yylno);
   /* Print the symbols being reduced, and their result.  */
   for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
     YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
@@ -731,7 +828,7 @@
    SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
    evaluated with infinite-precision integer arithmetic.  */
 
-#if YYMAXDEPTH == 0
+#if defined (YYMAXDEPTH) && YYMAXDEPTH == 0
 # undef YYMAXDEPTH
 #endif
 
@@ -929,9 +1026,9 @@
      to reallocate them elsewhere.  */
 
   /* The state stack.  */
-  short	yyssa[YYINITDEPTH];
-  short *yyss = yyssa;
-  register short *yyssp;
+  short int yyssa[YYINITDEPTH];
+  short int *yyss = yyssa;
+  register short int *yyssp;
 
   /* The semantic value stack.  */
   YYSTYPE yyvsa[YYINITDEPTH];
@@ -968,6 +1065,7 @@
   yyssp = yyss;
   yyvsp = yyvs;
 
+
   goto yysetstate;
 
 /*------------------------------------------------------------.
@@ -993,7 +1091,7 @@
 	   these so that the &'s don't force the real ones into
 	   memory.  */
 	YYSTYPE *yyvs1 = yyvs;
-	short *yyss1 = yyss;
+	short int *yyss1 = yyss;
 
 
 	/* Each stack pointer address is followed by the size of the
@@ -1021,7 +1119,7 @@
 	yystacksize = YYMAXDEPTH;
 
       {
-	short *yyss1 = yyss;
+	short int *yyss1 = yyss;
 	union yyalloc *yyptr =
 	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
 	if (! yyptr)
@@ -1154,17 +1252,17 @@
   switch (yyn)
     {
         case 6:
-#line 92 "grammar.y"
+#line 101 "grammar.y"
     { config.port = yyvsp[0].num; }
     break;
 
   case 7:
-#line 93 "grammar.y"
+#line 102 "grammar.y"
     { config.idletimeout = yyvsp[0].num; }
     break;
 
   case 8:
-#line 95 "grammar.y"
+#line 104 "grammar.y"
     {
 #ifdef HAVE_SYSLOG_H
 	          config.syslog = yyvsp[0].num;
@@ -1175,32 +1273,32 @@
     break;
 
   case 9:
-#line 102 "grammar.y"
+#line 111 "grammar.y"
     { child_configure(CHILD_MAXCLIENTS, yyvsp[0].num); }
     break;
 
   case 10:
-#line 103 "grammar.y"
+#line 112 "grammar.y"
     { child_configure(CHILD_MAXSPARESERVERS, yyvsp[0].num); }
     break;
 
   case 11:
-#line 104 "grammar.y"
+#line 113 "grammar.y"
     { child_configure(CHILD_MINSPARESERVERS, yyvsp[0].num); }
     break;
 
   case 12:
-#line 105 "grammar.y"
+#line 114 "grammar.y"
     { child_configure(CHILD_STARTSERVERS, yyvsp[0].num); }
     break;
 
   case 13:
-#line 106 "grammar.y"
+#line 115 "grammar.y"
     { child_configure(CHILD_MAXREQUESTSPERCHILD, yyvsp[0].num); }
     break;
 
   case 14:
-#line 108 "grammar.y"
+#line 117 "grammar.y"
     {
 	          config.logf_name = yyvsp[0].cptr;
 		  if (!config.logf_name) {
@@ -1210,42 +1308,42 @@
     break;
 
   case 15:
-#line 114 "grammar.y"
+#line 123 "grammar.y"
     { config.pidpath = yyvsp[0].cptr; }
     break;
 
   case 16:
-#line 115 "grammar.y"
+#line 124 "grammar.y"
     { config.username = yyvsp[0].cptr; }
     break;
 
   case 17:
-#line 116 "grammar.y"
+#line 125 "grammar.y"
     { config.group = yyvsp[0].cptr; }
     break;
 
   case 18:
-#line 117 "grammar.y"
+#line 126 "grammar.y"
     { anonymous_insert(yyvsp[0].cptr); }
     break;
 
   case 19:
-#line 118 "grammar.y"
+#line 127 "grammar.y"
     { add_new_errorpage(yyvsp[0].cptr, yyvsp[-1].num); }
     break;
 
   case 20:
-#line 119 "grammar.y"
+#line 128 "grammar.y"
     { config.errorpage_undef = yyvsp[0].cptr; }
     break;
 
   case 21:
-#line 120 "grammar.y"
+#line 129 "grammar.y"
     { config.statpage = yyvsp[0].cptr; }
     break;
 
   case 22:
-#line 122 "grammar.y"
+#line 131 "grammar.y"
     {
 #ifdef FILTER_ENABLE
 		  config.filter = yyvsp[0].cptr;
@@ -1256,7 +1354,7 @@
     break;
 
   case 23:
-#line 130 "grammar.y"
+#line 139 "grammar.y"
     {
 #ifdef FILTER_ENABLE
 		  config.filter_url = yyvsp[0].num;
@@ -1267,7 +1365,7 @@
     break;
 
   case 24:
-#line 138 "grammar.y"
+#line 147 "grammar.y"
     {
 #ifdef FILTER_ENABLE
 		  config.filter_extended = yyvsp[0].num;
@@ -1278,7 +1376,7 @@
     break;
 
   case 25:
-#line 146 "grammar.y"
+#line 155 "grammar.y"
     {
 #ifdef FILTER_ENABLE
 		  config.filter_casesensitive = yyvsp[0].num;
@@ -1289,7 +1387,7 @@
     break;
 
   case 26:
-#line 154 "grammar.y"
+#line 163 "grammar.y"
     {
 #ifdef FILTER_ENABLE
 		  if (yyvsp[0].num)
@@ -1301,7 +1399,7 @@
     break;
 
   case 27:
-#line 163 "grammar.y"
+#line 172 "grammar.y"
     {
 #ifdef XTINYPROXY_ENABLE
 	   	  config.my_domain = yyvsp[0].cptr;
@@ -1312,7 +1410,7 @@
     break;
 
   case 28:
-#line 171 "grammar.y"
+#line 180 "grammar.y"
     {
 #ifdef UPSTREAM_SUPPORT
 		  upstream_add(yyvsp[-2].cptr, yyvsp[0].num, NULL);
@@ -1323,7 +1421,7 @@
     break;
 
   case 29:
-#line 179 "grammar.y"
+#line 188 "grammar.y"
     {
 #ifdef UPSTREAM_SUPPORT
 		  upstream_add(yyvsp[-3].cptr, yyvsp[-1].num, yyvsp[0].cptr);
@@ -1334,7 +1432,7 @@
     break;
 
   case 30:
-#line 187 "grammar.y"
+#line 196 "grammar.y"
     {
 #ifdef UPSTREAM_SUPPORT
 		  upstream_add(NULL, 0, yyvsp[0].cptr);
@@ -1345,7 +1443,7 @@
     break;
 
   case 31:
-#line 195 "grammar.y"
+#line 204 "grammar.y"
     {
 		  log_message(LOG_INFO, "Establishing listening socket on IP %s", yyvsp[0].cptr);
                   config.ipAddr = yyvsp[0].cptr;
@@ -1353,27 +1451,27 @@
     break;
 
   case 32:
-#line 199 "grammar.y"
+#line 208 "grammar.y"
     { insert_acl(yyvsp[0].cptr, ACL_ALLOW); }
     break;
 
   case 33:
-#line 200 "grammar.y"
+#line 209 "grammar.y"
     { insert_acl(yyvsp[0].cptr, ACL_DENY); }
     break;
 
   case 34:
-#line 201 "grammar.y"
+#line 210 "grammar.y"
     { set_log_level(yyvsp[0].num); }
     break;
 
   case 35:
-#line 202 "grammar.y"
+#line 211 "grammar.y"
     { add_connect_port_allowed(yyvsp[0].num); }
     break;
 
   case 36:
-#line 204 "grammar.y"
+#line 213 "grammar.y"
     {
 #ifndef TRANSPARENT_PROXY
 		  log_message(LOG_INFO, "Binding outgoing connections to %s", yyvsp[0].cptr);
@@ -1385,7 +1483,7 @@
     break;
 
   case 37:
-#line 213 "grammar.y"
+#line 222 "grammar.y"
     {
 		  log_message(LOG_INFO, "Setting \"Via\" proxy name to: %s", yyvsp[0].cptr);
 		  config.via_proxy_name = yyvsp[0].cptr;
@@ -1393,7 +1491,7 @@
     break;
 
   case 38:
-#line 218 "grammar.y"
+#line 227 "grammar.y"
     {
 		  log_message(LOG_INFO, "Stathost is set to \"%s\"", yyvsp[0].cptr);
 		  config.stathost = yyvsp[0].cptr;
@@ -1401,55 +1499,151 @@
     break;
 
   case 39:
-#line 225 "grammar.y"
-    { yyval.num = LOG_CRIT; }
+#line 231 "grammar.y"
+    { config.clamav_port = yyvsp[0].num; }
     break;
 
   case 40:
-#line 226 "grammar.y"
-    { yyval.num = LOG_ERR; }
+#line 232 "grammar.y"
+    { config.ccheck_err_file = yyvsp[0].cptr; }
     break;
 
   case 41:
-#line 227 "grammar.y"
-    { yyval.num = LOG_WARNING; }
+#line 233 "grammar.y"
+    { config.admin_email = yyvsp[0].cptr; }
     break;
 
   case 42:
-#line 228 "grammar.y"
-    { yyval.num = LOG_NOTICE; }
+#line 235 "grammar.y"
+    { add_exclude_mime_type(yyvsp[0].cptr); }
     break;
 
   case 43:
-#line 229 "grammar.y"
-    { yyval.num = LOG_CONN; }
+#line 237 "grammar.y"
+    { add_exclude_url_regexp(yyvsp[0].cptr); }
     break;
 
   case 44:
-#line 230 "grammar.y"
-    { yyval.num = LOG_INFO; }
+#line 239 "grammar.y"
+    { add_user_agent_regexp(yyvsp[0].cptr); }
+    break;
+
+  case 45:
+#line 240 "grammar.y"
+    { config.chroot = yyvsp[0].cptr; }
+    break;
+
+  case 46:
+#line 241 "grammar.y"
+    { config.ccheck_max_size = yyvsp[0].num; }
+    break;
+
+  case 47:
+#line 242 "grammar.y"
+    { config.ccheck_pi_thresh = yyvsp[0].num; }
+    break;
+
+  case 48:
+#line 243 "grammar.y"
+    { config.ccheck_max_size_pass = yyvsp[0].num; }
     break;
 
   case 49:
 #line 244 "grammar.y"
-    { yyval.num = 1; }
+    { config.ccheck_use_real_size = yyvsp[0].num; }
     break;
 
   case 50:
 #line 245 "grammar.y"
-    { yyval.num = 0; }
+    { config.ccheck_min_free =  
+	                                  1024 * 1024 * yyvsp[0].num; }
     break;
 
   case 51:
-#line 246 "grammar.y"
+#line 247 "grammar.y"
+    { config.ccheck_temp_dir = yyvsp[0].cptr; }
+    break;
+
+  case 52:
+#line 248 "grammar.y"
+    { config.ccheck_virt_dir = yyvsp[0].cptr; }
+    break;
+
+  case 53:
+#line 249 "grammar.y"
+    { config.ccheck_redirect_url = yyvsp[0].cptr; }
+    break;
+
+  case 54:
+#line 250 "grammar.y"
+    { config.ccheck_peekbuf_size = yyvsp[0].num; }
+    break;
+
+  case 55:
+#line 251 "grammar.y"
+    { config.ccheck_scan_retries = yyvsp[0].num; }
+    break;
+
+  case 56:
+#line 252 "grammar.y"
+    { config.ccheck_upd_interval = yyvsp[0].num; }
+    break;
+
+  case 57:
+#line 253 "grammar.y"
+    { config.add_err_text = yyvsp[0].cptr; }
+    break;
+
+  case 58:
+#line 257 "grammar.y"
+    { yyval.num = LOG_CRIT; }
+    break;
+
+  case 59:
+#line 258 "grammar.y"
+    { yyval.num = LOG_ERR; }
+    break;
+
+  case 60:
+#line 259 "grammar.y"
+    { yyval.num = LOG_WARNING; }
+    break;
+
+  case 61:
+#line 260 "grammar.y"
+    { yyval.num = LOG_NOTICE; }
+    break;
+
+  case 62:
+#line 261 "grammar.y"
+    { yyval.num = LOG_CONN; }
+    break;
+
+  case 63:
+#line 262 "grammar.y"
+    { yyval.num = LOG_INFO; }
+    break;
+
+  case 68:
+#line 276 "grammar.y"
+    { yyval.num = 1; }
+    break;
+
+  case 69:
+#line 277 "grammar.y"
+    { yyval.num = 0; }
+    break;
+
+  case 70:
+#line 278 "grammar.y"
     { yyval.num = yyvsp[0].num; }
     break;
 
 
     }
 
-/* Line 999 of yacc.c.  */
-#line 1453 "y.tab.c"
+/* Line 1010 of yacc.c.  */
+#line 1647 "y.tab.c"
 
   yyvsp -= yylen;
   yyssp -= yylen;
@@ -1490,18 +1684,33 @@
 	{
 	  YYSIZE_T yysize = 0;
 	  int yytype = YYTRANSLATE (yychar);
+	  const char* yyprefix;
 	  char *yymsg;
-	  int yyx, yycount;
+	  int yyx;
 
-	  yycount = 0;
 	  /* Start YYX at -YYN if negative to avoid negative indexes in
 	     YYCHECK.  */
-	  for (yyx = yyn < 0 ? -yyn : 0;
-	       yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
+	  int yyxbegin = yyn < 0 ? -yyn : 0;
+
+	  /* Stay within bounds of both yycheck and yytname.  */
+	  int yychecklim = YYLAST - yyn;
+	  int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+	  int yycount = 0;
+
+	  yyprefix = ", expecting ";
+	  for (yyx = yyxbegin; yyx < yyxend; ++yyx)
 	    if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
-	      yysize += yystrlen (yytname[yyx]) + 15, yycount++;
-	  yysize += yystrlen ("syntax error, unexpected ") + 1;
-	  yysize += yystrlen (yytname[yytype]);
+	      {
+		yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]);
+		yycount += 1;
+		if (yycount == 5)
+		  {
+		    yysize = 0;
+		    break;
+		  }
+	      }
+	  yysize += (sizeof ("syntax error, unexpected ")
+		     + yystrlen (yytname[yytype]));
 	  yymsg = (char *) YYSTACK_ALLOC (yysize);
 	  if (yymsg != 0)
 	    {
@@ -1510,16 +1719,13 @@
 
 	      if (yycount < 5)
 		{
-		  yycount = 0;
-		  for (yyx = yyn < 0 ? -yyn : 0;
-		       yyx < (int) (sizeof (yytname) / sizeof (char *));
-		       yyx++)
+		  yyprefix = ", expecting ";
+		  for (yyx = yyxbegin; yyx < yyxend; ++yyx)
 		    if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
 		      {
-			const char *yyq = ! yycount ? ", expecting " : " or ";
-			yyp = yystpcpy (yyp, yyq);
+			yyp = yystpcpy (yyp, yyprefix);
 			yyp = yystpcpy (yyp, yytname[yyx]);
-			yycount++;
+			yyprefix = " or ";
 		      }
 		}
 	      yyerror (yymsg);
@@ -1540,25 +1746,27 @@
       /* If just tried and failed to reuse lookahead token after an
 	 error, discard it.  */
 
-      /* Return failure if at end of input.  */
-      if (yychar == YYEOF)
+      if (yychar <= YYEOF)
         {
-	  /* Pop the error token.  */
-          YYPOPSTACK;
-	  /* Pop the rest of the stack.  */
-	  while (yyss < yyssp)
-	    {
-	      YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
-	      yydestruct (yystos[*yyssp], yyvsp);
-	      YYPOPSTACK;
-	    }
-	  YYABORT;
+          /* If at end of input, pop the error token,
+	     then the rest of the stack, then return failure.  */
+	  if (yychar == YYEOF)
+	     for (;;)
+	       {
+		 YYPOPSTACK;
+		 if (yyssp == yyss)
+		   YYABORT;
+		 YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+		 yydestruct (yystos[*yyssp], yyvsp);
+	       }
         }
+      else
+	{
+	  YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
+	  yydestruct (yytoken, &yylval);
+	  yychar = YYEMPTY;
 
-      YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
-      yydestruct (yytoken, &yylval);
-      yychar = YYEMPTY;
-
+	}
     }
 
   /* Else will try to reuse lookahead token after shifting the error
@@ -1566,9 +1774,27 @@
   goto yyerrlab1;
 
 
-/*----------------------------------------------------.
-| yyerrlab1 -- error raised explicitly by an action.  |
-`----------------------------------------------------*/
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+#ifdef __GNUC__
+  /* Pacify GCC when the user code never invokes YYERROR and the label
+     yyerrorlab therefore never appears in user code.  */
+  if (0)
+     goto yyerrorlab;
+#endif
+
+  yyvsp -= yylen;
+  yyssp -= yylen;
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
 yyerrlab1:
   yyerrstatus = 3;	/* Each real token shifted decrements this.  */
 
@@ -1592,9 +1818,8 @@
 
       YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
       yydestruct (yystos[yystate], yyvsp);
-      yyvsp--;
-      yystate = *--yyssp;
-
+      YYPOPSTACK;
+      yystate = *yyssp;
       YY_STACK_PRINT (yyss, yyssp);
     }
 
@@ -1643,7 +1868,7 @@
 }
 
 
-#line 254 "grammar.y"
+#line 286 "grammar.y"
 
 
 extern int yylineno;
diff -Naur tinyproxy-1.6.2-orig/src/grammar.h tinyproxy-1.6.2/src/grammar.h
--- tinyproxy-1.6.2-orig/src/grammar.h	2003-08-06 22:47:56.000000000 +0200
+++ tinyproxy-1.6.2/src/grammar.h	2009-08-28 10:48:00.000000000 +0200
@@ -1,7 +1,7 @@
-/* A Bison parser, made by GNU Bison 1.875a.  */
+/* A Bison parser, made by GNU Bison 1.875d.  */
 
 /* Skeleton parser for Yacc-like parsing with Bison,
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -59,20 +59,41 @@
      KW_DEFAULT_ERRORPAGE = 285,
      KW_STATPAGE = 286,
      KW_VIA_PROXY_NAME = 287,
-     KW_YES = 288,
-     KW_NO = 289,
-     KW_LOGLEVEL = 290,
-     KW_LOG_CRITICAL = 291,
-     KW_LOG_ERROR = 292,
-     KW_LOG_WARNING = 293,
-     KW_LOG_NOTICE = 294,
-     KW_LOG_CONNECT = 295,
-     KW_LOG_INFO = 296,
-     IDENTIFIER = 297,
-     NUMBER = 298,
-     STRING = 299,
-     NUMERIC_ADDRESS = 300,
-     NETMASK_ADDRESS = 301
+     KW_CLAMAV_PORT = 288,
+     KW_CCHECK_ERR_FILE = 289,
+     KW_ADMIN_EMAIL = 290,
+     KW_CCHECK_MIME_EXCLUDE = 291,
+     KW_CHROOT = 292,
+     KW_CCHECK_MAX_SIZE = 293,
+     KW_CCHECK_MIN_FREE = 294,
+     KW_CCHECK_TEMP_DIR = 295,
+     KW_CCHECK_VIRT_DIR = 296,
+     KW_CCHECK_MAX_SIZE_PASS = 297,
+     KW_CCHECK_REDIRECT_URL = 298,
+     KW_CCHECK_USE_REAL_SIZE = 299,
+     KW_CCHECK_SAFE_URL = 300,
+     KW_CCHECK_PI_THRESH = 301,
+     KW_CCHECK_PEEKBUF_SIZE = 302,
+     KW_CCHECK_SCAN_RETRIES = 303,
+     KW_CCHECK_UPD_INTERVAL = 304,
+     KW_CCHECK_REDIRECT_UA = 305,
+     KW_ADD_ERR_TEXT = 306,
+     KW_YES = 307,
+     KW_NO = 308,
+     KW_LOGLEVEL = 309,
+     KW_LOG_CRITICAL = 310,
+     KW_LOG_ERROR = 311,
+     KW_LOG_WARNING = 312,
+     KW_LOG_NOTICE = 313,
+     KW_LOG_CONNECT = 314,
+     KW_LOG_INFO = 315,
+     IDENTIFIER = 316,
+     NUMBER = 317,
+     STRING = 318,
+     NUMERIC_ADDRESS = 319,
+     NETMASK_ADDRESS = 320,
+     MIME_TYPE = 321,
+     PCRE_STRING = 322
    };
 #endif
 #define KW_PORT 258
@@ -105,20 +126,41 @@
 #define KW_DEFAULT_ERRORPAGE 285
 #define KW_STATPAGE 286
 #define KW_VIA_PROXY_NAME 287
-#define KW_YES 288
-#define KW_NO 289
-#define KW_LOGLEVEL 290
-#define KW_LOG_CRITICAL 291
-#define KW_LOG_ERROR 292
-#define KW_LOG_WARNING 293
-#define KW_LOG_NOTICE 294
-#define KW_LOG_CONNECT 295
-#define KW_LOG_INFO 296
-#define IDENTIFIER 297
-#define NUMBER 298
-#define STRING 299
-#define NUMERIC_ADDRESS 300
-#define NETMASK_ADDRESS 301
+#define KW_CLAMAV_PORT 288
+#define KW_CCHECK_ERR_FILE 289
+#define KW_ADMIN_EMAIL 290
+#define KW_CCHECK_MIME_EXCLUDE 291
+#define KW_CHROOT 292
+#define KW_CCHECK_MAX_SIZE 293
+#define KW_CCHECK_MIN_FREE 294
+#define KW_CCHECK_TEMP_DIR 295
+#define KW_CCHECK_VIRT_DIR 296
+#define KW_CCHECK_MAX_SIZE_PASS 297
+#define KW_CCHECK_REDIRECT_URL 298
+#define KW_CCHECK_USE_REAL_SIZE 299
+#define KW_CCHECK_SAFE_URL 300
+#define KW_CCHECK_PI_THRESH 301
+#define KW_CCHECK_PEEKBUF_SIZE 302
+#define KW_CCHECK_SCAN_RETRIES 303
+#define KW_CCHECK_UPD_INTERVAL 304
+#define KW_CCHECK_REDIRECT_UA 305
+#define KW_ADD_ERR_TEXT 306
+#define KW_YES 307
+#define KW_NO 308
+#define KW_LOGLEVEL 309
+#define KW_LOG_CRITICAL 310
+#define KW_LOG_ERROR 311
+#define KW_LOG_WARNING 312
+#define KW_LOG_NOTICE 313
+#define KW_LOG_CONNECT 314
+#define KW_LOG_INFO 315
+#define IDENTIFIER 316
+#define NUMBER 317
+#define STRING 318
+#define NUMERIC_ADDRESS 319
+#define NETMASK_ADDRESS 320
+#define MIME_TYPE 321
+#define PCRE_STRING 322
 
 
 
@@ -129,8 +171,8 @@
 	unsigned int num;
 	char *cptr;
 } YYSTYPE;
-/* Line 1240 of yacc.c.  */
-#line 134 "y.tab.h"
+/* Line 1285 of yacc.c.  */
+#line 176 "y.tab.h"
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
 # define YYSTYPE_IS_TRIVIAL 1
diff -Naur tinyproxy-1.6.2-orig/src/grammar.y tinyproxy-1.6.2/src/grammar.y
--- tinyproxy-1.6.2-orig/src/grammar.y	2003-06-26 20:17:09.000000000 +0200
+++ tinyproxy-1.6.2/src/grammar.y	2009-08-28 10:48:00.000000000 +0200
@@ -56,6 +56,13 @@
 %token KW_ERRORPAGE KW_DEFAULT_ERRORPAGE
 %token KW_STATPAGE
 %token KW_VIA_PROXY_NAME
+%token KW_CLAMAV_PORT KW_CCHECK_ERR_FILE KW_ADMIN_EMAIL KW_CCHECK_MIME_EXCLUDE
+%token KW_CHROOT KW_CCHECK_MAX_SIZE KW_CCHECK_MIN_FREE KW_CCHECK_TEMP_DIR
+%token KW_CCHECK_VIRT_DIR KW_CCHECK_MAX_SIZE_PASS KW_CCHECK_REDIRECT_URL
+%token KW_CCHECK_USE_REAL_SIZE KW_CCHECK_SAFE_URL KW_CCHECK_PI_THRESH
+%token KW_CCHECK_PEEKBUF_SIZE KW_CCHECK_SCAN_RETRIES KW_CCHECK_UPD_INTERVAL
+%token KW_CCHECK_REDIRECT_UA
+%token KW_ADD_ERR_TEXT
 
 /* yes/no switches */
 %token KW_YES KW_NO
@@ -69,6 +76,8 @@
 %token <cptr> STRING
 %token <cptr> NUMERIC_ADDRESS
 %token <cptr> NETMASK_ADDRESS
+%token <cptr> MIME_TYPE
+%token <cptr> PCRE_STRING
 
 %type <num> yesno
 %type <cptr> string
@@ -219,6 +228,29 @@
 		  log_message(LOG_INFO, "Stathost is set to \"%s\"", $2);
 		  config.stathost = $2;
 	  }
+	| KW_CLAMAV_PORT NUMBER         { config.clamav_port = $2; }
+	| KW_CCHECK_ERR_FILE string     { config.ccheck_err_file = $2; }
+	| KW_ADMIN_EMAIL string		{ config.admin_email = $2; }
+	| KW_CCHECK_MIME_EXCLUDE MIME_TYPE
+					{ add_exclude_mime_type($2); }
+	| KW_CCHECK_SAFE_URL PCRE_STRING
+					{ add_exclude_url_regexp($2); }
+	| KW_CCHECK_REDIRECT_UA PCRE_STRING
+					{ add_user_agent_regexp($2); }
+	| KW_CHROOT string              { config.chroot = $2; }
+	| KW_CCHECK_MAX_SIZE NUMBER     { config.ccheck_max_size = $2; }
+	| KW_CCHECK_PI_THRESH NUMBER    { config.ccheck_pi_thresh = $2; }
+	| KW_CCHECK_MAX_SIZE_PASS NUMBER	{ config.ccheck_max_size_pass = $2; }
+	| KW_CCHECK_USE_REAL_SIZE NUMBER	{ config.ccheck_use_real_size = $2; }
+	| KW_CCHECK_MIN_FREE NUMBER     { config.ccheck_min_free =  
+	                                  1024 * 1024 * $2; }
+	| KW_CCHECK_TEMP_DIR string     { config.ccheck_temp_dir = $2; }
+	| KW_CCHECK_VIRT_DIR string     { config.ccheck_virt_dir = $2; }
+	| KW_CCHECK_REDIRECT_URL string { config.ccheck_redirect_url = $2; }
+	| KW_CCHECK_PEEKBUF_SIZE NUMBER { config.ccheck_peekbuf_size = $2; }
+	| KW_CCHECK_SCAN_RETRIES NUMBER { config.ccheck_scan_retries = $2; }
+	| KW_CCHECK_UPD_INTERVAL NUMBER { config.ccheck_upd_interval = $2; }
+	| KW_ADD_ERR_TEXT string        { config.add_err_text = $2; }
 	;
 
 loglevels
diff -Naur tinyproxy-1.6.2-orig/src/htmlerror.c tinyproxy-1.6.2/src/htmlerror.c
--- tinyproxy-1.6.2-orig/src/htmlerror.c	2003-07-14 19:42:43.000000000 +0200
+++ tinyproxy-1.6.2/src/htmlerror.c	2009-08-28 10:48:00.000000000 +0200
@@ -233,10 +233,20 @@
 add_standard_vars(struct conn_s *connptr) {
 	char timebuf[30];
 	time_t global_time = time(NULL);
+	char *p1, *p2, save;
+	char *url;
 
 	strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT",
 			 gmtime(&global_time));
-
+	if((p1 = index(connptr->request_line, ' ')) &&
+	  (p2 = index(p1 + 1, ' '))) {
+		save = *p2;
+		*p2 = 0;
+		url = strdup(p1 + 1);
+		*p2 = save;
+	} else {
+		url = strdup(connptr->request_line);
+	}
 	ADD_VAR_RET("request", connptr->request_line);
 	ADD_VAR_RET("cause", connptr->error_string);
 	ADD_VAR_RET("clientip", connptr->client_ip_addr);
@@ -244,6 +254,14 @@
 	ADD_VAR_RET("version", VERSION);
 	ADD_VAR_RET("package", PACKAGE);
 	ADD_VAR_RET("date", timebuf);
+	ADD_VAR_RET("admin", config.admin_email);
+	ADD_VAR_RET("url", url);
+	if (config.add_err_text != NULL) {
+		ADD_VAR_RET("add_error", config.add_err_text);
+	} else {
+		ADD_VAR_RET("add_error", "");
+	}
+	free(url);
 	return(0);
 }
 
diff -Naur tinyproxy-1.6.2-orig/src/Makefile.am tinyproxy-1.6.2/src/Makefile.am
--- tinyproxy-1.6.2-orig/src/Makefile.am	2003-06-26 20:23:01.000000000 +0200
+++ tinyproxy-1.6.2/src/Makefile.am	2009-08-28 10:48:00.000000000 +0200
@@ -40,12 +40,13 @@
 	utils.c utils.h \
 	vector.c vector.h \
 	grammar.y scanner.l \
-	regexp.h
+	regexp.h \
+	virus.c virus.h
 
 EXTRA_DIST = gnuregex.c gnuregex.h
 EXTRA_tinyproxy_SOURCES = filter.c filter.h grammar.h
 tinyproxy_DEPENDENCIES = @ADDITIONAL_OBJECTS@
-tinyproxy_LDADD = @ADDITIONAL_OBJECTS@
+tinyproxy_LDADD = @ADDITIONAL_OBJECTS@ -lpaiface -lpcre -lmagic
 
 scanner.c: scanner.l grammar.h
 	$(LEX) $(LEX_FLAGS) $(LFLAGS) -i $< && mv $(LEX_OUTPUT_ROOT).c $@
diff -Naur tinyproxy-1.6.2-orig/src/Makefile.in tinyproxy-1.6.2/src/Makefile.in
--- tinyproxy-1.6.2-orig/src/Makefile.in	2003-10-17 17:50:00.000000000 +0200
+++ tinyproxy-1.6.2/src/Makefile.in	2009-08-28 10:48:00.000000000 +0200
@@ -116,13 +116,13 @@
 
 sbin_PROGRAMS = tinyproxy
 
-tinyproxy_SOURCES =  	acl.c acl.h 	anonymous.c anonymous.h 	buffer.c buffer.h 	child.c child.h 	common.h 	conns.c conns.h 	daemon.c daemon.h 	hashmap.c hashmap.h 	heap.c heap.h 	htmlerror.c htmlerror.h 	http_message.c http_message.h 	log.c log.h 	network.c network.h 	reqs.c reqs.h 	sock.c sock.h 	stats.c stats.h 	text.c text.h 	tinyproxy.c tinyproxy.h 	utils.c utils.h 	vector.c vector.h 	grammar.y scanner.l 	regexp.h
+tinyproxy_SOURCES =  	acl.c acl.h 	anonymous.c anonymous.h 	buffer.c buffer.h 	child.c child.h 	common.h 	conns.c conns.h 	daemon.c daemon.h 	hashmap.c hashmap.h 	heap.c heap.h 	htmlerror.c htmlerror.h 	http_message.c http_message.h 	log.c log.h 	network.c network.h 	reqs.c reqs.h 	sock.c sock.h 	stats.c stats.h 	text.c text.h 	tinyproxy.c tinyproxy.h 	utils.c utils.h 	vector.c vector.h 	grammar.y scanner.l 	regexp.h virus.c virus.h
 
 
 EXTRA_DIST = gnuregex.c gnuregex.h
 EXTRA_tinyproxy_SOURCES = filter.c filter.h grammar.h
 tinyproxy_DEPENDENCIES = @ADDITIONAL_OBJECTS@
-tinyproxy_LDADD = @ADDITIONAL_OBJECTS@
+tinyproxy_LDADD = @ADDITIONAL_OBJECTS@ -lpaiface -lpcre -lmagic
 mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
 CONFIG_HEADER = ../config.h
 CONFIG_CLEAN_FILES = 
@@ -136,7 +136,7 @@
 heap.$(OBJEXT) htmlerror.$(OBJEXT) http_message.$(OBJEXT) log.$(OBJEXT) \
 network.$(OBJEXT) reqs.$(OBJEXT) sock.$(OBJEXT) stats.$(OBJEXT) \
 text.$(OBJEXT) tinyproxy.$(OBJEXT) utils.$(OBJEXT) vector.$(OBJEXT) \
-grammar.$(OBJEXT) scanner.$(OBJEXT)
+grammar.$(OBJEXT) scanner.$(OBJEXT) virus.$(OBJEXT)
 tinyproxy_LDFLAGS = 
 LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
 LEXLIB = @LEXLIB@
diff -Naur tinyproxy-1.6.2-orig/src/network.c tinyproxy-1.6.2/src/network.c
--- tinyproxy-1.6.2-orig/src/network.c	2002-05-23 06:41:48.000000000 +0200
+++ tinyproxy-1.6.2/src/network.c	2009-08-28 10:48:00.000000000 +0200
@@ -236,3 +236,141 @@
 
 	return ret;
 }
+
+/*
+ * A version of recv() that is wrapped with a select() so
+ * that it will handle timeouts. Used by the special version
+ * of readline() to implement a timeout mechanism.
+ */
+static ssize_t recv_with_timeout(int s, void *buf,
+  size_t len, int flags, int timeout)
+{
+	int rc;
+	fd_set rfds;
+	struct timeval tv;
+
+	FD_ZERO(&rfds);
+	FD_SET(s, &rfds);
+
+	tv.tv_sec = timeout;
+	tv.tv_usec = 0;
+
+	rc = select(s + 1, &rfds, NULL, NULL, &tv);
+	if (rc < 0) {
+		return (rc);
+	}
+
+	if (rc > 0) {
+		rc = recv(s, buf, len, flags);
+	}
+
+	return (rc);
+}
+
+/*
+ * This is a very ugly hack: we duplicate the readline code
+ * so we can have a second version of readline() that uses a
+ * timeout. This is used when retrieving the server response
+ * line and/or the headers returned by the server to avoid
+ * nasty hangs on dead connections as observed at Salzlandkreis.
+ */
+ssize_t
+readline_with_timeout(int fd, char **whole_buffer, int timeout)
+{
+	ssize_t whole_buffer_len;
+	char buffer[SEGMENT_LEN];
+	char *ptr;
+
+	ssize_t ret;
+	ssize_t diff;
+
+	struct read_lines_s {
+		char *data;
+		size_t len;
+		struct read_lines_s *next;
+	};
+	struct read_lines_s *first_line, *line_ptr;
+
+	first_line = safecalloc(sizeof(struct read_lines_s), 1);
+	if (!first_line)
+		return -ENOMEM;
+
+	line_ptr = first_line;
+
+	whole_buffer_len = 0;
+	for (;;) {
+		ret = recv_with_timeout(fd, buffer, SEGMENT_LEN, MSG_PEEK, timeout);
+		if (ret <= 0)
+			goto CLEANUP;
+
+		ptr = memchr(buffer, '\n', ret);
+		if (ptr)
+			diff = ptr - buffer + 1;
+		else
+			diff = ret;
+
+		whole_buffer_len += diff;
+
+		/*
+		 * Don't allow the buffer to grow without bound. If we
+		 * get to more than MAXIMUM_BUFFER_LENGTH close.
+		 */
+		if (whole_buffer_len > MAXIMUM_BUFFER_LENGTH) {
+			ret = -ERANGE;
+			goto CLEANUP;
+		}
+
+		line_ptr->data = safemalloc(diff);
+		if (!line_ptr->data) {
+			ret = -ENOMEM;
+			goto CLEANUP;
+		}
+
+		recv(fd, line_ptr->data, diff, 0);
+		line_ptr->len = diff;
+
+		if (ptr) {
+			line_ptr->next = NULL;
+			break;
+		}
+
+		line_ptr->next = safecalloc(sizeof(struct read_lines_s), 1);
+		if (!line_ptr->next) {
+			ret = -ENOMEM;
+			goto CLEANUP;
+		}
+		line_ptr = line_ptr->next;
+	}
+
+	*whole_buffer = safemalloc(whole_buffer_len + 1);
+	if (!*whole_buffer) {
+		ret = -ENOMEM;
+		goto CLEANUP;
+	}
+
+	*(*whole_buffer + whole_buffer_len) = '\0';
+
+	whole_buffer_len = 0;
+	line_ptr = first_line;
+	while (line_ptr) {
+		memcpy(*whole_buffer + whole_buffer_len, line_ptr->data,
+		       line_ptr->len);
+		whole_buffer_len += line_ptr->len;
+
+		line_ptr = line_ptr->next;
+	}
+
+	ret = whole_buffer_len;
+
+      CLEANUP:
+	do {
+		line_ptr = first_line->next;
+		if (first_line->data)
+			safefree(first_line->data);
+		safefree(first_line);
+		first_line = line_ptr;
+	} while (first_line);
+
+	return ret;
+}
+
diff -Naur tinyproxy-1.6.2-orig/src/network.h tinyproxy-1.6.2/src/network.h
--- tinyproxy-1.6.2-orig/src/network.h	2002-05-23 06:41:48.000000000 +0200
+++ tinyproxy-1.6.2/src/network.h	2009-08-28 10:48:00.000000000 +0200
@@ -23,5 +23,6 @@
 
 extern int write_message(int fd, const char *fmt, ...);
 extern ssize_t readline(int fd, char **whole_buffer);
+extern ssize_t readline_with_timeout(int fd, char **whole_buffer, int timeout);
 
 #endif
diff -Naur tinyproxy-1.6.2-orig/src/reqs.c tinyproxy-1.6.2/src/reqs.c
--- tinyproxy-1.6.2-orig/src/reqs.c	2003-06-26 20:19:57.000000000 +0200
+++ tinyproxy-1.6.2/src/reqs.c	2009-08-28 10:48:00.000000000 +0200
@@ -40,6 +40,18 @@
 #include "text.h"
 #include "utils.h"
 #include "vector.h"
+#include "virus.h"
+
+#include <sys/vfs.h>
+#include <sys/socket.h>
+#include <linux/tcp.h>
+#include "pa/spaced.h"
+
+/*
+ * String to replace 'tinyproxy' in various messages and protocol headers
+ */
+#define UTM_PRODUCT "packetalarm UTM"
+
 
 /*
  * Maximum length of a HTTP line
@@ -88,6 +100,46 @@
 	char *path;
 };
 
+static int write_via_header(int fd, hashmap_t hashofheaders,
+  unsigned int major, unsigned int minor);
+
+
+int send_server_headers(struct conn_s *connptr)
+{
+	char *data, *header;
+	hashmap_iter iter;
+	int ret;
+	ret = write_via_header(connptr->client_fd, connptr->server_headers,
+	  connptr->protocol.major, connptr->protocol.minor);
+	if (ret < 0)
+		return(-1);
+	
+	iter = hashmap_first(connptr->server_headers);
+	if (iter >= 0)
+	{
+		int i, max;
+		for(max = 0; !hashmap_is_end(connptr->server_headers, max); max++);
+		max--;
+		for(i = max; i >= 0; i--) {
+			hashmap_return_entry(connptr->server_headers,
+					     i,
+					     &data,
+					     (void **)&header);
+
+			ret = write_message(connptr->client_fd,
+						  "%s: %s\r\n",
+						  data, header);
+			if (ret < 0)
+				return(-1);
+		}
+	}
+	if (safe_write(connptr->client_fd, "\r\n", 2) < 0)
+		return -1;
+	return(0);
+}
+
+
+
 /*
  * Now, this routine adds a "port" to the list.  It also creates the list if
  * it hasn't already by done.
@@ -469,9 +521,12 @@
  * Create a connection for HTTP connections.
  */
 static int
-establish_http_connection(struct conn_s *connptr, struct request_s *request)
+establish_http_connection(struct conn_s *connptr, struct request_s *request,
+  hashmap_t hashofheaders)
 {
 	char portbuff[7];
+	int length;
+	char *data;
 
 	/* Build a port string if it's not a standard port */
 	if (request->port != HTTP_PORT && request->port != HTTP_PORT_SSL)
@@ -479,19 +534,29 @@
 	else
 		portbuff[0] = '\0';
 
-	return write_message(connptr->server_fd,
-			     "%s %s HTTP/1.0\r\n" \
-			     "Host: %s%s\r\n" \
-			     "Connection: close\r\n",
-			     request->method, request->path,
-			     request->host, portbuff);
+	length = hashmap_entry_by_key(hashofheaders, "host", (void **)&data);
+	if (length <= 0) {
+		return write_message(connptr->server_fd,
+				     "%s %s HTTP/1.0\r\n" \
+				     "Host: %s%s\r\n" \
+				     "Connection: close\r\n",
+				     request->method, request->path,
+				     request->host, portbuff);
+	} else {
+		return write_message(connptr->server_fd,
+				     "%s %s HTTP/1.0\r\n" \
+				     "Host: %s\r\n" \
+				     "Connection: close\r\n",
+				     request->method, request->path,
+				     data);
+	}
 }
 
 /*
  * These two defines are for the SSL tunneling.
  */
 #define SSL_CONNECTION_RESPONSE "HTTP/1.0 200 Connection established"
-#define PROXY_AGENT "Proxy-agent: " PACKAGE "/" VERSION
+#define PROXY_AGENT "Proxy-agent: " UTM_PRODUCT
 
 /*
  * Send the appropriate response to the client to establish a SSL
@@ -878,7 +943,7 @@
 	assert(hashofheaders != NULL);
 
 	for (;;) {
-		if ((len = readline(fd, &header)) <= 0) {
+		if ((len = readline_with_timeout(fd, &header, config.idletimeout)) <= 0) {
 			safefree(header);
 			return -1;
 		}
@@ -1019,17 +1084,16 @@
 	len = hashmap_entry_by_key(hashofheaders, "via", (void **)&data);
 	if (len > 0) {
 		ret = write_message(fd,
-				    "Via: %s, %hu.%hu %s (%s/%s)\r\n",
+				    "Via: %s, %hu.%hu %s (%s)\r\n",
 				    data,
 				    major, minor,
-				    hostname, PACKAGE, VERSION);
-
+				    hostname, UTM_PRODUCT);
 		hashmap_remove(hashofheaders, "via");
 	} else {
 		ret = write_message(fd,
-				    "Via: %hu.%hu %s (%s/%s)\r\n",
+				    "Via: %hu.%hu %s (%s)\r\n",
 				    major, minor,
-				    hostname, PACKAGE, VERSION);
+				    hostname, UTM_PRODUCT);
 	}
 
 	return ret;
@@ -1076,6 +1140,14 @@
 		log_message(LOG_INFO, "Not sending client headers to remote machine");
 		return 0;
 	}
+	/*
+	 * Store X-Forwarded-For information
+	 */
+	if(hashmap_entry_by_key(hashofheaders, "X-Forwarded-For",
+	  (void **)&data) > 0)
+		connptr->forwarded_for = strdup(data);
+	else
+		connptr->forwarded_for = strdup("unknown");
 
 	/*
 	 * See if there is a "Content-Length" header.  If so, again we need
@@ -1182,9 +1254,12 @@
 
 	/* Get the response line from the remote server. */
       retry:
-	len = readline(connptr->server_fd, &response_line);
-	if (len <= 0)
+	len = readline_with_timeout(connptr->server_fd,
+	  &response_line, config.idletimeout);
+	if (len <= 0) {
+		log_message(LOG_WARNING, "Could not retrieve response line from the remote server.");
 		return -1;
+	}
 
 	/*
 	 * Strip the new line and character return from the string.
@@ -1214,17 +1289,11 @@
 		safefree(response_line);
 
 		indicate_http_error(connptr, 503, "Could not retrieve all the headers",
-				    "detail", PACKAGE " was unable to retrieve and process headers from the remote web server.",
+				    "detail", UTM_PRODUCT " was unable to retrieve and process headers from the remote web server.",
 				    NULL);
 		return -1;
 	}
 
-	/* Send the saved response line first */
-	ret = write_message(connptr->client_fd, "%s\r\n", response_line);
-	safefree(response_line);
-	if (ret < 0)
-		goto ERROR_EXIT;
-
 	/*
 	 * If there is a "Content-Length" header, retrieve the information
 	 * from it for later use.
@@ -1244,41 +1313,26 @@
 		hashmap_remove(hashofheaders, skipheaders[i]);
 	}
 
-	/* Send, or add the Via header */
-	ret = write_via_header(connptr->client_fd, hashofheaders,
-			       connptr->protocol.major,
-			       connptr->protocol.minor);
-	if (ret < 0)
-		goto ERROR_EXIT;
-
+	connptr->server_headers = hashofheaders;
 	/*
-	 * All right, output all the remaining headers to the client.
+	 * Determine how the incoming data is handled.
 	 */
-	iter = hashmap_first(hashofheaders);
-	if (iter >= 0) {
-		for ( ; !hashmap_is_end(hashofheaders, iter); ++iter) {
-			hashmap_return_entry(hashofheaders,
-					     iter,
-					     &data,
-					     (void **)&header);
+	content_check_required(connptr);
 
-			ret = write_message(connptr->client_fd,
-						  "%s: %s\r\n",
-						  data, header);
-			if (ret < 0)
-				goto ERROR_EXIT;
-		}
+	if (connptr->check_content != CONN_CCHECK_REDIRECT) {
+		/* Send the saved response line first */
+		ret = write_message(connptr->client_fd, "%s\r\n", response_line);
+		safefree(response_line);
+		if (ret < 0)
+			goto ERROR_EXIT;
+	} else {
+		/* Since we may not redirect after all, save response */
+		connptr->response_line = response_line;
 	}
-	hashmap_delete(hashofheaders);
-
-	/* Write the final blank line to signify the end of the headers */
-	if (safe_write(connptr->client_fd, "\r\n", 2) < 0)
-		return -1;
 
 	return 0;
 
   ERROR_EXIT:
-	hashmap_delete(hashofheaders);
 	return -1;
 }
 
@@ -1324,8 +1378,8 @@
 			FD_SET(connptr->client_fd, &rset);
 
 		ret = select(maxfd, &rset, &wset, NULL, &tv);
-
-		if (ret == 0) {
+	
+                if (ret == 0) {
 			tdiff = difftime(time(NULL), last_access);
 			if (tdiff > config.idletimeout) {
 				log_message(LOG_INFO,
@@ -1394,11 +1448,359 @@
 	return;
 }
 
+
+/*
+static int do_content_check(struct conn_s *connptr, char *filename)
+{
+	int fd[2];
+	int pid;
+	char msg_buffer[500];
+
+	if(pipe(fd) < 0)
+	{
+		internal_error(connptr);
+		printf("Unable to create pipe: %s\n", strerror(errno));
+		return(-1);
+	}
+	if((pid = fork()) < 0)
+	{
+		internal_error(connptr);
+		printf("Unable to fork: %s\n", strerror(errno));
+		return(-1);
+	}
+	if(pid == 0)
+	{
+		close(fd[0]);
+		close(1);
+		dup2(fd[1], 1);
+		if(execlp("/tmp/filter", "filter", filename) < 0)
+		{
+			printf("execlp failed(): %s\n", strerror(errno));
+			exit(2);
+		}
+	}
+	else
+	{
+		FILE *file;
+		char buf[500];
+		int lc = 0;
+		int status;
+
+		close(fd[1]);
+		file = fdopen(fd[0], "r");
+		while(fgets(buf, sizeof(buf), file))
+		{
+			if(lc++ == 0)
+				strncpy(msg_buffer, buf, sizeof(msg_buffer));
+		}
+		fclose(file);
+		close(fd[0]);
+		waitpid(pid, &status, 0);
+		if(!WIFEXITED(status))
+		{
+			internal_error(connptr);
+			printf("check program failed\n");
+			return(-1);
+		}
+
+		if(WEXITSTATUS(status) == 2)
+		{
+			internal_error(connptr);
+			printf("check program failed\n");
+			return(-1);
+		}
+		else if(WEXITSTATUS(status) == 1)
+		{
+			indicate_http_error(connptr, 503, "Malicious Content ",
+			  "detail", msg_buffer, NULL);
+			send_http_error_message(connptr);
+			return(0);
+		}
+		else if(WEXITSTATUS(status) != 0)
+		{
+			internal_error(connptr);
+			printf("unexpected return code (%d)\n",
+			  WEXITSTATUS(status));
+			return(-1);
+		}
+	}
+
+	return(1);
+}
+
+*/
+
+
+static void
+relay_check_content(struct conn_s *connptr)
+{
+	fd_set rset, wset;
+	struct timeval tv;
+	time_t last_access;
+	time_t last_client_talk;
+	int ret;
+	double tdiff;
+	int maxfd = max(connptr->client_fd, connptr->server_fd) + 1;
+	ssize_t bytes_received;
+	int tmp_file;
+	int tmp_file2;
+	int connection_timeout = 0;
+	char filename[255];
+	int i, len, k, j;
+	char sendbuf[20000];
+	char one_byte[1];
+	char client_timeout_buf[2000];
+	int content_result;
+	char content_msg[200];
+	char *sock_str_int;
+
+/*	if(config.ccheck_max_size != 0 &&
+	  connptr->content_length.server > config.ccheck_max_size
+	  || connptr->content_length.server < 0 )
+	{
+		if(connptr->content_length.server < 0) {
+			send_server_headers(connptr);
+			relay_connection(connptr);
+			return;
+		}
+
+		if(config.ccheck_max_size_pass == 1) {
+			log_message(LOG_WARNING, "Maximum allowed file size exceeded "
+			  "(content-length: %d)",connptr->content_length.server); 
+			log_message(LOG_WARNING, "Piping Message through without scanning....");
+			send_server_headers(connptr);
+			relay_connection(connptr);
+			return;
+		}
+		send_ccheck_response(connptr, "Content Rejected",
+		  "The requested file exceeds the maximum allowed size");
+		log_message(LOG_WARNING, "Maximum allowed file size exceeded "
+		  "(content-length: %d)",connptr->content_length.server); 
+		return;
+	} */
+	/* Catch Space from SpaceDaemon */
+	if(config.ccheck_use_real_size == 1) {
+		if(! (connptr->spacedaemon = pasd_request(pasd_client_type_http, connptr->content_length.server)))
+		{
+			log_message(LOG_WARNING, "PA-SpaceDaemon returned: %s", pasd_errstr);
+			return;
+		}
+	} else {
+		if(! (connptr->spacedaemon = pasd_request(pasd_client_type_http, config.ccheck_max_size)))
+		{
+			log_message(LOG_WARNING, "PA-SpaceDaemon returned: %s", pasd_errstr);
+			return;
+		}
+	}
+	
+	snprintf(filename, sizeof(filename), "%s/buffer.%d", 
+	  config.virt_ccheck_temp_dir, getpid());
+	if((tmp_file = open(filename, O_CREAT|O_WRONLY, 0666)) < 0)
+	{
+		send_ccheck_response(connptr, ccheckMsgTypeErr,
+		  "Unable to create temporary buffer file");
+		log_message(LOG_ERR, "Unable to create buffer file (%s): %s",
+		  filename, strerror(errno));
+		return;
+	}
+
+	socket_nonblocking(connptr->client_fd);
+	socket_nonblocking(connptr->server_fd);
+
+	last_access = time(NULL);
+	last_client_talk = time(NULL);
+	len = 0;
+	
+	for (;;) {
+		FD_ZERO(&rset);
+		FD_ZERO(&wset);
+
+		tv.tv_sec =
+		    config.idletimeout - difftime(time(NULL), last_access);
+		tv.tv_usec = 0;
+
+		if (buffer_size(connptr->sbuffer) > 0)
+			FD_SET(connptr->client_fd, &wset);
+		if (buffer_size(connptr->cbuffer) > 0)
+			FD_SET(connptr->server_fd, &wset);
+		if (buffer_size(connptr->sbuffer) < MAXBUFFSIZE)
+			FD_SET(connptr->server_fd, &rset);
+		if (buffer_size(connptr->cbuffer) < MAXBUFFSIZE)
+			FD_SET(connptr->client_fd, &rset);
+
+		tdiff = difftime(time(NULL), last_client_talk);
+		if (tdiff > config.idletimeout) {
+			if (len <= connection_timeout) {
+
+				if((tmp_file2 = open(filename, O_RDONLY)) < 0) {
+					if (connection_timeout == 0) {
+						send_ccheck_response(connptr, ccheckMsgTypeErr,
+						  "Unable to open temporary buffer file");
+					} else {
+						send_ccheck_response_nohead(connptr, ccheckMsgTypeErr,
+						  "Unable to open temporary buffer file");
+					}
+					log_message(LOG_ERR, "unable to open buffer file: %s",
+					  strerror(errno));
+				}
+				len = read(tmp_file2, client_timeout_buf, sizeof(client_timeout_buf));
+				close(tmp_file2);
+			}
+			//Sending Closing Header
+			if (connection_timeout == 0) {
+				send_server_headers(connptr);
+			} else {
+				one_byte[0] = client_timeout_buf[connection_timeout -1];
+				send(connptr->client_fd, one_byte, 1 , MSG_DONTWAIT);
+			}
+			connection_timeout++;
+			log_message(LOG_WARNING, "Client getting into Timeout... Sending bytes");
+			last_client_talk = time(NULL);
+		}
+		ret = select(maxfd, &rset, &wset, NULL, &tv);
+		if (ret == 0) {
+			tdiff = difftime(time(NULL), last_access);
+			if (tdiff > config.idletimeout) {
+				log_message(LOG_INFO,
+					    "Idle Timeout (after select) as %g > %u.",
+					    tdiff, config.idletimeout);
+				return;
+			} else {
+				continue;
+			}
+		} else if (ret < 0) {
+			log_message(LOG_ERR,
+				    "relay_connection: select() error \"%s\". Closing connection (client_fd:%d, server_fd:%d)",
+				    strerror(errno), connptr->client_fd,
+				    connptr->server_fd);
+			return;
+		} else {
+			/*
+			 * All right, something was actually selected so mark it.
+			 */
+			last_access = time(NULL);
+		}
+
+		if (FD_ISSET(connptr->server_fd, &rset)) {
+			bytes_received = read_buffer(connptr->server_fd, connptr->sbuffer);
+			if (bytes_received < 0)
+				break;
+			write_buffer_fd(tmp_file, connptr->sbuffer);
+			if(config.ccheck_min_free > 0)
+			{
+				struct statfs fs;
+
+				if(fstatfs(tmp_file, &fs) < 0 ||
+				  (fs.f_bavail * 1024 < config.ccheck_min_free)) {
+					if(connection_timeout == 0) {
+						send_ccheck_response(connptr, ccheckMsgTypeErr,
+						  "Free diskspace too low");
+					} else {
+						send_ccheck_response_nohead(connptr, ccheckMsgTypeErr,
+						  "Free diskspace too low");
+					}
+					log_message(LOG_WARNING,
+					  "Free diskspace too low");
+					close(tmp_file);
+					unlink(filename);
+					return;
+				}
+			}
+					
+			connptr->content_length.server -= bytes_received;
+			if (connptr->content_length.server == 0)
+				break;
+		}
+		if (FD_ISSET(connptr->client_fd, &rset)
+		    && read_buffer(connptr->client_fd, connptr->cbuffer) < 0) {
+			break;
+		}
+		if (FD_ISSET(connptr->server_fd, &wset)
+		    && write_buffer(connptr->server_fd, connptr->cbuffer) < 0) {
+			break;
+		}
+	}
+
+	/*
+	 * Here the server has closed the connection... write the
+	 * remainder to the client and then exit.
+	 */
+	socket_blocking(connptr->client_fd);
+	while (buffer_size(connptr->sbuffer) > 0) {
+		if (write_buffer_fd(tmp_file, connptr->sbuffer) < 0)
+			break;
+	}
+
+	/*
+	 * Try to send any remaining data to the server if we can.
+	 */
+	socket_blocking(connptr->server_fd);
+	while (buffer_size(connptr->cbuffer) > 0) {
+		if (write_buffer(connptr->server_fd, connptr->cbuffer) < 0)
+			break;
+	}
+
+	close(tmp_file);
+
+	content_result = scan_file(filename, connptr, content_msg,
+	  sizeof(content_msg));
+	if(content_result < 0)
+	{
+		if (connection_timeout == 0)
+			send_ccheck_response(connptr, ccheckMsgTypeErr, content_msg);
+		else
+			send_ccheck_response_nohead(connptr, ccheckMsgTypeErr, content_msg);
+		log_message(LOG_ERR, "Content scanner error: %s", content_msg);
+	}
+	else if(content_result == 0)
+	{
+		if (connection_timeout == 0) {
+			send_ccheck_response(connptr, ccheckMsgTypeVirus, content_msg);
+		} else {
+			send_ccheck_response_nohead(connptr, ccheckMsgTypeVirus,
+			  content_msg);
+		}
+		log_message(LOG_WARNING, "Content Rejected: %s", content_msg);
+	}
+	else
+	{
+		if((tmp_file = open(filename, O_RDONLY)) < 0)
+		{
+			if (connection_timeout == 0) {
+				send_ccheck_response(connptr, ccheckMsgTypeErr,
+					"Unable to open temporary buffer file");
+			} else {
+				send_ccheck_response_nohead(connptr, ccheckMsgTypeSize,
+					"Unable to open temporary buffer file");
+			}
+			log_message(LOG_ERR, "unable to open buffer file: %s",
+			  strerror(errno));
+		}
+		if (connection_timeout == 0)
+			send_server_headers(connptr);
+		if (connection_timeout != 0)
+		{
+			j = read(tmp_file, sendbuf, connection_timeout -1);
+			log_message(LOG_WARNING, "Time_Out happend %d -> Discarding %d Bytes", connection_timeout, j);
+		}
+		while(i = read(tmp_file, sendbuf, sizeof(sendbuf)))
+		{
+			send(connptr->client_fd, sendbuf, i, MSG_NOSIGNAL);
+		}
+		close(tmp_file);
+	}
+	unlink(filename);
+	shutdown(connptr->client_fd, SHUT_WR);
+
+	return;
+}
+
 /*
  * Establish a connection to the upstream proxy server.
  */
 static int
-connect_to_upstream(struct conn_s *connptr, struct request_s *request)
+connect_to_upstream(struct conn_s *connptr, struct request_s *request,
+  hashmap_t hashofheaders)
 {
 #ifndef UPSTREAM_SUPPORT
 	/*
@@ -1465,7 +1867,7 @@
 		safefree(request->path);
 	request->path = combined_string;
 
-	return establish_http_connection(connptr, request);
+	return establish_http_connection(connptr, request, hashofheaders);
 #endif
 }
 
@@ -1481,6 +1883,7 @@
 void
 handle_connection(int fd)
 {
+	char *uagent, *hosthdr;
 	struct conn_s *connptr;
 	struct request_s *request = NULL;
 	hashmap_t hashofheaders = NULL;
@@ -1511,10 +1914,10 @@
 
 	if (read_request_line(connptr) < 0) {
 		update_stats(STAT_BADCONN);
-		indicate_http_error(connptr, 408, "Timeout",
+/*		indicate_http_error(connptr, 408, "Timeout",
 				    "detail", "Server timeout waiting for the HTTP request from the client.",
 				    NULL);
-		send_http_error_message(connptr);
+		send_http_error_message(connptr); */
 		destroy_conn(connptr);
 		return;
 	}
@@ -1543,6 +1946,22 @@
 		return;
 	}
 
+	/*
+	 * Isolate and save user agent here.
+	 */
+	if (hashmap_entry_by_key(hashofheaders, "User-Agent",
+	  (void **)&uagent) > 0) {
+	  	connptr->user_agent = strdup(uagent);
+	}
+
+	/*
+	 * Isolate and save host header here.
+	 */
+	if (hashmap_entry_by_key(hashofheaders, "Host",
+	  (void **)&hosthdr) > 0) {
+	  	connptr->host_header = strdup(hosthdr);
+	}
+
 	request = process_request(connptr, hashofheaders);
 	if (!request) {
 		if (!connptr->error_variables && !connptr->show_stats) {
@@ -1555,14 +1974,14 @@
 	}
 
 	if (UPSTREAM_CONFIGURED() && (UPSTREAM_HOST(request->host) != NULL)) {
-		if (connect_to_upstream(connptr, request) < 0) {
+		if (connect_to_upstream(connptr, request, hashofheaders) < 0) {
 			goto send_error;
 		}
 	} else {
 		connptr->server_fd = opensock(request->host, request->port);
 		if (connptr->server_fd < 0) {
 			indicate_http_error(connptr, 500, "Unable to connect",
-					    "detail", PACKAGE " was unable to connect to the remote web server.",
+					    "detail", UTM_PRODUCT " was unable to connect to the remote web server.",
 					    "error", strerror(errno),
 					    NULL);
 			goto send_error;
@@ -1573,7 +1992,7 @@
 			    request->host, connptr->server_fd);
 
 		if (!connptr->connect_method)
-			establish_http_connection(connptr, request);
+			establish_http_connection(connptr, request, hashofheaders);
 	}
 
       send_error:
@@ -1608,6 +2027,11 @@
 			destroy_conn(connptr);
 			return;
 		}
+//		content_check_required(connptr);
+//		if(!connptr->check_content)
+//		{
+//			send_server_headers(connptr);
+//		}
 	} else {
 		if (send_ssl_response(connptr) < 0) {
 			log_message(LOG_ERR,
@@ -1617,9 +2041,41 @@
 			return;
 		}
 	}
+	
+	connptr->spacedaemon = NULL;
+	if (connptr->connect_method) {
+		relay_connection(connptr);
+	} else {
+		switch (connptr->check_content) {
+			case CONN_CCHECK_PASSTHRU:
+				send_server_headers(connptr);
+				relay_connection(connptr);
+				break;
+
+			case CONN_CCHECK_SCANONLY:
+				relay_check_content(connptr);
+				break;
+
+			case CONN_CCHECK_OVERSIZE:
+				send_ccheck_response(connptr, ccheckMsgTypeSize,
+				  "The requested file exceeds the maximum allowed size");
+				log_message(LOG_WARNING, "Maximum allowed file size exceeded "
+				  "(content-length: %d)",connptr->content_length.server); 
+				break;
 
-	relay_connection(connptr);
+			case CONN_CCHECK_REDIRECT:
+				send_ccheck_redirect(connptr);
+				break;
 
+			default:
+				break;
+		}
+	}
+
+	/* Release Space from SpaceDaemon */
+	if(connptr->spacedaemon != NULL)
+		pasd_release(connptr->spacedaemon);
+	
 	log_message(LOG_INFO, "Closed connection between local client (fd:%d) and remote client (fd:%d)",
 		    connptr->client_fd, connptr->server_fd);
 
@@ -1629,3 +2085,5 @@
 	destroy_conn(connptr);
 	return;
 }
+
+// vim:ts=4:sw=4
diff -Naur tinyproxy-1.6.2-orig/src/scanner.c tinyproxy-1.6.2/src/scanner.c
--- tinyproxy-1.6.2-orig/src/scanner.c	2003-08-06 22:47:57.000000000 +0200
+++ tinyproxy-1.6.2/src/scanner.c	2009-08-28 10:48:00.000000000 +0200
@@ -20,7 +20,6 @@
 #include <string.h>
 #include <errno.h>
 #include <stdlib.h>
-#include <stdint.h> /* May break IA64 test-noansi-r */
 
 /* end standard C headers. */
 
@@ -368,8 +367,8 @@
 	*yy_cp = '\0'; \
 	(yy_c_buf_p) = yy_cp;
 
-#define YY_NUM_RULES 20
-#define YY_END_OF_BUFFER 21
+#define YY_NUM_RULES 22
+#define YY_END_OF_BUFFER 23
 /* This struct is not used in this scanner,
    but its presence is necessary. */
 struct yy_trans_info
@@ -377,14 +376,15 @@
 	flex_int32_t yy_verify;
 	flex_int32_t yy_nxt;
 	};
-static yyconst flex_int16_t yy_accept[52] =
+static yyconst flex_int16_t yy_accept[63] =
     {   0,
-        0,    0,    0,    0,   21,   20,    4,    2,    9,   20,
-        7,    7,    3,   20,   17,   16,   20,    4,    0,    1,
-        0,    6,    0,    7,    8,   17,   15,   10,   11,   12,
-       13,   14,    0,    6,    5,    7,    0,    0,    6,    7,
-        0,    0,    0,    0,   18,    0,    0,   18,   19,   18,
-        0
+        0,    0,    0,    0,   23,   22,    4,    2,    9,   22,
+        7,    7,    3,   22,   22,   17,   16,   22,    4,    0,
+        0,    1,    0,    6,    0,    7,    8,    8,   17,   15,
+       10,   11,   12,   13,   14,    0,    0,    6,    5,    7,
+        8,    0,    0,    0,    0,    6,    7,    8,   20,    0,
+        0,   21,    0,    0,   21,   18,    0,    0,   18,   19,
+       18,    0
     } ;
 
 static yyconst flex_int32_t yy_ec[256] =
@@ -393,16 +393,16 @@
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    2,    1,    4,    5,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    6,    7,    8,    9,   10,   10,
-       10,   10,   10,   10,   10,   10,   10,   11,    1,    1,
-        1,    1,    1,    1,   13,   14,   14,   14,   14,   14,
-       14,   14,   14,   14,   14,   14,   14,   15,   14,   14,
-       14,   16,   14,   17,   14,   18,   14,   19,   14,   14,
-        1,   12,    1,    1,    6,    1,   13,   14,   14,   14,
-
-       14,   14,   14,   14,   14,   14,   14,   14,   14,   15,
-       14,   14,   14,   16,   14,   17,   14,   18,   14,   19,
-       14,   14,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    6,    7,    1,    8,    9,   10,   11,   12,   12,
+       12,   12,   12,   12,   12,   12,   12,   13,    1,    1,
+        1,    1,    1,    1,   16,   17,   18,   17,   19,   17,
+       17,   17,   17,   17,   17,   17,   17,   20,   17,   21,
+       17,   22,   17,   23,   17,   24,   17,   25,   17,   17,
+        1,   14,    1,    1,   15,    1,   16,   17,   18,   17,
+
+       19,   17,   17,   17,   17,   17,   17,   17,   17,   20,
+       17,   21,   17,   22,   17,   23,   17,   24,   17,   25,
+       17,   17,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -419,77 +419,86 @@
         1,    1,    1,    1,    1
     } ;
 
-static yyconst flex_int32_t yy_meta[20] =
+static yyconst flex_int32_t yy_meta[26] =
     {   0,
-        1,    1,    1,    2,    1,    3,    4,    5,    6,    6,
-        1,    2,    3,    3,    3,    3,    3,    3,    3
+        1,    2,    2,    3,    1,    4,    5,    6,    6,    1,
+        6,    6,    1,    3,    7,    6,    6,    6,    6,    6,
+        6,    6,    6,    6,    6
     } ;
 
-static yyconst flex_int16_t yy_base[68] =
+static yyconst flex_int16_t yy_base[71] =
     {   0,
-        0,    0,   16,   17,  117,  118,  114,  118,  118,  112,
-       23,  107,  118,    0,    0,  118,   30,  111,  109,  118,
-       13,   99,   15,   96,    0,    0,  118,  118,  118,  118,
-      118,  118,   93,   90,   17,   87,   25,   84,   27,   29,
-       81,   78,   31,   66,   62,   59,   40,   36,   42,   23,
-      118,   52,   58,   61,   65,   71,   77,   80,   83,   86,
-       89,   92,   95,   98,  101,  103,  105
+        0,    0,   22,   23,  146,  147,  143,  147,    0,  141,
+       29,   19,  147,    0,  120,    0,  147,   39,  120,   79,
+       80,  147,   21,   33,   23,   37,    0,   53,    0,  147,
+      147,  147,  147,  147,  147,   63,   41,   55,   45,   59,
+       46,   47,   54,   61,   65,   67,   69,   34,  147,   73,
+       34,    0,   75,   79,    0,   82,   30,   84,   87,   89,
+       19,  147,  101,  104,  110,  112,  119,  126,  130,  136
     } ;
 
-static yyconst flex_int16_t yy_def[68] =
+static yyconst flex_int16_t yy_def[71] =
     {   0,
-       51,    1,   52,   52,   51,   51,   51,   51,   51,   53,
-       51,   54,   51,   55,   56,   51,   57,   51,   53,   51,
-       51,   58,   51,   59,   55,   56,   51,   51,   51,   51,
-       51,   51,   60,   61,   51,   62,   51,   63,   51,   51,
-       64,   51,   51,   65,   66,   51,   51,   67,   51,   51,
-        0,   51,   51,   51,   51,   51,   51,   51,   51,   51,
-       51,   51,   51,   51,   51,   51,   51
+       62,    1,   63,   63,   62,   62,   62,   62,   64,   65,
+       62,   62,   62,   66,   66,   67,   62,   68,   62,   64,
+       65,   62,   62,   62,   62,   62,   66,   66,   67,   62,
+       62,   62,   62,   62,   62,   69,   62,   62,   62,   62,
+       66,   62,   69,   62,   62,   62,   62,   66,   62,   62,
+       62,   70,   62,   62,   70,   62,   62,   62,   62,   62,
+       62,    0,   62,   62,   62,   62,   62,   62,   62,   62
     } ;
 
-static yyconst flex_int16_t yy_nxt[138] =
+static yyconst flex_int16_t yy_nxt[173] =
     {   0,
-        6,    7,    8,    9,   10,    6,    6,    6,   11,   12,
-       13,    6,   14,   14,   14,   14,   14,   14,   14,   16,
-       16,   33,   33,   35,   35,   35,   35,   17,   17,   21,
-       47,   22,   22,   41,   41,   39,   39,   40,   40,   45,
-       45,   23,   28,   47,   29,   30,   31,   32,   49,   49,
-       49,   49,   15,   15,   15,   15,   15,   15,   19,   19,
-       19,   19,   19,   19,   24,   43,   24,   25,   25,   47,
-       25,   26,   43,   26,   26,   26,   26,   27,   27,   27,
-       27,   27,   27,   34,   37,   34,   36,   43,   36,   38,
-       37,   38,   39,   21,   39,   40,   21,   40,   42,   37,
-
-       42,   44,   21,   44,   46,   21,   46,   48,   48,   50,
-       50,   20,   18,   21,   20,   18,   51,    5,   51,   51,
-       51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
-       51,   51,   51,   51,   51,   51,   51
+        6,    7,    8,    9,   10,    6,    6,    6,    6,    6,
+       11,   12,   13,    6,    6,   14,   14,   14,   14,   14,
+       15,   14,   14,   14,   14,   17,   17,   23,   58,   26,
+       26,   37,   37,   39,   39,   18,   18,   23,   53,   24,
+       24,   23,   44,   38,   38,   23,   52,   40,   40,   44,
+       49,   45,   45,   25,   31,   39,   39,   49,   32,   62,
+       33,   34,   35,   23,   48,   46,   46,   23,   42,   47,
+       47,   50,   50,   44,   41,   51,   51,   46,   46,   47,
+       47,   53,   22,   54,   54,   56,   56,   53,   36,   57,
+       57,   58,   59,   59,   60,   60,   58,   61,   61,   60,
+
+       60,   16,   16,   16,   16,   16,   16,   16,   20,   20,
+       21,   21,   21,   21,   21,   21,   21,   27,   27,   29,
+       29,   19,   29,   29,   29,   29,   30,   30,   30,   30,
+       30,   30,   30,   43,   43,   43,   55,   28,   55,   55,
+       55,   55,   55,   22,   19,   62,    5,   62,   62,   62,
+       62,   62,   62,   62,   62,   62,   62,   62,   62,   62,
+       62,   62,   62,   62,   62,   62,   62,   62,   62,   62,
+       62,   62
     } ;
 
-static yyconst flex_int16_t yy_chk[138] =
+static yyconst flex_int16_t yy_chk[173] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    3,
-        4,   21,   21,   23,   23,   35,   35,    3,    4,   11,
-       50,   11,   11,   37,   37,   39,   39,   40,   40,   43,
-       43,   11,   17,   48,   17,   17,   17,   17,   47,   47,
-       49,   49,   52,   52,   52,   52,   52,   52,   53,   53,
-       53,   53,   53,   53,   54,   46,   54,   55,   55,   45,
-       55,   56,   44,   56,   56,   56,   56,   57,   57,   57,
-       57,   57,   57,   58,   42,   58,   59,   41,   59,   60,
-       38,   60,   61,   36,   61,   62,   34,   62,   63,   33,
-
-       63,   64,   24,   64,   65,   22,   65,   66,   66,   67,
-       67,   19,   18,   12,   10,    7,    5,   51,   51,   51,
-       51,   51,   51,   51,   51,   51,   51,   51,   51,   51,
-       51,   51,   51,   51,   51,   51,   51
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    3,    4,   12,   61,   12,
+       12,   23,   23,   25,   25,    3,    4,   11,   57,   11,
+       11,   24,   51,   24,   24,   26,   48,   26,   26,   37,
+       42,   37,   37,   11,   18,   39,   39,   43,   18,   43,
+       18,   18,   18,   38,   41,   38,   38,   40,   36,   40,
+       40,   44,   44,   45,   28,   45,   45,   46,   46,   47,
+       47,   50,   21,   50,   50,   53,   53,   54,   20,   54,
+       54,   56,   56,   56,   58,   58,   59,   59,   59,   60,
+
+       60,   63,   63,   63,   63,   63,   63,   63,   64,   64,
+       65,   65,   65,   65,   65,   65,   65,   66,   66,   67,
+       67,   19,   67,   67,   67,   67,   68,   68,   68,   68,
+       68,   68,   68,   69,   69,   69,   70,   15,   70,   70,
+       70,   70,   70,   10,    7,    5,   62,   62,   62,   62,
+       62,   62,   62,   62,   62,   62,   62,   62,   62,   62,
+       62,   62,   62,   62,   62,   62,   62,   62,   62,   62,
+       62,   62
     } ;
 
 /* Table of booleans, true if rule could match eol. */
-static yyconst flex_int32_t yy_rule_can_match_eol[21] =
+static yyconst flex_int32_t yy_rule_can_match_eol[23] =
     {   0,
 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 
-    0,     };
+    0, 0, 0,     };
 
 static yy_state_type yy_last_accepting_state;
 static char *yy_last_accepting_cpos;
@@ -526,6 +535,8 @@
  */
 #line 20 "scanner.l"
 
+#include "common.h"
+
 #include "tinyproxy.h"
 
 #include "grammar.h"
@@ -567,6 +578,25 @@
 	{ "errorfile",	         KW_ERRORPAGE },
 	{ "defaulterrorfile",    KW_DEFAULT_ERRORPAGE },
 	{ "statfile",            KW_STATPAGE },
+	{ "clamavport",          KW_CLAMAV_PORT },
+	{ "ccheckerrfile",       KW_CCHECK_ERR_FILE },
+	{ "adminemail",          KW_ADMIN_EMAIL },
+	{ "ccheckexclude",       KW_CCHECK_MIME_EXCLUDE },
+	{ "cchecksafeurl",       KW_CCHECK_SAFE_URL },
+	{ "ccheckpithresh",      KW_CCHECK_PI_THRESH },
+	{ "chroot",              KW_CHROOT },
+	{ "ccheckuserealsize",   KW_CCHECK_USE_REAL_SIZE },
+	{ "ccheckmaxsize",       KW_CCHECK_MAX_SIZE },
+	{ "ccheckmaxsizepass",   KW_CCHECK_MAX_SIZE_PASS },
+	{ "ccheckminfree",       KW_CCHECK_MIN_FREE },
+	{ "cchecktempdir",       KW_CCHECK_TEMP_DIR },
+	{ "ccheckvirtdir",       KW_CCHECK_VIRT_DIR },
+	{ "ccheckredirecturl",   KW_CCHECK_REDIRECT_URL },
+	{ "ccheckpeekbufsize",   KW_CCHECK_PEEKBUF_SIZE },
+	{ "ccheckscanretries",   KW_CCHECK_SCAN_RETRIES },
+	{ "ccheckupdinterval",   KW_CCHECK_UPD_INTERVAL },
+	{ "ccheckredirua",       KW_CCHECK_REDIRECT_UA },
+	{ "adderrtext",          KW_ADD_ERR_TEXT },
 
         /* loglevel and the settings */
         { "loglevel",            KW_LOGLEVEL },
@@ -597,7 +627,7 @@
 static void append_char(char c);
 
 
-#line 601 "lex.yy.c"
+#line 631 "lex.yy.c"
 
 #define INITIAL 0
 #define string 1
@@ -749,10 +779,10 @@
 	register char *yy_cp, *yy_bp;
 	register int yy_act;
     
-#line 103 "scanner.l"
+#line 125 "scanner.l"
 
 
-#line 756 "lex.yy.c"
+#line 786 "lex.yy.c"
 
 	if ( (yy_init) )
 		{
@@ -805,13 +835,13 @@
 			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 				{
 				yy_current_state = (int) yy_def[yy_current_state];
-				if ( yy_current_state >= 52 )
+				if ( yy_current_state >= 63 )
 					yy_c = yy_meta[(unsigned int) yy_c];
 				}
 			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
 			++yy_cp;
 			}
-		while ( yy_current_state != 51 );
+		while ( yy_current_state != 62 );
 		yy_cp = (yy_last_accepting_cpos);
 		yy_current_state = (yy_last_accepting_state);
 
@@ -846,48 +876,48 @@
 (yy_c_buf_p) = yy_cp -= 1;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 105 "scanner.l"
+#line 127 "scanner.l"
 ;
 	YY_BREAK
 case 2:
 /* rule 2 can match eol */
 YY_RULE_SETUP
-#line 106 "scanner.l"
+#line 128 "scanner.l"
 { return '\n'; }
 	YY_BREAK
 case 3:
 YY_RULE_SETUP
-#line 107 "scanner.l"
+#line 129 "scanner.l"
 { return ':'; }
 	YY_BREAK
 case 4:
 YY_RULE_SETUP
-#line 108 "scanner.l"
+#line 130 "scanner.l"
 ;
 	YY_BREAK
 case 5:
 YY_RULE_SETUP
-#line 109 "scanner.l"
+#line 131 "scanner.l"
 { yylval.num = strtol(yytext, NULL, 16); return NUMBER; }
 	YY_BREAK
 case 6:
 YY_RULE_SETUP
-#line 110 "scanner.l"
+#line 132 "scanner.l"
 { yylval.num = strtol(yytext, NULL, 8); return NUMBER; }
 	YY_BREAK
 case 7:
 YY_RULE_SETUP
-#line 111 "scanner.l"
+#line 133 "scanner.l"
 { yylval.num = atoi(yytext); return NUMBER; }
 	YY_BREAK
 case 8:
 YY_RULE_SETUP
-#line 112 "scanner.l"
+#line 134 "scanner.l"
 { return check_reserved_words(yytext); }
 	YY_BREAK
 case 9:
 YY_RULE_SETUP
-#line 114 "scanner.l"
+#line 136 "scanner.l"
 {
 			        tiny_str = tiny_buf;
 				BEGIN(string);
@@ -895,38 +925,38 @@
 	YY_BREAK
 case 10:
 YY_RULE_SETUP
-#line 118 "scanner.l"
+#line 140 "scanner.l"
 { append_char(7); }
 	YY_BREAK
 case 11:
 YY_RULE_SETUP
-#line 119 "scanner.l"
+#line 141 "scanner.l"
 { append_char(10); }
 	YY_BREAK
 case 12:
 YY_RULE_SETUP
-#line 120 "scanner.l"
+#line 142 "scanner.l"
 { append_char(13); }
 	YY_BREAK
 case 13:
 YY_RULE_SETUP
-#line 121 "scanner.l"
+#line 143 "scanner.l"
 { append_char(9); }
 	YY_BREAK
 case 14:
 YY_RULE_SETUP
-#line 122 "scanner.l"
+#line 144 "scanner.l"
 { append_char(11); }
 	YY_BREAK
 case 15:
 /* rule 15 can match eol */
 YY_RULE_SETUP
-#line 123 "scanner.l"
+#line 145 "scanner.l"
 { append_string(1, yytext + 1); }
 	YY_BREAK
 case 16:
 YY_RULE_SETUP
-#line 124 "scanner.l"
+#line 146 "scanner.l"
 {
 				BEGIN(INITIAL);
 				yylval.cptr = strdup(tiny_buf);
@@ -936,25 +966,43 @@
 case 17:
 /* rule 17 can match eol */
 YY_RULE_SETUP
-#line 129 "scanner.l"
+#line 151 "scanner.l"
 { append_string(strlen(yytext), yytext); }
 	YY_BREAK
 case 18:
 YY_RULE_SETUP
-#line 132 "scanner.l"
+#line 154 "scanner.l"
 { yylval.cptr = strdup(yytext); return NUMERIC_ADDRESS; }
 	YY_BREAK
 case 19:
 YY_RULE_SETUP
-#line 133 "scanner.l"
+#line 155 "scanner.l"
 { yylval.cptr = strdup(yytext); return NETMASK_ADDRESS; }
 	YY_BREAK
 case 20:
 YY_RULE_SETUP
-#line 136 "scanner.l"
+#line 156 "scanner.l"
+{
+					yylval.cptr = strdup(yytext + 1);
+					yylval.cptr[yyleng - 2] = 0;
+					return MIME_TYPE;
+				}
+	YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 161 "scanner.l"
+{
+					yylval.cptr = strdup(yytext + 5);
+					yylval.cptr[yyleng - 5] = 0;
+					return PCRE_STRING;
+				}
+	YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 168 "scanner.l"
 ECHO;
 	YY_BREAK
-#line 958 "lex.yy.c"
+#line 1006 "lex.yy.c"
 case YY_STATE_EOF(INITIAL):
 case YY_STATE_EOF(string):
 	yyterminate();
@@ -1240,7 +1288,7 @@
 		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 			{
 			yy_current_state = (int) yy_def[yy_current_state];
-			if ( yy_current_state >= 52 )
+			if ( yy_current_state >= 63 )
 				yy_c = yy_meta[(unsigned int) yy_c];
 			}
 		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@@ -1268,11 +1316,11 @@
 	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 		{
 		yy_current_state = (int) yy_def[yy_current_state];
-		if ( yy_current_state >= 52 )
+		if ( yy_current_state >= 63 )
 			yy_c = yy_meta[(unsigned int) yy_c];
 		}
 	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-	yy_is_jam = (yy_current_state == 51);
+	yy_is_jam = (yy_current_state == 62);
 
 	return yy_is_jam ? 0 : yy_current_state;
 }
@@ -1931,7 +1979,7 @@
 #undef YY_DECL_IS_OURS
 #undef YY_DECL
 #endif
-#line 136 "scanner.l"
+#line 168 "scanner.l"
 
 
 
diff -Naur tinyproxy-1.6.2-orig/src/scanner.l tinyproxy-1.6.2/src/scanner.l
--- tinyproxy-1.6.2-orig/src/scanner.l	2003-06-26 20:26:10.000000000 +0200
+++ tinyproxy-1.6.2/src/scanner.l	2009-08-28 10:48:00.000000000 +0200
@@ -18,6 +18,8 @@
  */
 %{
 
+#include "common.h"
+
 #include "tinyproxy.h"
 
 #include "grammar.h"
@@ -59,6 +61,25 @@
 	{ "errorfile",	         KW_ERRORPAGE },
 	{ "defaulterrorfile",    KW_DEFAULT_ERRORPAGE },
 	{ "statfile",            KW_STATPAGE },
+	{ "clamavport",          KW_CLAMAV_PORT },
+	{ "ccheckerrfile",       KW_CCHECK_ERR_FILE },
+	{ "adminemail",          KW_ADMIN_EMAIL },
+	{ "ccheckexclude",       KW_CCHECK_MIME_EXCLUDE },
+	{ "cchecksafeurl",       KW_CCHECK_SAFE_URL },
+	{ "ccheckpithresh",      KW_CCHECK_PI_THRESH },
+	{ "chroot",              KW_CHROOT },
+	{ "ccheckuserealsize",   KW_CCHECK_USE_REAL_SIZE },
+	{ "ccheckmaxsize",       KW_CCHECK_MAX_SIZE },
+	{ "ccheckmaxsizepass",   KW_CCHECK_MAX_SIZE_PASS },
+	{ "ccheckminfree",       KW_CCHECK_MIN_FREE },
+	{ "cchecktempdir",       KW_CCHECK_TEMP_DIR },
+	{ "ccheckvirtdir",       KW_CCHECK_VIRT_DIR },
+	{ "ccheckredirecturl",   KW_CCHECK_REDIRECT_URL },
+	{ "ccheckpeekbufsize",   KW_CCHECK_PEEKBUF_SIZE },
+	{ "ccheckscanretries",   KW_CCHECK_SCAN_RETRIES },
+	{ "ccheckupdinterval",   KW_CCHECK_UPD_INTERVAL },
+	{ "ccheckredirua",       KW_CCHECK_REDIRECT_UA },
+	{ "adderrtext",          KW_ADD_ERR_TEXT },
 
         /* loglevel and the settings */
         { "loglevel",            KW_LOGLEVEL },
@@ -97,6 +118,7 @@
 alpha		[a-zA-Z]
 alphanum	[a-zA-Z0-9]
 word		[^ \#'"\(\)\{\}\\;\n\t,|\.]
+alphamime	[a-zA-Z0-9\.\+\-]
 
 %x string
 
@@ -131,6 +153,16 @@
 
 ({digit}{1,3}\.){3}{digit}{1,3} { yylval.cptr = strdup(yytext); return NUMERIC_ADDRESS; }
 ({digit}{1,3}\.){3}{digit}{1,3}\/{digit}+ { yylval.cptr = strdup(yytext); return NETMASK_ADDRESS; }
+\"{alphamime}+\/(({alphamime}+)|(\*))\" {
+					yylval.cptr = strdup(yytext + 1);
+					yylval.cptr[yyleng - 2] = 0;
+					return MIME_TYPE;
+				}
+pcre:[^ \t\n]* {
+					yylval.cptr = strdup(yytext + 5);
+					yylval.cptr[yyleng - 5] = 0;
+					return PCRE_STRING;
+				}
 
 
 %%
diff -Naur tinyproxy-1.6.2-orig/src/tinyproxy.c tinyproxy-1.6.2/src/tinyproxy.c
--- tinyproxy-1.6.2-orig/src/tinyproxy.c	2003-03-17 05:24:19.000000000 +0100
+++ tinyproxy-1.6.2/src/tinyproxy.c	2009-08-28 10:48:00.000000000 +0200
@@ -35,6 +35,7 @@
 #include "sock.h"
 #include "stats.h"
 #include "utils.h"
+#include "virus.h"
 
 void takesig(int sig);
 
@@ -68,8 +69,15 @@
 		break;
 
 	case SIGCHLD:
-		while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
-			;
+		while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+			if(pid > 0 && WIFSIGNALED(status))
+			{
+				log_message(LOG_WARNING,
+				  "Child terminated with signal %s",
+				  strsignal(WTERMSIG(status)));
+			}
+				remove_child(pid);
+		}
 		break;
 	}
 
@@ -158,6 +166,7 @@
 	 */
 #if defined(HAVE_SETRLIMIT) && defined(NDEBUG)
 	struct rlimit core_limit = { 0, 0 };
+	memset(&config, 0, sizeof(struct config_s));
 	if (setrlimit(RLIMIT_CORE, &core_limit) < 0) {
 		fprintf(stderr, "%s: Could not set the core limit to zero.\n",
 			argv[0]);
@@ -266,6 +275,52 @@
 			    MAX_IDLE_TIME);
 		config.idletimeout = MAX_IDLE_TIME;
 	}
+	if(config.clamav_port == 0)
+		config.clamav_port = 3310;
+	if(config.ccheck_temp_dir == NULL)
+		config.ccheck_temp_dir = strdup("/tmp");
+	if (config.ccheck_peekbuf_size == 0) {
+		config.ccheck_peekbuf_size = 40960;
+	}
+	if (config.ccheck_scan_retries == 0) {
+		config.ccheck_scan_retries = 5;
+	}
+	if (config.ccheck_upd_interval == 0) {
+		config.ccheck_upd_interval = 2;
+	}
+	if ((config.ccheck_pi_thresh > 0) && (config.ccheck_redirect_url == NULL)) {
+		fprintf(stderr,
+			"%s: use of progress indicator needs a redirect URL.\n",
+			argv[0]);
+		exit(EX_SOFTWARE);
+	}
+	if(config.chroot)
+	{
+		trim_slash(config.ccheck_temp_dir);
+		trim_slash(config.chroot);
+		if(!config.syslog)
+		{
+			trim_slash(config.logf_name);
+			if(!path_inside_chroot(config.logf_name))
+			{
+				fprintf(stderr, "%s: Logfile path not "
+				  "inside chroot dir\n", argv[0]);
+				exit(EX_SOFTWARE);
+			}
+			if(!path_inside_chroot(config.ccheck_temp_dir))
+			{
+				fprintf(stderr, "%s: Content check temp "
+				  "directory not inside chroot dir\n", argv[0]);
+				exit(EX_SOFTWARE);
+			}
+			config.virt_ccheck_temp_dir = config.ccheck_temp_dir +
+			  strlen(config.chroot);
+		}
+	}
+	else
+	{
+		config.virt_ccheck_temp_dir = config.ccheck_temp_dir;
+	}
 
 	init_stats();
 
@@ -312,47 +367,77 @@
 		exit(EX_OSERR);
 	}
 
-	/*
-	 * Switch to a different user.
-	 */
-	if (geteuid() == 0) {
-		if (config.group && strlen(config.group) > 0) {
+	/* do chroot if requested */
+	if (geteuid() == 0)
+	{
+		/* first get userid and groupid of non-privileged user
+		 * because, after chroot we can't access the
+		 * passwd and group file
+		 */
+		if(config.group && strlen(config.group) > 0)
+		{
 			thisgroup = getgrnam(config.group);
-			if (!thisgroup) {
+			if (!thisgroup)
+			{
 				fprintf(stderr,
-					"%s: Unable to find group \"%s\".\n",
-					argv[0], config.group);
+				  "%s: Unable to find group \"%s\".\n",
+				  argv[0], config.group);
 				exit(EX_NOUSER);
 			}
-			if (setgid(thisgroup->gr_gid) < 0) {
-				fprintf(stderr,
-					"%s: Unable to change to group \"%s\".\n",
-					argv[0], config.group);
-				exit(EX_CANTCREAT);
-			}
-			log_message(LOG_INFO, "Now running as group \"%s\".",
-				    config.group);
 		}
-		if (config.username && strlen(config.username) > 0) {
+		if(config.username && strlen(config.username) > 0)
+		{
 			thisuser = getpwnam(config.username);
-			if (!thisuser) {
+			if(!thisuser)
+			{
 				fprintf(stderr,
-					"%s: Unable to find user \"%s\".",
-					argv[0], config.username);
+				  "%s: Unable to find user \"%s\".",
+				  argv[0], config.username);
 				exit(EX_NOUSER);
 			}
-			if (setuid(thisuser->pw_uid) < 0) {
+		}
+	}
+	if(config.chroot != NULL && chroot(config.chroot) < 0)
+	{
+		fprintf(stderr, "%s: unable to chroot to %s, %s\n",
+		  argv[0], config.chroot, strerror(errno));
+		exit(EX_SOFTWARE);
+	}
+
+	/*
+	 * Switch to a different user.
+	 */
+	if(geteuid() == 0)
+	{
+		if(thisgroup)
+		{
+			if(setgid(thisgroup->gr_gid) < 0)
+			{
+				fprintf(stderr,
+				  "%s: Unable to change to group \"%s\".\n",
+				  argv[0], config.group);
+				exit(EX_CANTCREAT);
+			}
+			log_message(LOG_INFO, "Now running as group \"%s\".",
+			  config.group);
+		}
+		if(thisuser)
+		{
+			if(setuid(thisuser->pw_uid) < 0)
+			{
 				fprintf(stderr,
-					"%s: Unable to change to user \"%s\".",
-					argv[0], config.username);
+				  "%s: Unable to change to user \"%s\".",
+				  argv[0], config.username);
 				exit(EX_CANTCREAT);
 			}
 			log_message(LOG_INFO, "Now running as user \"%s\".",
-				    config.username);
+			  config.username);
 		}
-	} else {
+	}
+	else
+	{
 		log_message(LOG_WARNING,
-			    "Not running as root, so not changing UID/GID.");
+		  "Not running as root, so not changing UID/GID.");
 	}
 
 	if (child_pool_create() < 0) {
diff -Naur tinyproxy-1.6.2-orig/src/tinyproxy.h tinyproxy-1.6.2/src/tinyproxy.h
--- tinyproxy-1.6.2-orig/src/tinyproxy.h	2003-06-20 19:02:12.000000000 +0200
+++ tinyproxy-1.6.2/src/tinyproxy.h	2009-08-28 10:48:00.000000000 +0200
@@ -86,6 +86,34 @@
 	 * The HTML statistics page. 
 	 */
 	char *statpage;
+
+	/*
+	 * Content Check
+	 */
+	int clamav_port;
+	char *ccheck_err_file;
+	char *admin_email;
+	char *chroot;
+	int ccheck_max_size;
+	int ccheck_max_size_pass;
+	int ccheck_min_free;
+	int ccheck_use_real_size;
+	char *ccheck_temp_dir;
+	char *ccheck_virt_dir;
+	char *ccheck_admin;
+	char *virt_ccheck_temp_dir;
+	struct exclude_mtype_s {
+		char *main;
+		char *sub;
+	} **exclude_mtypes;
+	pcre **exclude_url_regexp;
+	int ccheck_pi_thresh;
+	char *ccheck_redirect_url;
+	int ccheck_peekbuf_size;
+	int ccheck_scan_retries;
+	int ccheck_upd_interval;
+	pcre **ua_regexp;
+	char *add_err_text;
 };
 
 /* Global Structures used in the program */
diff -Naur tinyproxy-1.6.2-orig/src/virus.c tinyproxy-1.6.2/src/virus.c
--- tinyproxy-1.6.2-orig/src/virus.c	1970-01-01 01:00:00.000000000 +0100
+++ tinyproxy-1.6.2/src/virus.c	2009-08-28 10:48:00.000000000 +0200
@@ -0,0 +1,1133 @@
+#include "common.h"
+#include "tinyproxy.h"
+#include "buffer.h"
+#include "conns.h"
+#include "htmlerror.h"
+#include "heap.h"
+#include "log.h"
+#include "virus.h"
+#include <pa/scanqclient.h>
+
+#include <sys/param.h>
+#include <sys/vfs.h>
+
+#include <magic.h>
+
+
+#define DLSTAT_UNDEFINED	0
+#define DLSTAT_PASSTHRU		1
+#define DLSTAT_DOWNLOAD		2
+#define DLSTAT_COMPLETE		3
+#define DLSTAT_SCANNING		4
+#define DLSTAT_SCANNED		5
+#define DLSTAT_VIRUS		6
+#define DLSTAT_SCANERROR	7
+
+
+typedef struct _DLSTAT {
+	FILE	*ds_f;
+	time_t	ds_lastupd;
+	int		ds_laststat;
+	char	*ds_fname;
+	char	*ds_mime;
+	int		ds_conlen;
+	int		ds_status;
+	int		ds_xfered;
+	char	*ds_scanres;
+	char	*ds_cntdisp;
+	int		ds_cntdisp_invalid;
+} DLSTAT;
+
+
+char *mkdlfntmpl(char *fn, struct conn_s *connptr)
+{
+	srandom(time(NULL) + getpid());
+	sprintf(fn, "%s/dl%08lxXXXXXX", config.virt_ccheck_temp_dir,
+	  random());
+
+	return (fn);
+}
+
+
+void update_status(DLSTAT *dls, struct conn_s *connptr)
+{
+	char	*txt, *fn, *mime, *hdr;
+	time_t	t;
+
+	if (dls == NULL) {
+		return;
+	}
+
+	if (dls->ds_f == NULL) {
+		return;
+	}
+
+	time(&t);
+
+	if (dls->ds_status == dls->ds_laststat) {
+		if ((t - dls->ds_lastupd) < config.ccheck_upd_interval) {
+			return;
+		}
+	}
+
+	dls->ds_lastupd = t;
+	dls->ds_laststat = dls->ds_status;
+
+	switch (dls->ds_status) {
+		case DLSTAT_DOWNLOAD:
+		case DLSTAT_COMPLETE:
+			txt = "downloading";
+			break;
+
+		case DLSTAT_SCANNING:
+			txt = "scanning";
+			break;
+
+		case DLSTAT_SCANNED:
+			txt = "complete";
+			break;
+
+		case DLSTAT_VIRUS:
+			txt = "virus:%s";
+			break;
+
+		case DLSTAT_SCANERROR:
+			txt = "error:%s";
+			break;
+
+		default:
+			txt = "undefined";
+			break;
+	}
+
+	mime = dls->ds_mime;
+	if (mime == NULL) {
+		mime = "application/octet-stream";
+	}
+
+	fn = dls->ds_fname;
+	if (fn == NULL) {
+		fn = "download.bin";
+	}
+
+	flock(fileno(dls->ds_f), LOCK_EX);
+	rewind(dls->ds_f);
+	ftruncate(fileno(dls->ds_f), 0);
+	if (dls->ds_scanres != NULL) {
+		fprintf(dls->ds_f, txt, dls->ds_scanres);
+	} else {
+		fprintf(dls->ds_f, txt);
+	}
+	fprintf(dls->ds_f, "\n%s\n%s\n%d\n%d\n%d\n",
+	  mime, fn, dls->ds_conlen,
+	  dls->ds_xfered, t);
+
+	if ((hashmap_entry_by_key(connptr->server_headers, "Content-Disposition",
+	  (void **)&hdr) > 0) && !dls->ds_cntdisp_invalid) {
+	  	fprintf(dls->ds_f, "Content-Disposition: %s\n", hdr);
+	} else {
+		fprintf(dls->ds_f, "Content-Disposition: inline; filename=\"%s\"\n",
+		  fn);
+	}
+	fflush(dls->ds_f);
+	fchmod(fileno(dls->ds_f), 0666);
+	flock(fileno(dls->ds_f), LOCK_UN);
+
+	return;
+}
+
+
+char *determine_filename(struct conn_s *connptr, int *cdi_flag)
+{
+	char		*hdr, *rq_line, *uri, *p, *q, *fn, *tok, *saveptr, *cd, *tmp;
+
+	fn = strdup("download.bin");
+
+	if ((rq_line = strdup(connptr->request_line)) == NULL) {
+		return (fn);
+	}
+
+	if ((p = strchr(rq_line, ' ')) == NULL) {
+		free(rq_line);
+		return (fn);
+	}
+
+	uri = p + 1;
+
+	if ((p = strchr(uri, ' ')) != NULL) {
+		*p = '\0';
+	}
+
+	if ((p = strrchr(uri, '/')) != NULL) {
+		p++;
+		if ((p - 3) >= uri) {
+			if (*(p - 3) != ':') {
+				if (strlen(p) > 0) {
+					if (fn != NULL) {
+						free(fn);
+					}
+					fn = strdup(p);
+				}
+			}
+		}
+	}
+
+	free(rq_line);
+
+	if (hashmap_entry_by_key(connptr->server_headers, "Content-Disposition",
+	  (void **)&hdr) > 0) {
+		if ((cd = strdup(hdr)) != NULL) {
+			tok = strtok_r(cd, "\t ;=", &saveptr);
+			p = NULL;
+
+			while (tok != NULL) {
+				if (strcasecmp(tok, "filename") == 0) {
+					p = tok + 9;
+					break;
+				}
+
+				tok = strtok_r(NULL, "\t ;=", &saveptr);
+			}
+
+			if (p != NULL) {
+				while ((*p != '\0') && (isspace(*p) || (*p == '='))) {
+					p++;
+				}
+
+				if (*p != '\0') {
+					if (*p == '"') {
+						p++;
+						q = p;
+						while ((*q != '\0') && (*q != '"')) {
+							q++;
+						}
+					} else {
+						q = p;
+						while ((*q != '\0') && !isspace(*p)) {
+							q++;
+						}
+					}
+
+					if ((tmp = malloc((q - p) + 1)) != NULL) {
+						memcpy(tmp, p, (q - p));
+						tmp[q - p] = '\0';
+						if (strlen(tmp) > 0) {
+							if (fn != NULL) {
+								free(fn);
+							}
+							fn = tmp;
+						} else {
+							free(tmp);
+							*cdi_flag = 1;
+						}
+					}
+				}
+			} else {
+				/* Content-Disposition does not contain a filename */
+				*cdi_flag = 1;
+			}
+
+			free(cd);
+		}
+	}
+
+	return (fn);
+}
+
+
+char *mime_magic(unsigned char *buf, int len)
+{
+	char	*str;
+	magic_t	mh;
+
+	if ((mh = magic_open(MAGIC_ERROR|MAGIC_MIME)) == NULL) {
+		return (NULL);
+	}
+
+	if (magic_load(mh, NULL) != 0) {
+		magic_close(mh);
+		return (NULL);
+	}
+
+	str = strdup(magic_buffer(mh, buf, len));
+
+	magic_close(mh);
+
+	return (str);
+}
+
+
+int scan_file(char *filename, struct conn_s *connptr, char *msg, int msg_size)
+{
+	int		retry, res;
+	char	info[1000];
+
+	snprintf(info, sizeof(info), "Client: %s, Request: %s",
+	  connptr->forwarded_for, connptr->request_line);
+	retry = -1;
+
+	for (;;) {
+		res = pa_virus_scan("HTTP", filename, info);
+
+		if (res > 0) {
+			log_message(LOG_INFO, "No virus found");
+			snprintf(msg, msg_size, "No virus found");
+			break;
+		}
+
+		if (res == 0) {
+			log_message(LOG_WARNING, "Found virus: %s", pa_virus_name());
+			snprintf(msg, msg_size, "%s", pa_virus_name());
+			break;
+		}
+
+		log_message(LOG_WARNING, "Virus scan failed: %s", pa_virus_errstr());
+		retry++;
+
+		if (retry >= config.ccheck_scan_retries) {
+			snprintf(msg, msg_size, "%s", pa_virus_errstr());
+			break;
+		}
+
+		sleep(1 << retry);
+	}
+
+	return (res);
+}
+
+
+void send_ccheck_redirect(struct conn_s *connptr)
+{
+	char *headers =
+	  "Status: 302\r\n"
+	  "Content-Type: text/html\r\n"
+	  "Location: %s\r\n"
+	  "Server: %s/%s\r\n"
+	  "\r\n";
+	char *fallback_error =
+	  "<html><head><title>%s</title></head><body>"
+	  "<h1>%s</h1>"
+	  "The following error occured, but the proxy server was unable "
+	  "to find the error page<br/><br/>"
+	  "<b>%s</b><br/><br/>"
+	  "Please contact your administrator: <a href='mailto:%s'>%s</a>"
+	  "</body></html>";
+
+	fd_set rset, wset;
+	struct timeval tv;
+	time_t last_access;
+	int ret, passthru, sublen;
+	double tdiff;
+	int maxfd = max(connptr->client_fd, connptr->server_fd) + 1;
+	ssize_t bytes_received;
+	char *mime, *sub, *p, *dl_id, *redir_target;
+	unsigned char *peek;
+	struct exclude_mtype_s **type;
+	DLSTAT dls;
+
+	int	dlfd;
+	char dlfn[MAXPATHLEN], statfn[MAXPATHLEN];
+	char avmsg[512];
+
+	memset(&dls, 0x00, sizeof(dls));
+	memset(&avmsg, 0x00, sizeof(avmsg));
+	dls.ds_cntdisp_invalid = 0;
+	dls.ds_fname = determine_filename(connptr, &dls.ds_cntdisp_invalid);
+	dls.ds_conlen = connptr->content_length.server;
+	dls.ds_scanres = avmsg;
+	dls.ds_mime = "application/octet-stream";
+
+	socket_nonblocking(connptr->server_fd);
+
+	last_access = time(NULL);
+	passthru = 0;
+	mime = NULL;
+
+	for (;;) {
+		FD_ZERO(&rset);
+		FD_ZERO(&wset);
+
+		tv.tv_sec =
+		    config.idletimeout - difftime(time(NULL), last_access);
+		tv.tv_usec = 0;
+
+		if (passthru != 2) {
+			if (buffer_size(connptr->sbuffer) > 0)
+				FD_SET(connptr->client_fd, &wset);
+		}
+		if (buffer_size(connptr->cbuffer) > 0)
+			FD_SET(connptr->server_fd, &wset);
+		if (buffer_size(connptr->sbuffer) < MAXBUFFSIZE)
+			FD_SET(connptr->server_fd, &rset);
+		if (passthru != 2) {
+			if (buffer_size(connptr->cbuffer) < MAXBUFFSIZE)
+				FD_SET(connptr->client_fd, &rset);
+		}
+
+		ret = select(maxfd, &rset, &wset, NULL, &tv);
+	
+		if (ret == 0) {
+			tdiff = difftime(time(NULL), last_access);
+			if (tdiff > config.idletimeout) {
+				log_message(LOG_INFO,
+				  "Idle Timeout (after select) as %g > %u.",
+				  tdiff, config.idletimeout);
+				if (dls.ds_fname != NULL) {
+					free(dls.ds_fname);
+				}
+				return;
+			} else {
+				continue;
+			}
+		} else if (ret < 0) {
+			log_message(LOG_ERR,
+			  "relay_connection: select() error \"%s\". Closing connection (client_fd:%d, server_fd:%d)",
+			  strerror(errno), connptr->client_fd,
+			  connptr->server_fd);
+			if (dls.ds_fname != NULL) {
+				free(dls.ds_fname);
+			}
+			return;
+		} else {
+			/*
+			 * All right, something was actually selected so mark it.
+			 */
+			last_access = time(NULL);
+		}
+
+		if (FD_ISSET(connptr->server_fd, &rset)) {
+			bytes_received = read_buffer(connptr->server_fd, connptr->sbuffer);
+			if (bytes_received < 0)
+				break;
+
+			dls.ds_xfered += bytes_received;
+			connptr->content_length.server -= bytes_received;
+			if (connptr->content_length.server == 0)
+				break;
+		}
+		if (passthru != 2) {
+			if (FD_ISSET(connptr->client_fd, &rset)
+			    && read_buffer(connptr->client_fd, connptr->cbuffer) < 0) {
+				break;
+			}
+			if (FD_ISSET(connptr->server_fd, &wset)
+			    && write_buffer(connptr->server_fd, connptr->cbuffer) < 0) {
+				break;
+			}
+		}
+		if (passthru == 1) {
+			if (FD_ISSET(connptr->client_fd, &wset)
+			    && write_buffer(connptr->client_fd, connptr->sbuffer) < 0) {
+				break;
+			}
+		} else {
+			if (passthru == 0) {
+				if (buffer_size(connptr->sbuffer) >= config.ccheck_peekbuf_size) {
+					/* ok, we have enough shit in there to check */
+
+					mime = NULL;
+
+					if ((peek = peek_buffer(connptr->sbuffer)) != NULL) {
+						mime = mime_magic(peek, buffer_size(connptr->sbuffer));
+						free(peek);
+					}
+
+					if (mime == NULL) {
+						log_message(LOG_ERR, "Magic MIME reports: (NULL)");
+						passthru = 2;
+					}
+
+					if (mime != NULL) {
+						log_message(LOG_INFO, "Magic MIME reports: %s", mime);
+						dls.ds_mime = mime;
+
+						passthru = 2;
+
+						if ((sub = index(mime, '/')) != NULL) {
+							++sub;
+							if((p = index(sub, ';')) == NULL) 
+								sublen = strlen(sub);
+							else
+								sublen = p - sub;
+							if ((type = config.exclude_mtypes) != NULL) {
+								while(*type != NULL)
+								{
+									if(strncasecmp(mime, (*type)->main,
+									  strlen((*type)->main)) == 0 &&
+									  ((*type)->sub == NULL ||
+									  strncasecmp(sub, (*type)->sub, sublen) == 0))
+									{
+										passthru = 1;
+										log_message(LOG_INFO,
+										  "Passthru because magic MIME %s matched.",
+										  mime);
+										break;
+									}
+									++type;
+								}
+							}
+						}
+					}
+
+					log_message(LOG_INFO, "Final passthru decision: %d",
+					  passthru);
+
+					switch (passthru) {
+						case 1:
+							/* case passthru, no progress redirect */
+							if (mime != NULL) {
+								free(mime);
+								mime = NULL;
+							}
+							dls.ds_mime = NULL;
+							dls.ds_status = DLSTAT_PASSTHRU;
+							ret = write_message(connptr->client_fd, "%s\r\n",
+							  connptr->response_line);
+							send_server_headers(connptr);
+							socket_nonblocking(connptr->client_fd);
+							break;
+
+						case 2:
+							/* case no passthru, progress redirect */
+
+							/* should reserve space from spaced */
+							if (config.ccheck_use_real_size == 1) {
+								if (!(connptr->spacedaemon =
+								  pasd_request(pasd_client_type_http,
+								  connptr->content_length.server)))	{
+									log_message(LOG_WARNING,
+									  "PA-SpaceDaemon returned: %s",
+									  pasd_errstr);
+									if (dls.ds_fname != NULL) {
+										free(dls.ds_fname);
+									}
+									return;
+								}
+							} else {
+								if (!(connptr->spacedaemon =
+								  pasd_request(pasd_client_type_http,
+								  config.ccheck_max_size))) {
+									log_message(LOG_WARNING,
+									  "PA-SpaceDaemon returned: %s",
+									  pasd_errstr);
+									if (dls.ds_fname != NULL) {
+										free(dls.ds_fname);
+									}
+									return;
+								}
+							}
+
+							mkdlfntmpl(dlfn, connptr);
+							if ((dlfd = mkstemp(dlfn)) == -1) {
+								/* Bail out */
+								if (mime != NULL) {
+									free(mime);
+								}
+								socket_blocking(connptr->server_fd);
+								if (dls.ds_fname != NULL) {
+									free(dls.ds_fname);
+								}
+								return;
+							}
+
+							/* Isolate download ID from temp file name */
+							if ((dl_id = strrchr(dlfn, '/')) == NULL) {
+								/* Spooky, bail out! */
+								close(dlfd);
+								unlink(dlfn);
+								if (mime != NULL) {
+									free(mime);
+								}
+								socket_blocking(connptr->server_fd);
+								if (dls.ds_fname != NULL) {
+									free(dls.ds_fname);
+								}
+								return;
+							}
+							dl_id++;
+
+							/* Download status file is initially created here */
+							strcpy(statfn, dlfn);
+							strcat(statfn, ".status");
+							write_buffer_fd(dlfd, connptr->sbuffer);
+							dls.ds_status = DLSTAT_DOWNLOAD;
+							if ((dls.ds_f = fopen(statfn, "w")) == NULL) {
+								/* Bail out */
+								close(dlfd);
+								unlink(dlfn);
+								if (mime != NULL) {
+									free(mime);
+								}
+								socket_blocking(connptr->server_fd);
+								if (dls.ds_fname != NULL) {
+									free(dls.ds_fname);
+								}
+								return;
+							}
+							update_status(&dls, connptr);
+
+							/* Proper redirection target is built here */
+
+							redir_target = malloc(strlen(config.ccheck_redirect_url)
+							  + strlen(dl_id) + 2);
+							if (redir_target == NULL) {
+								/* OOM, bail out! */
+								fclose(dls.ds_f);
+								unlink(statfn);
+								close(dlfd);
+								unlink(dlfn);
+								if (mime != NULL) {
+									free(mime);
+								}
+								socket_blocking(connptr->server_fd);
+								if (dls.ds_fname != NULL) {
+									free(dls.ds_fname);
+								}
+								return;
+							}
+							sprintf(redir_target, config.ccheck_redirect_url, dl_id);
+							log_message(LOG_INFO, "Redirecting to %s", redir_target);
+
+							write_message(connptr->client_fd,
+							  "HTTP/%d.%d 302 Found\r\n",
+							  connptr->protocol.major, connptr->protocol.minor);
+							write_message(connptr->client_fd, headers,
+							  redir_target, PACKAGE, VERSION);
+							write_message(connptr->client_fd, fallback_error,
+							  "Redirect", "Redirect", "302 Found",
+							  config.admin_email, config.admin_email);
+
+							free(redir_target);
+							socket_blocking(connptr->client_fd);
+							shutdown(connptr->client_fd, SHUT_WR);
+							break;
+					}
+				}
+			} else {
+				/* client was redirected, need to save */
+
+				struct stat	st;
+
+				/* Need to check for abort */
+				if (stat(statfn, &st) == -1) {
+					if (errno == ENOENT) {
+						log_message(LOG_INFO, "Aborting transfer %s", dl_id);
+						fclose(dls.ds_f);
+						close(dlfd);
+						unlink(dlfn);
+						if (mime != NULL) {
+							free(mime);
+						}
+						socket_blocking(connptr->server_fd);
+						if (dls.ds_fname != NULL) {
+							free(dls.ds_fname);
+						}
+						return;
+					}
+				}
+
+				/* Need to check free space */
+				if (config.ccheck_min_free > 0) {
+					struct statfs fs;
+
+					if ((fstatfs(dlfd, &fs) != -1) &&
+					  (fs.f_bavail * 1024 < config.ccheck_min_free)) {
+						close(dlfd);
+						unlink(dlfn);
+
+						/* Communicate error via status file */
+						dls.ds_status = DLSTAT_SCANERROR;
+						dls.ds_scanres = "Download aborted due to low diskspace";
+						update_status(&dls, connptr);
+						fclose(dls.ds_f);
+						log_message(LOG_WARNING,
+						  "Free diskspace too low, aborting transfer %s", dl_id);
+
+						if (mime != NULL) {
+							free(mime);
+						}
+						socket_blocking(connptr->server_fd);
+						if (dls.ds_fname != NULL) {
+							free(dls.ds_fname);
+						}
+						return;
+					}
+				}
+
+				write_buffer_fd(dlfd, connptr->sbuffer);
+
+				/* Need to update download status */
+				update_status(&dls, connptr);
+			}
+		}
+	}
+
+	if (passthru != 2) {
+		/*
+		 * Here the server has closed the connection... write the
+		 * remainder to the client and then exit.
+		 */
+		socket_blocking(connptr->client_fd);
+		while (buffer_size(connptr->sbuffer) > 0) {
+			if (write_buffer(connptr->client_fd, connptr->sbuffer) < 0)
+				break;
+		}
+		shutdown(connptr->client_fd, SHUT_WR);
+
+		/*
+		 * Try to send any remaining data to the server if we can.
+		 */
+		socket_blocking(connptr->server_fd);
+		while (buffer_size(connptr->cbuffer) > 0) {
+			if (write_buffer(connptr->server_fd, connptr->cbuffer) < 0)
+				break;
+		}
+	} else {
+		socket_blocking(connptr->server_fd);
+		while (buffer_size(connptr->sbuffer) > 0) {
+			if (write_buffer_fd(dlfd, connptr->sbuffer) < 0)
+				break;
+		}
+		close(dlfd);
+
+		dls.ds_status = DLSTAT_COMPLETE;
+		update_status(&dls, connptr);
+
+		/* Need to scan */
+		dls.ds_status = DLSTAT_SCANNING;
+		update_status(&dls, connptr);
+		ret = scan_file(dlfn, connptr, avmsg, sizeof(avmsg));
+		if (ret < 0) {
+			dls.ds_status = DLSTAT_SCANERROR;
+			unlink(dlfn);
+		} else {
+			if (ret == 0) {
+				dls.ds_status = DLSTAT_VIRUS;
+				unlink(dlfn);
+			} else {
+				dls.ds_status = DLSTAT_SCANNED;
+			}
+		}
+		update_status(&dls, connptr);
+	}
+
+	if (dls.ds_f != NULL) {
+		fclose(dls.ds_f);
+	}
+
+	if (dls.ds_fname != NULL) {
+		free(dls.ds_fname);
+	}
+
+	if (mime != NULL) {
+		free(mime);
+	}
+
+	return;
+}
+
+
+void send_ccheck_response(struct conn_s *connptr, ccheckMsgType_t type,
+  char *error_text)
+{
+	char *headers =
+	  "Server: %s/%s\r\n"
+	  "Content-Type: text/html\r\n" \
+	  "Connection: close\r\n" \
+	"\r\n";
+	char *fallback_error =
+	  "<html><head><title>%s</title></head><body>"
+	  "<h1>%s</h1>"
+	  "The following error occured, but the proxy server was unable "
+	  "to find the error page<br/><br/>"
+	  "<b>%s</b><br/><br/>"
+	  "Please contact your administrator: <a href='mailto:%s'>%s</a>"
+	  "</body></html>";
+
+	write_message(connptr->client_fd, headers, PACKAGE, VERSION);
+	send_ccheck_response_nohead(connptr, type, error_text);
+}
+
+
+void send_ccheck_response_nohead(struct conn_s *connptr, ccheckMsgType_t type,
+  char *error_text)
+{
+	char *fallback_error =
+	  "<html><head><title>HTTP Proxy Error</title></head><body>"
+	  "<h1>Error Page Not Found</h1>"
+	  "The following error occured, but the proxy server was unable "
+	  "to find the error page (%s)<br/><br/>"
+	  "<b>%s</b><br/><br/>"
+	  "Please contact your administrator: <a href='mailto:%s'>%s</a>"
+	  "</body></html>";
+	FILE *msg_file;
+	char filename[PATH_MAX];
+	char sizeBuf[30];
+
+	switch(type) {
+	case ccheckMsgTypeErr:
+		snprintf(filename, sizeof(filename), config.ccheck_err_file, "error");
+		break;
+	case ccheckMsgTypeSize:
+		snprintf(filename, sizeof(filename), config.ccheck_err_file, "size");
+		break;
+	case ccheckMsgTypeVirus:
+		snprintf(filename, sizeof(filename), config.ccheck_err_file, "virus");
+		break;
+	default:
+		snprintf(filename, sizeof(filename), config.ccheck_err_file, "default");
+		break;
+	}
+
+	if((msg_file = fopen(filename, "r")) == NULL) {
+		write_message(connptr->client_fd, fallback_error, filename,
+		  error_text, config.admin_email, config.admin_email);
+	} else {
+		snprintf(sizeBuf, sizeof(sizeBuf), "%d", config.ccheck_max_size);
+		add_standard_vars(connptr);
+		add_error_variable(connptr, "cc_error_text", safestrdup(error_text));
+		add_error_variable(connptr, "cc_max_size", safestrdup(sizeBuf));
+		send_html_file(msg_file, connptr);
+		fclose(msg_file);
+	}
+}
+
+
+int add_exclude_mime_type(char *mime_type)
+{
+	static int count = 0;
+	char *p;
+	char temp;
+	int i;
+
+	log_message(LOG_INFO, "Adding mime type [%s] to exclude list", mime_type);
+	if((p = index(mime_type, '/')) == NULL)
+		return(-1);
+	p++;
+	config.exclude_mtypes = saferealloc(config.exclude_mtypes,
+	  sizeof(struct exclude_mtype_s *) * (count + 2));
+	config.exclude_mtypes[count] =
+	  (struct exclude_mtype_s *)safemalloc(sizeof(struct exclude_mtype_s));
+	temp = *p;
+	*p = 0;
+	config.exclude_mtypes[count]->main = safestrdup(mime_type);
+	*p = temp;
+	config.exclude_mtypes[count]->sub = *p == '*' ? NULL :
+	  safestrdup(p);
+	config.exclude_mtypes[count + 1] = NULL;
+	++count;
+	return(0);
+}
+
+
+int add_user_agent_regexp(char *subject)
+{
+	int			erroffset;
+	const char	*error;
+	static int 	count = 0;
+
+	log_message(LOG_INFO, "Adding PCRE \"%s\" to UA list", subject);
+
+	config.ua_regexp = saferealloc(config.ua_regexp,
+	  sizeof(pcre *) * (count + 2));
+
+	config.ua_regexp[count] =
+	  pcre_compile(subject, 0, &error, &erroffset, NULL);
+
+	if (config.ua_regexp[count] == NULL) {
+		log_message(LOG_WARNING,
+		  "PCRE compilation for \"%s\" failed at offset %d: %s",
+		  subject, erroffset, error);
+		return (-1);
+	}
+
+	config.ua_regexp[count + 1] = NULL;
+	++count;
+
+	return (0);
+}
+
+
+int add_exclude_url_regexp(char *subject)
+{
+	int			erroffset;
+	const char	*error;
+	static int 	count = 0;
+
+	log_message(LOG_INFO, "Adding PCRE \"%s\" to URL list", subject);
+
+	config.exclude_url_regexp = saferealloc(config.exclude_url_regexp,
+	  sizeof(pcre *) * (count + 2));
+
+	config.exclude_url_regexp[count] =
+	  pcre_compile(subject, 0, &error, &erroffset, NULL);
+
+	if (config.exclude_url_regexp[count] == NULL) {
+		log_message(LOG_WARNING,
+		  "PCRE compilation for \"%s\" failed at offset %d: %s",
+		  subject, erroffset, error);
+		return (-1);
+	}
+
+	config.exclude_url_regexp[count + 1] = NULL;
+	++count;
+
+	return (0);
+}
+
+
+#define OVECCOUNT	30
+
+int match_user_agent(struct conn_s *connptr)
+{
+	int rc;
+	int ovector[OVECCOUNT];
+	pcre **re;
+
+	if (connptr == NULL) {
+		return (0);
+	}
+
+	if (connptr->user_agent == NULL) {
+		return (0);
+	}
+
+	if ((re = config.ua_regexp) != NULL) {
+		while (*re != NULL) {
+//			log_message(LOG_INFO, "pcre_exec() for %08lx", *re);
+			rc = pcre_exec(*re, NULL, connptr->user_agent,
+			  strlen(connptr->user_agent), 0, 0, ovector, OVECCOUNT);
+			if (rc >= 0) {
+				log_message(LOG_INFO, "UA \"%s\" matched.", connptr->user_agent);
+				return (1);
+			} else {
+//				log_message(LOG_INFO, "pcre_exec() returned %d", rc);
+			}
+			++re;
+		}
+	}
+
+	return (0);
+}
+
+
+char *rebuild_uri(struct conn_s *connptr)
+{
+	char	*request_line, *p, *q, *uri, *r_uri;
+
+	if ((request_line = strdup(connptr->request_line)) == NULL) {
+		return (NULL);
+	}
+
+	if ((p = strchr(request_line, ' ')) == NULL) {
+		free(request_line);
+		return (NULL);
+	}
+
+	q = p + 1;
+	if ((p = strchr(q, ' ')) != NULL) {
+		*p = '\0';
+	}
+
+	if ((uri = strdup(q)) == NULL) {
+		free(request_line);
+		return (NULL);
+	}
+
+	free(request_line);
+
+	if (connptr->host_header == NULL) {
+		return (uri);
+	}
+
+	log_message(LOG_INFO, "URI: %s", uri);
+	// log_message(LOG_INFO, "Host: %s", connptr->host_header);
+
+	if ((p = strchr(uri, '/')) == NULL) {
+		return (uri);
+	}
+
+	p++;
+
+	if (*p != '/') {
+		return (uri);
+	}
+
+	p++;
+
+	if ((q = strchr(p, '/')) == NULL) {
+		q = p + strlen(p);
+	}
+
+	r_uri = malloc(1 + (p - uri) + strlen(connptr->host_header) + strlen(q));
+
+	if (r_uri == NULL) {
+		return (uri);
+	}
+
+	*p = '\0';
+	strcpy(r_uri, uri);
+	strcat(r_uri, connptr->host_header);
+	strcat(r_uri, q);
+	free(uri);
+
+	log_message(LOG_INFO, "Rebuilt URI: %s", r_uri);
+
+	return (r_uri);
+}
+
+
+int content_check_required(struct conn_s *connptr)
+{
+	char *header;
+	char *sub;
+	char *request_line, *uri;
+	char *p;
+	int l, sublen, rc;
+	int ovector[OVECCOUNT];
+	pcre **re;
+	struct exclude_mtype_s **type;
+
+	connptr->check_content = CONN_CCHECK_SCANONLY;
+
+	/*
+	 * First we check if the URL matches a PCRE listed in the
+	 * 'trusted' URL list (if there is one). If so, data should
+	 * be passed directly without downloading and scanning it first.
+	 */
+
+	if ((re = config.exclude_url_regexp) != NULL) {
+		if ((uri = rebuild_uri(connptr)) != NULL) {
+			while (*re != NULL) {
+//				log_message(LOG_INFO, "pcre_exec() for %08lx", *re);
+				rc = pcre_exec(*re, NULL, uri, strlen(uri), 0, 0, ovector, OVECCOUNT);
+				if (rc >= 0) {
+					connptr->check_content = CONN_CCHECK_PASSTHRU;
+					log_message(LOG_INFO, "CONN_CCHECK_PASSTHRU because URI %s matched.", uri);
+					free(request_line);
+					return (0);
+				} else {
+//					log_message(LOG_INFO, "pcre_exec() returned %d", rc);
+				}
+				++re;
+			}
+
+			free(uri);
+		}
+	}
+
+
+	/*
+	 * Check the content type header, if provided, against the list
+	 * of types (if provided) that should be passed directly (e.g.
+	 * for streaming purposes).
+	 */
+
+	if (hashmap_entry_by_key(connptr->server_headers, "Content-Type",
+	  (void **)&header) > 0) {
+	  	log_message(LOG_INFO, "Content-Type: %s", header);
+		if ((sub = index(header, '/')) != NULL) {
+			++sub;
+			if((p = index(sub, ';')) == NULL) 
+				sublen = strlen(sub);
+			else
+				sublen = p - sub;
+			if ((type = config.exclude_mtypes) != NULL) {
+				while(*type != NULL)
+				{
+//					log_message(LOG_INFO, "[%s] [%s%s]", header, (*type)->main,
+//					  (*type)->sub);
+					if(strncasecmp(header, (*type)->main, strlen((*type)->main)) == 0 &&
+					  ((*type)->sub == NULL ||
+					  strncasecmp(sub, (*type)->sub, sublen) == 0))
+					{
+						connptr->check_content = CONN_CCHECK_PASSTHRU;
+						log_message(LOG_INFO,
+						  "CONN_CCHECK_PASSTHRU because MIME %s matched.",
+						  header);
+						return(0);
+					}
+					++type;
+				}
+			}
+		}
+	}
+
+	/*
+	 * Use provided content length to determine the request's
+	 * further destiny, depending on the config options used.
+	 */
+
+	if (connptr->content_length.server < 0) {
+		log_message(LOG_INFO, "CONN_CCHECK_PASSTHRU because length missing.");
+		connptr->check_content = CONN_CCHECK_PASSTHRU;
+		return (0);
+	}
+
+	if (config.ccheck_max_size != 0) {
+		if (connptr->content_length.server > config.ccheck_max_size) {
+			if (config.ccheck_max_size_pass == 1) {
+				log_message(LOG_INFO,
+				  "CONN_CCHECK_PASSTHRU because length exceeds %d.",
+				  config.ccheck_max_size);
+				connptr->check_content = CONN_CCHECK_PASSTHRU;
+				return (0);
+			} else {
+				log_message(LOG_INFO,
+				  "CONN_CCHECK_OVERSIZE because length exceeds %d.",
+				  config.ccheck_max_size);
+				connptr->check_content = CONN_CCHECK_OVERSIZE;
+				return (0);
+			}
+
+			log_message(LOG_INFO,
+			  "CONN_CCHECK_SCANONLY because length is less than %d.",
+			  config.ccheck_max_size);
+			return (0);
+		}
+	}
+
+	if ((config.ccheck_pi_thresh == 0) ||
+	  (connptr->content_length.server <= config.ccheck_pi_thresh)) {
+		log_message(LOG_INFO,
+		  "CONN_CCHECK_SCANONLY because length less than %d.",
+	 	  config.ccheck_pi_thresh);
+		return (0);
+	}
+
+	if (connptr->user_agent) {
+		log_message(LOG_INFO, "User-Agent: \"%s\"", connptr->user_agent);
+	} else {
+		log_message(LOG_INFO, "User-Agent: (null)");
+	}
+
+	if (match_user_agent(connptr) == 0) {
+		log_message(LOG_INFO, "CONN_CCHECK_SCANONLY because no UA match.");
+		return (0);
+	}
+
+	connptr->check_content = CONN_CCHECK_REDIRECT;
+	log_message(LOG_INFO, "CONN_CCHECK_REDIRECT because length exceeds %d.",
+	  config.ccheck_pi_thresh);
+
+	return (0);
+}
+
+
+void trim_slash(char *path)
+{
+	int len;
+
+	len = strlen(path);
+	while(path[len - 1] == '/' && len > 0)
+		path[--len] = 0;
+}
+
+
+int path_inside_chroot(char *path)
+{
+	if(strncmp(path, config.chroot, strlen(config.chroot)) == 0)
+		return(1);
+	return(0);
+
+}
diff -Naur tinyproxy-1.6.2-orig/src/virus.h tinyproxy-1.6.2/src/virus.h
--- tinyproxy-1.6.2-orig/src/virus.h	1970-01-01 01:00:00.000000000 +0100
+++ tinyproxy-1.6.2/src/virus.h	2009-08-28 10:48:00.000000000 +0200
@@ -0,0 +1,19 @@
+#include "conns.h"
+
+typedef enum {
+	ccheckMsgTypeErr,
+	ccheckMsgTypeSize,
+	ccheckMsgTypeVirus
+} ccheckMsgType_t;
+
+
+void send_ccheck_response(struct conn_s *connptr, ccheckMsgType_t type,
+  char *error_text);
+void send_ccheck_response_nohead(struct conn_s *connptr, ccheckMsgType_t type,
+  char *error_text);
+void send_ccheck_redirect(struct conn_s *connptr);
+int scan_file(char *filename, struct conn_s *connptr, char *msg, int msg_size);
+int add_exclude_mime_type(char *mime_type);
+int content_check_required(struct conn_s *connptr);
+void trim_slash(char *path);
+int path_inside_chroot(char *path);
diff -Naur tinyproxy-1.6.2-orig/utm_err_pages/err_foot.html tinyproxy-1.6.2/utm_err_pages/err_foot.html
--- tinyproxy-1.6.2-orig/utm_err_pages/err_foot.html	1970-01-01 01:00:00.000000000 +0100
+++ tinyproxy-1.6.2/utm_err_pages/err_foot.html	2009-08-28 10:48:00.000000000 +0200
@@ -0,0 +1,15 @@
+</div>
+</tr></td>
+</tbody>
+</table>
+</td></tr>
+<tr><td><!-- fill --></tr></td>
+<tr><td id="footCell"><div id="foot"></div></td></tr>
+</tbody>
+</table>
+<div id="debug">Debug-Output:<br/></div>
+</body>
+</html>
+<!--
+vim:ts=4:sw=4
+-->
diff -Naur tinyproxy-1.6.2-orig/utm_err_pages/err_head.html tinyproxy-1.6.2/utm_err_pages/err_head.html
--- tinyproxy-1.6.2-orig/utm_err_pages/err_head.html	1970-01-01 01:00:00.000000000 +0100
+++ tinyproxy-1.6.2/utm_err_pages/err_head.html	2009-08-28 10:48:00.000000000 +0200
@@ -0,0 +1,160 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns='http://www.w3.org/1999/xhtml'>
+<head>
+<style type="text/css">
+<!--
+html {
+	height: 100%;
+}
+
+body, td {
+	font-size: 12px;
+	font-family: sans-serif;
+}
+
+body {
+	padding: 0px 0px 0px 0px;
+	margin: 0px 0px 0px 0px;
+	width: 100%;
+	height: 100%;
+}
+
+#pageLayout {
+	width: 800px;
+	height: 100%;
+	border-spacing: 0px;
+}
+
+#footCell {
+	vertical-align: bottom;
+}
+
+#foot {
+	background-color:#9EB9CE;
+	border-bottom:2px solid #000000;
+	border-top:2px solid #000000;
+	height:20px;
+}
+
+
+#infoBoxCell {
+	padding-top: 50px;
+	vertical-align: top;
+}
+
+#pageHead {
+	width: 100%;
+	height: 60px;
+	background: transparent url(/squid-internal-static/icons/fec-utm-bg1.jpg) repeat scroll 0 0;
+	border-spacing: 0px;
+}
+
+#pageHeadCell {
+	vertical-align: top;
+}
+
+#productCell {
+	vertical-align: middle;
+	padding-left: 15px;
+	color: #ffffff;
+	font-size: 16px;
+	font-weight: bold;
+}
+
+#logoCell {
+	text-align: right;
+	vertical-align: middle;
+	padding-right: 15px;
+}
+
+#infoBox {
+	border: 2px #cc3333 solid;
+	width: 600px;
+	/* border-collapse: collapse; */
+	margin-left: auto;
+	margin-right: auto;
+	background-color: #e0e0e0;
+}
+
+#errorHead {
+	color: #cc3333;
+	font-weight: bold;
+	font-size: 14px;
+	padding: 4px;
+}
+
+#errorDetail {
+	border: 2px #e0e0e0 inset;
+	font-size: 12px;
+	padding: 4px;
+	margin: 4px;
+}
+
+.de {
+	display: none;
+}
+
+h2 {
+	font-size: 14px;
+	padding: 0px;
+	margin: 5px 0px 5px 0px;
+}
+-->
+</style>
+
+<script type="text/javascript">
+
+function start() {
+	var lang = "en";
+	var language;
+	if(navigator.appName == 'Netscape')
+        language = navigator.language;
+    else
+        language = navigator.browserLanguage;
+    if(language.indexOf("de") > -1)
+        lang = "de";
+	showLang(document, lang);
+}
+
+function showLang(ele, lang) {
+	for(var i = 0; i < ele.childNodes.length; i++) {
+		var c = ele.childNodes[i];
+		if(c.nodeType == 1) {
+			if(typeof(c.className) == "string") {
+				if(c.className == "en") {
+					c.style.display= "none";
+				}
+				if(c.className == lang) {
+					c.style.display = "block";
+				}
+			}
+			showLang(ele.childNodes[i], lang);
+		}
+	}
+}
+
+</script>
+
+<title>HTTP Proxy Error</title>
+</head>
+<body onload="start();">
+<table id="pageLayout">
+<tbody>
+<tr><td id="pageHeadCell">
+	<table id="pageHead">
+	<tr>
+		<td id='productCell'>packetalarm UTM</td>
+		<td id='logoCell'><img src='/squid-internal-static/icons/fec-utm-logo1.gif'/></td>
+	</tr>
+	</table>
+</tr></td>
+<tr><td id="infoBoxCell">
+<table id="infoBox">
+<tbody>
+<tr><td>
+<div id="errorHead">
+<div class="en">HTTP Proxy Error</div>
+<div class="de">HTTP Proxy Fehler</div>
+</div>
+<div id="errorDetail">
diff -Naur tinyproxy-1.6.2-orig/utm_err_pages/install.sh tinyproxy-1.6.2/utm_err_pages/install.sh
--- tinyproxy-1.6.2-orig/utm_err_pages/install.sh	1970-01-01 01:00:00.000000000 +0100
+++ tinyproxy-1.6.2/utm_err_pages/install.sh	2009-08-28 10:48:00.000000000 +0200
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+set -e
+
+LIBDIR=$1
+if [ -z "$LIBDIR" ]; then
+	echo -e "Usage: $(basename $0) <tinyproxy-lib-dir>\n"
+	exit 1
+fi
+cd $(dirname $0)
+mkdir -p ${LIBDIR}
+TMPHEAD=$(tempfile)
+sed s/{/{{/ err_head.html > ${TMPHEAD}
+for I in $(ls pages_in/*); do
+	DEST_FILE=${LIBDIR}/$(basename $I)
+	cat ${TMPHEAD} $I err_foot.html > ${DEST_FILE}
+done
+rm ${TMPHEAD}
diff -Naur tinyproxy-1.6.2-orig/utm_err_pages/pages_in/ccheck_default.html tinyproxy-1.6.2/utm_err_pages/pages_in/ccheck_default.html
--- tinyproxy-1.6.2-orig/utm_err_pages/pages_in/ccheck_default.html	1970-01-01 01:00:00.000000000 +0100
+++ tinyproxy-1.6.2/utm_err_pages/pages_in/ccheck_default.html	2009-08-28 10:48:00.000000000 +0200
@@ -0,0 +1,22 @@
+<div class="en">
+<h2>The requested URL could not be retrieved</h2>
+<hr noshade size="1px"/>
+<p>While trying to retrieve the URL: <a href='{url}'>{url}</a></p>
+<p>The following error was encountered:</p>
+<ul>
+<li><strong>Unknown Error</strong></li>
+</ul>
+<p>{cc_error_text}</p>
+<p>{add_error}</p>
+</div>
+<div class="de">
+<h2>Die angeforderte URL konnte nicht geladen werden</h2>
+<hr noshade size="1px"/>
+<p>Beim Laden der URL: <a href='{url}'>{url}</a></p>
+<p>Trat folgender Fehler auf:</p>
+<ul>
+<li><strong>Unbekannter Fehler</strong></li>
+</ul>
+<p>{cc_error_text}</p>
+<p>{add_error}</p>
+</div>
diff -Naur tinyproxy-1.6.2-orig/utm_err_pages/pages_in/ccheck_error.html tinyproxy-1.6.2/utm_err_pages/pages_in/ccheck_error.html
--- tinyproxy-1.6.2-orig/utm_err_pages/pages_in/ccheck_error.html	1970-01-01 01:00:00.000000000 +0100
+++ tinyproxy-1.6.2/utm_err_pages/pages_in/ccheck_error.html	2009-08-28 10:48:00.000000000 +0200
@@ -0,0 +1,28 @@
+<div class="en">
+<h2>The requested URL could not be retrieved</h2>
+<hr noshade size="1px"/>
+<p>While trying to retrieve the URL: <a href='{url}'>{url}</a></p>
+<p>The following error was encountered:</p>
+<ul>
+<li><strong>Internal Virus Check Error</strong></li>
+</ul>
+<p>An internal error occured while checking the file for viruses. The
+following error was detected: {cc_error_text}</p>
+<p>Please try again. If the error persists, please contact your local
+IT helpdesk.</p>
+<p>{add_error}</p>
+</div>
+<div class="de">
+<h2>Die angeforderte URL konnte nicht geladen werden</h2>
+<hr noshade size="1px"/>
+<p>Beim Laden der URL: <a href='{url}'>{url}</a></p>
+<p>Trat folgender Fehler auf:</p>
+<ul>
+<li><strong>Interner Fehler bei Virus-Pr&uuml;fung</strong></li>
+</ul>
+<p>Bei der Suche nach Viren in der Datei trat ein interner Fehler auf.
+Folgender Fehler wurde erkannt: {cc_error_text}</p>
+<p>Bitte wiederholen Sie Ihre Anfrage. Sollte das Problem weiterhin
+bestehen, wenden Sie sich bitte an Ihre lokale IT Benutzerbetreuung</p>
+<p>{add_error}</p>
+</div>
diff -Naur tinyproxy-1.6.2-orig/utm_err_pages/pages_in/ccheck_size.html tinyproxy-1.6.2/utm_err_pages/pages_in/ccheck_size.html
--- tinyproxy-1.6.2-orig/utm_err_pages/pages_in/ccheck_size.html	1970-01-01 01:00:00.000000000 +0100
+++ tinyproxy-1.6.2/utm_err_pages/pages_in/ccheck_size.html	2009-08-28 10:48:00.000000000 +0200
@@ -0,0 +1,26 @@
+<div class="en">
+<h2>The requested URL could not be retrieved</h2>
+<hr noshade size="1px"/>
+<p>While trying to retrieve the URL: <a href='{url}'>{url}</a></p>
+<p>The following error was encountered:</p>
+<ul>
+<li><strong>Filesize exceeded</strong></li>
+</ul>
+<p>The filesize exceeded a limit of {cc_max_size} bytes and could
+not be checked for viruses. The limit was configured by the administrator
+of the proxy server.</p>
+<p>{add_error}</p>
+</div>
+<div class="de">
+<h2>Die angeforderte URL konnte nicht geladen werden</h2>
+<hr noshade size="1px"/>
+<p>Beim Laden der URL: <a href='{url}'>{url}</a></p>
+<p>Trat folgender Fehler auf:</p>
+<ul>
+<li><strong>Dateigr&ouml;&szlig;e &uuml;berschritten</strong></li>
+</ul>
+<p>Die Dateigr&ouml;&szlig;e &uuml;berschritt ein Limit von {cc_max_size} Bytes
+und konnte nicht auf Viren untersucht werden. Die Grenze wurde vom
+Administrator des Proxy-Servers konfiguriert.</p>
+<p>{add_error}</p>
+</div>
diff -Naur tinyproxy-1.6.2-orig/utm_err_pages/pages_in/ccheck_virus.html tinyproxy-1.6.2/utm_err_pages/pages_in/ccheck_virus.html
--- tinyproxy-1.6.2-orig/utm_err_pages/pages_in/ccheck_virus.html	1970-01-01 01:00:00.000000000 +0100
+++ tinyproxy-1.6.2/utm_err_pages/pages_in/ccheck_virus.html	2009-08-28 10:48:00.000000000 +0200
@@ -0,0 +1,22 @@
+<div class="en">
+<h2>The requested URL could not be retrieved</h2>
+<hr noshade size="1px"/>
+<p>While trying to retrieve the URL: <a href='{url}'>{url}</a></p>
+<p>The following error was encountered:</p>
+<ul>
+<li><strong>Virus Found</strong></li>
+</ul>
+<p>The file contains the following virus: {cc_error_text}</p>
+<p>{add_error}</p>
+</div>
+<div class="de">
+<h2>Die angeforderte URL konnte nicht geladen werden</h2>
+<hr noshade size="1px"/>
+<p>Beim Laden der URL: <a href='{url}'>{url}</a></p>
+<p>Trat folgender Fehler auf:</p>
+<ul>
+<li><strong>Virus gefunden</strong></li>
+</ul>
+<p>Die Datei enth&auml;lt folgenden Virus: {cc_error_text}</p>
+<p>{add_error}</p>
+</div>
diff -Naur tinyproxy-1.6.2-orig/utm_err_pages/pages_in/default.html tinyproxy-1.6.2/utm_err_pages/pages_in/default.html
--- tinyproxy-1.6.2-orig/utm_err_pages/pages_in/default.html	1970-01-01 01:00:00.000000000 +0100
+++ tinyproxy-1.6.2/utm_err_pages/pages_in/default.html	2009-08-28 10:48:00.000000000 +0200
@@ -0,0 +1,22 @@
+<div class="en">
+<h2>The requested URL could not be retrieved</h2>
+<hr noshade size="1px"/>
+<p>While trying to retrieve the URL: <a href='{url}'>{url}</a></p>
+<p>The following error was encountered:</p>
+<ul>
+<li><strong>{cause}</strong></li>
+</ul>
+<p>{detail}</p>
+<p>{add_error}</p>
+</div>
+<div class="de">
+<h2>Die angeforderte URL konnte nicht geladen werden</h2>
+<hr noshade size="1px"/>
+<p>Beim Laden der URL: <a href='{url}'>{url}</a></p>
+<p>Trat folgender Fehler auf:</p>
+<ul>
+<li><strong>{cause}</strong></li>
+</ul>
+<p>{detail}</p>
+<p>{add_error}</p>
+</div>
diff -Naur tinyproxy-1.6.2-orig/utm_err_pages/pages_in/err_400.html tinyproxy-1.6.2/utm_err_pages/pages_in/err_400.html
--- tinyproxy-1.6.2-orig/utm_err_pages/pages_in/err_400.html	1970-01-01 01:00:00.000000000 +0100
+++ tinyproxy-1.6.2/utm_err_pages/pages_in/err_400.html	2009-08-28 10:48:00.000000000 +0200
@@ -0,0 +1,28 @@
+<div class="en">
+<h2>The requested URL could not be retrieved</h2>
+<hr noshade size="1px"/>
+<p>While trying to retrieve the URL: <a href='{url}'>{url}</a></p>
+<p>The following error was encountered:</p>
+<ul>
+<li><strong>Bad Request</strong></li>
+</ul>
+<p>
+The proxy server received an invalid request from the client {clientip}.
+{detail}
+</p>
+<p>{add_error}</p>
+</div>
+<div class="de">
+<h2>Die angeforderte URL konnte nicht geladen werden</h2>
+<hr noshade size="1px"/>
+<p>Beim Laden der URL: <a href='{url}'>{url}</a></p>
+<p>Trat folgender Fehler auf:</p>
+<ul>
+<li><strong>Ung&uuml;ltige Anfrage</strong></li>
+</ul>
+<p>
+Der Proxy-Server hat eine ung&uuml;ltige Anfrage vom Client {clientip}
+empfangen. {detail}
+</p>
+<p>{add_error}</p>
+</div>
diff -Naur tinyproxy-1.6.2-orig/utm_err_pages/pages_in/err_404.html tinyproxy-1.6.2/utm_err_pages/pages_in/err_404.html
--- tinyproxy-1.6.2-orig/utm_err_pages/pages_in/err_404.html	1970-01-01 01:00:00.000000000 +0100
+++ tinyproxy-1.6.2/utm_err_pages/pages_in/err_404.html	2009-08-28 10:48:00.000000000 +0200
@@ -0,0 +1,30 @@
+<div class="en">
+<h2>The requested URL could not be retrieved</h2>
+<hr noshade size="1px"/>
+<p>While trying to retrieve the URL: <a href='{url}'>{url}</a></p>
+<p>The following error was encountered:</p>
+<ul>
+<li><strong>Unable to connect to upstream proxy</strong></li>
+</ul>
+<p>
+The proxy server failed to connect to the upstream proxy. Please try again
+later. If the problem persists, please contact your local IT helpdesk.
+</p>
+<p>{add_error}</p>
+</div>
+<div class="de">
+<h2>Die angeforderte URL konnte nicht geladen werden</h2>
+<hr noshade size="1px"/>
+<p>Beim Laden der URL: <a href='{url}'>{url}</a></p>
+<p>Trat folgender Fehler auf:</p>
+<ul>
+<li><strong>Die Verbindung zum &uuml;bergeordneten Proxy-Server
+ist fehlgeschlagen.</strong></li>
+</ul>
+<p>
+Der Proxy-Server konnte keine Verbindung zum &uuml;bergeordneten Proxy-Server
+aufbauen. Bitte wiederholen Sie Ihre Anfrage. Sollte das Problem weiteherhin
+bestehen, wenden Sie sich bitte an Ihre lokale IT Benutzerbetreuung.
+</p>
+<p>{add_error}</p>
+</div>
diff -Naur tinyproxy-1.6.2-orig/utm_err_pages/pages_in/err_408.html tinyproxy-1.6.2/utm_err_pages/pages_in/err_408.html
--- tinyproxy-1.6.2-orig/utm_err_pages/pages_in/err_408.html	1970-01-01 01:00:00.000000000 +0100
+++ tinyproxy-1.6.2/utm_err_pages/pages_in/err_408.html	2009-08-28 10:48:00.000000000 +0200
@@ -0,0 +1,28 @@
+<div class="en">
+<h2>The requested URL could not be retrieved</h2>
+<hr noshade size="1px"/>
+<p>While trying to retrieve the URL: <a href='{url}'>{url}</a></p>
+<p>The following error was encountered:</p>
+<ul>
+<li><strong>Timeout</strong></li>
+</ul>
+<p>
+A timeout occurred while connecting to the remote web server.
+Please try again later.
+</p>
+<p>{add_error}</p>
+</div>
+<div class="de">
+<h2>Die angeforderte URL konnte nicht geladen werden</h2>
+<hr noshade size="1px"/>
+<p>Beim Laden der URL: <a href='{url}'>{url}</a></p>
+<p>Trat folgender Fehler auf:</p>
+<ul>
+<li><strong>Zeit&uuml;berschreitung</strong></li>
+</ul>
+<p>
+Bei der Verbindung mit dem Web-Server trat eine Zeit&uuml;berschreitung auf.
+Bitte wiederholen Sie Ihre Anfrage sp&auml;ter.
+</p>
+<p>{add_error}</p>
+</div>
diff -Naur tinyproxy-1.6.2-orig/utm_err_pages/pages_in/err_500.html tinyproxy-1.6.2/utm_err_pages/pages_in/err_500.html
--- tinyproxy-1.6.2-orig/utm_err_pages/pages_in/err_500.html	1970-01-01 01:00:00.000000000 +0100
+++ tinyproxy-1.6.2/utm_err_pages/pages_in/err_500.html	2009-08-28 10:48:00.000000000 +0200
@@ -0,0 +1,28 @@
+<div class="en">
+<h2>The requested URL could not be retrieved</h2>
+<hr noshade size="1px"/>
+<p>While trying to retrieve the URL: <a href='{url}'>{url}</a></p>
+<p>The following error was encountered:</p>
+<ul>
+<li><strong>Unable to connect</strong></li>
+</ul>
+<p>
+The proxy server was unable to connect to the remote web server.
+Please try again later.
+</p>
+<p>{add_error}</p>
+</div>
+<div class="de">
+<h2>Die angeforderte URL konnte nicht geladen werden</h2>
+<hr noshade size="1px"/>
+<p>Beim Laden der URL: <a href='{url}'>{url}</a></p>
+<p>Trat folgender Fehler auf:</p>
+<ul>
+<li><strong>Die Verbindung ist fehlgeschlagen</strong></li>
+</ul>
+<p>
+Der Proxy-Server konnte keine Verbindung zum Web-Server aufbauen.
+Bitte wiederholen Sie Ihre Anfrage.
+</p>
+<p>{add_error}</p>
+</div>
diff -Naur tinyproxy-1.6.2-orig/utm_err_pages/pages_in/err_503.html tinyproxy-1.6.2/utm_err_pages/pages_in/err_503.html
--- tinyproxy-1.6.2-orig/utm_err_pages/pages_in/err_503.html	1970-01-01 01:00:00.000000000 +0100
+++ tinyproxy-1.6.2/utm_err_pages/pages_in/err_503.html	2009-08-28 10:48:00.000000000 +0200
@@ -0,0 +1,29 @@
+<div class="en">
+<h2>The requested URL could not be retrieved</h2>
+<hr noshade size="1px"/>
+<p>While trying to retrieve the URL: <a href='{url}'>{url}</a></p>
+<p>The following error was encountered:</p>
+<ul>
+<li><strong>Internal error</strong></li>
+</ul>
+<p>
+An internal server error occurred while processing your request. Please try
+again. If the problem persists, please contact your local IT helpdesk.
+</p>
+<p>{add_error}</p>
+</div>
+<div class="de">
+<h2>Die angeforderte URL konnte nicht geladen werden</h2>
+<hr noshade size="1px"/>
+<p>Beim Laden der URL: <a href='{url}'>{url}</a></p>
+<p>Trat folgender Fehler auf:</p>
+<ul>
+<li><strong>Interner Fehler</strong></li>
+</ul>
+<p>
+Bei der Bearbeitung Ihrer Anfrage trat ein interner Fehler auf. Bitte
+wiederholen Sie Ihre Anfrage. Sollte das Problem weiteherhin
+bestehen, wenden Sie sich bitte an Ihre lokale IT Benutzerbetreuung.
+</p>
+<p>{add_error}</p>
+</div>

