[syslog-ng]template() and template_escape() extension for all destination drivers

Achim Gsell a@tac.ch
Thu, 12 Sep 2002 11:29:11 +0200


--------------Boundary-00=_NOJBWJVQIWAAK32WEVZY
Content-Type: text/plain;
  charset="us-ascii"
Content-Transfer-Encoding: quoted-printable

Hi,

We need the "template()" and "template_escape()" options in all destinati=
on=20
drivers, not only in the "file" driver. The attached patch adds these opt=
ions=20
to all other destination drivers in syslog-ng 1.5.20. We test the patch o=
n=20
Linux 2.2.20 and Solaris 8.

Is there a reason to have these options available only in the "file"=20
destination driver?

Achim

--------------Boundary-00=_NOJBWJVQIWAAK32WEVZY
Content-Type: text/x-diff;
  charset="us-ascii";
  name="syslog-ng-1.5.20.template.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="syslog-ng-1.5.20.template.diff"

diff -ur syslog-ng-1.5.20/src/afinet.c syslog-ng-1.5.20.1/src/afinet.c
--- syslog-ng-1.5.20/src/afinet.c	Wed Aug 21 16:03:50 2002
+++ syslog-ng-1.5.20.1/src/afinet.c	Thu Sep 12 11:00:31 2002
@@ -40,6 +40,9 @@
 
 #include "afinet.c.x"
 
+extern struct ol_string *
+expand_macros(struct syslog_config *cfg, struct ol_string *template, int template_escape, struct log_info *msg);
+
 void inet_address_setip(struct address_info **a, const char *ip)
 {
 	CAST(inet_address_info, addr, *a);
@@ -386,6 +389,9 @@
        (dest_buf object abstract_buffer)
        (sync_freq simple UINT32)
        (conn_fd object connect_fd)
+       (template_fname string)
+       (template_output string)
+       (template_escape . int)
        (cfg object syslog_config)))
 */
 /* af_inet destination */
@@ -422,6 +428,20 @@
 	inet_address_setport(&dest->bind_addr, port, service, proto);
 }
 
+void afinet_dest_set_template(struct log_dest_driver *c, char *t)
+{
+	CAST(afinet_dest, self, c);
+ 
+	self->template_output = c_format("%z", t);
+}
+
+void afinet_dest_set_template_escape(struct log_dest_driver *c, int enable)
+{
+	CAST(afinet_dest, self, c);
+
+	self->template_escape = enable;
+}
+
 void afinet_dest_set_destport(struct log_dest_driver *c, UINT32 port, 
 			      const char *service, const char *proto)
 {
@@ -527,7 +547,14 @@
 	CAST(afinet_dest, self, c);
 
 	if (self->dest_buf) {
-		A_WRITE_STRING(&self->dest_buf->super, c_format("<%i>%S %S %S\n", msg->pri, msg->date, msg->host, msg->msg));
+		if (self->template_output)
+			A_WRITE_STRING(&self->dest_buf->super,
+				       c_format("<%i>%S\n",
+						msg->pri, expand_macros(self->cfg, self->template_output, self->template_escape, msg)));
+		else
+                	A_WRITE_STRING(&self->dest_buf->super,
+				       c_format("<%i>%S %S %S\n", msg->pri, msg->date, msg->host, msg->msg));
+
 	}
 	log_info_free(msg);
 }
diff -ur syslog-ng-1.5.20/src/afinet.c.x syslog-ng-1.5.20.1/src/afinet.c.x
--- syslog-ng-1.5.20/src/afinet.c.x	Wed Aug 21 16:04:22 2002
+++ syslog-ng-1.5.20.1/src/afinet.c.x	Wed Sep 11 17:36:28 2002
@@ -33,6 +33,9 @@
   struct abstract_buffer *dest_buf;
   UINT32 sync_freq;
   struct connect_fd *conn_fd;
+  struct ol_string *template_fname;
+  struct ol_string *template_output;
+  int template_escape;
   struct syslog_config *cfg;
 };
 extern struct ol_class afinet_dest_class;
@@ -49,11 +52,18 @@
   mark((struct ol_object *) i->cfg);
 }
 
+static void do_afinet_dest_free(struct ol_object *o)
+{
+  struct afinet_dest *i = (struct afinet_dest *) o;
+  ol_string_free(i->template_fname);
+  ol_string_free(i->template_output);
+}
+
 struct ol_class afinet_dest_class =
 { STATIC_HEADER,
   &afsocket_dest_class, "afinet_dest", sizeof(struct afinet_dest),
   do_afinet_dest_mark,
-  NULL
+  do_afinet_dest_free
 };
 #endif /* !CLASS_DECLARE */
 
diff -ur syslog-ng-1.5.20/src/afinter.c syslog-ng-1.5.20.1/src/afinter.c
--- syslog-ng-1.5.20/src/afinter.c	Fri Apr 26 11:43:54 2002
+++ syslog-ng-1.5.20.1/src/afinter.c	Fri Aug 30 11:26:56 2002
@@ -82,6 +82,9 @@
 {
 	CAST(log_source_driver, self, c);
 	cfg->internal = self->super.next;
+	if (assigned_configuration == NULL) {
+		assigned_configuration = cfg;
+	}
 	return ST_OK | ST_GOON;
 }
 
diff -ur syslog-ng-1.5.20/src/afprogram.c syslog-ng-1.5.20.1/src/afprogram.c
--- syslog-ng-1.5.20/src/afprogram.c	Sun Jul  8 19:04:21 2001
+++ syslog-ng-1.5.20.1/src/afprogram.c	Thu Sep  5 16:15:05 2002
@@ -38,13 +38,20 @@
 
 #include "afprogram.c.x"
 
+extern struct ol_string *
+expand_macros(struct syslog_config *cfg, struct ol_string *template, int template_escape, struct log_info *msg);
+
 /* CLASS:
    (class
      (name afprogram_dest)
      (super log_dest_driver)
      (vars
        (progname string)
-       (dest object io_fd)))
+       (dest object io_fd)
+       (template_fname string)
+       (template_output string)
+       (template_escape . int)
+       (cfg object syslog_config)))
 */
 
 /* CLASS:
@@ -55,6 +62,22 @@
        (pid simple pid_t)
        (dest object io_fd)))
 */
+void
+afprogram_dest_set_template(struct log_dest_driver *c, char *t)
+{
+	CAST(afprogram_dest, self, c);
+ 
+	self->template_output = c_format("%z", t);
+}
+
+void
+afprogram_dest_set_template_escape(struct log_dest_driver *c, int enable)
+{
+	CAST(afprogram_dest, self, c);
+
+	self->template_escape = enable;
+}
+
 
 static void do_kill_child(struct resource *c)
 {
@@ -94,6 +117,7 @@
 	}
 	else {
 		NEW(afprogram_child, prg);
+		self->cfg = cfg;
 
 		prg->super.kill = do_kill_child;
 		prg->pid = pid;
@@ -109,18 +133,26 @@
 	return ST_OK | ST_GOON;
 }
 
+
+
 static void do_handle_afprogram_dest(struct log_handler *c, 
 				     struct log_info *msg)
 {
         CAST(afprogram_dest, self, c);
 
-        if (self->dest)
-                A_WRITE_STRING(&self->dest->buffer->super, 
-			       c_format("<%i>%S %S %S\n", 
-					msg->pri, 
-					msg->date, 
-					msg->host, 
-					msg->msg));
+        if (self->dest) {
+		struct ol_string *msg_line;
+
+		if (self->template_output) {
+			msg_line = c_format("<%i>%S\n", msg->pri,
+					    expand_macros(self->cfg, self->template_output, self->template_escape, msg));
+		} else {
+			msg_line = c_format("<%i>%S %S %S\n", msg->pri,
+					    msg->date, msg->host, msg->msg);
+		}
+
+                A_WRITE_STRING(&self->dest->buffer->super, msg_line );
+	}
         log_info_free(msg);
 }
 
diff -ur syslog-ng-1.5.20/src/afprogram.c.x syslog-ng-1.5.20.1/src/afprogram.c.x
--- syslog-ng-1.5.20/src/afprogram.c.x	Sun Jul  8 19:09:41 2001
+++ syslog-ng-1.5.20.1/src/afprogram.c.x	Thu Sep  5 16:15:06 2002
@@ -4,6 +4,10 @@
   struct log_dest_driver super;
   struct ol_string *progname;
   struct io_fd *dest;
+  struct ol_string *template_fname;
+  struct ol_string *template_output;
+  int template_escape;
+  struct syslog_config *cfg;
 };
 extern struct ol_class afprogram_dest_class;
 #endif /* !CLASS_DEFINE */
@@ -14,12 +18,15 @@
 {
   struct afprogram_dest *i = (struct afprogram_dest *) o;
   mark((struct ol_object *) i->dest);
+  mark((struct ol_object *) i->cfg);
 }
 
 static void do_afprogram_dest_free(struct ol_object *o)
 {
   struct afprogram_dest *i = (struct afprogram_dest *) o;
   ol_string_free(i->progname);
+  ol_string_free(i->template_fname);
+  ol_string_free(i->template_output);
 }
 
 struct ol_class afprogram_dest_class =
diff -ur syslog-ng-1.5.20/src/afprogram.h syslog-ng-1.5.20.1/src/afprogram.h
--- syslog-ng-1.5.20/src/afprogram.h	Sun Feb 25 13:00:22 2001
+++ syslog-ng-1.5.20.1/src/afprogram.h	Thu Sep  5 15:54:11 2002
@@ -29,5 +29,7 @@
 #include "syslog-ng.h"
 
 struct log_dest_driver *make_afprogram_dest(const char *cmd);
+void afprogram_dest_set_template(struct log_dest_driver *c, char *t);
+void afprogram_dest_set_template_escape(struct log_dest_driver *c, int enable);
 
 #endif
diff -ur syslog-ng-1.5.20/src/afsocket.h syslog-ng-1.5.20.1/src/afsocket.h
--- syslog-ng-1.5.20/src/afsocket.h	Sat Apr 14 11:10:34 2001
+++ syslog-ng-1.5.20.1/src/afsocket.h	Thu Sep  5 14:10:45 2002
@@ -138,12 +138,16 @@
 void afinet_dest_set_mac(struct log_dest_driver *c, UINT32 value);
 void afinet_dest_set_encrypt(struct log_dest_driver *c, UINT32 value);
 void afinet_dest_set_syncfreq(struct log_dest_driver *c, UINT32 value);
+void afinet_dest_set_template(struct log_dest_driver *c, char *t);
+void afinet_dest_set_template_escape(struct log_dest_driver *c, int enable);
 
 struct log_source_driver *
 make_afunix_source(struct address_info *bind_addr, UINT32 flags);
 
 struct log_dest_driver *
 make_afunix_dest(struct address_info *dest_addr, UINT32 flags);
+void afunix_dest_set_template(struct log_dest_driver *c, char *t);
+void afunix_dest_set_template_escape(struct log_dest_driver *c, int enable);
 
 struct log_source_driver *
 make_afinet_source(struct address_info *bind_addr, UINT32 flags);
diff -ur syslog-ng-1.5.20/src/afunix.c syslog-ng-1.5.20.1/src/afunix.c
--- syslog-ng-1.5.20/src/afunix.c	Wed Aug 21 16:03:50 2002
+++ syslog-ng-1.5.20.1/src/afunix.c	Thu Sep 12 11:01:00 2002
@@ -41,6 +41,9 @@
 
 #include "afunix.c.x"
 
+extern struct ol_string *
+expand_macros(struct syslog_config *cfg, struct ol_string *template, int template_escape, struct log_info *msg);
+
 /* af_unix source connection */
 
 static int
@@ -316,16 +319,50 @@
      (vars
        (dest object io_fd)
        (dest_buf object abstract_buffer)
+       (template_fname string)
+       (template_output string)
+       (template_escape . int)
        (cfg object syslog_config)))
 */
 
-void do_handle_afunix_dest(struct log_handler *c, struct log_info *msg)
+void
+afunix_dest_set_template(struct log_dest_driver *c, char *t)
+{
+	CAST(afunix_dest, self, c);
+ 
+	self->template_output = c_format("%z", t);
+}
+
+void
+afunix_dest_set_template_escape(struct log_dest_driver *c, int enable)
+{
+	CAST(afunix_dest, self, c);
+
+	self->template_escape = enable;
+}
+
+void
+do_handle_afunix_dest(struct log_handler *c, struct log_info *msg)
 {
 	CAST(afunix_dest, self, c);
 
 	if (self->dest_buf) {
-		A_WRITE_STRING(&self->dest_buf->super, c_format("<%i>%S %S%c", msg->pri, msg->date, msg->msg, 0));
+		if (self->template_output)
+			A_WRITE_STRING(&self->dest_buf->super,
+				       c_format("<%i>%S\n",
+						msg->pri,
+						expand_macros(
+							      self->cfg,
+							      self->template_output,
+							      self->template_escape, msg)));
+		else
+                	A_WRITE_STRING(&self->dest_buf->super,
+				       c_format("<%i>%S %S %S\n",
+						msg->pri,
+						msg->date,
+						msg->host, msg->msg));
 	}
+
 	log_info_free(msg);
 }
 
diff -ur syslog-ng-1.5.20/src/afunix.c.x syslog-ng-1.5.20.1/src/afunix.c.x
--- syslog-ng-1.5.20/src/afunix.c.x	Wed Aug 21 16:04:21 2002
+++ syslog-ng-1.5.20.1/src/afunix.c.x	Wed Sep 11 17:36:27 2002
@@ -34,6 +34,9 @@
   struct afsocket_dest super;
   struct io_fd *dest;
   struct abstract_buffer *dest_buf;
+  struct ol_string *template_fname;
+  struct ol_string *template_output;
+  int template_escape;
   struct syslog_config *cfg;
 };
 extern struct ol_class afunix_dest_class;
@@ -49,11 +52,18 @@
   mark((struct ol_object *) i->cfg);
 }
 
+static void do_afunix_dest_free(struct ol_object *o)
+{
+  struct afunix_dest *i = (struct afunix_dest *) o;
+  ol_string_free(i->template_fname);
+  ol_string_free(i->template_output);
+}
+
 struct ol_class afunix_dest_class =
 { STATIC_HEADER,
   &afsocket_dest_class, "afunix_dest", sizeof(struct afunix_dest),
   do_afunix_dest_mark,
-  NULL
+  do_afunix_dest_free
 };
 #endif /* !CLASS_DECLARE */
 
diff -ur syslog-ng-1.5.20/src/afuser.c syslog-ng-1.5.20.1/src/afuser.c
--- syslog-ng-1.5.20/src/afuser.c	Sun Jul  8 18:07:27 2001
+++ syslog-ng-1.5.20.1/src/afuser.c	Fri Sep  6 14:31:54 2002
@@ -37,19 +37,46 @@
 
 #include "afuser.c.x"
 
+extern struct ol_string *
+expand_macros(struct syslog_config *cfg, struct ol_string *template, int template_escape, struct log_info *msg);
+
 /* CLASS:
    (class
      (name afuser_dest)
      (super log_dest_driver)
      (vars
-       (username string)))
+       (username string)
+       (template_fname string)
+       (template_output string)
+       (template_escape . int)
+       (cfg object syslog_config)))
 */
 
+void
+afuser_dest_set_template(struct log_dest_driver *c, char *t)
+{
+	CAST(afuser_dest, self, c);
+ 
+	self->template_output = c_format("%z", t);
+}
+
+void
+afuser_dest_set_template_escape(struct log_dest_driver *c, int enable)
+{
+	CAST(afuser_dest, self, c);
+
+	self->template_escape = enable;
+}
+
 static int 
 do_init_afuser_dest(struct log_handler *c, 
 		    struct syslog_config *cfg, 
 		    struct persistent_config *persistent)
 {
+	CAST(afuser_dest, self, c);
+
+	self->cfg = cfg;
+
 	return ST_OK | ST_GOON;
 }
 
@@ -59,7 +86,14 @@
 	struct utmp *ut;
 	struct ol_string *msg_line;
 
-	msg_line = c_format("%S %S %S\n", msg->date, msg->host, msg->msg);
+	if (self->template_output) {
+		msg_line = c_format("%S\n",
+				    expand_macros(self->cfg, self->template_output, self->template_escape, msg));
+	} else {
+		msg_line = c_format("%S %S %S\n",
+				    msg->date, msg->host, msg->msg);
+	}
+
 	while ((ut = getutent())) {
 #if HAVE_MODERN_UTMP
 		if (ut->ut_type == USER_PROCESS &&
diff -ur syslog-ng-1.5.20/src/afuser.c.x syslog-ng-1.5.20.1/src/afuser.c.x
--- syslog-ng-1.5.20/src/afuser.c.x	Sun Jul  8 18:37:13 2001
+++ syslog-ng-1.5.20.1/src/afuser.c.x	Fri Sep  6 14:31:56 2002
@@ -3,21 +3,34 @@
 {
   struct log_dest_driver super;
   struct ol_string *username;
+  struct ol_string *template_fname;
+  struct ol_string *template_output;
+  int template_escape;
+  struct syslog_config *cfg;
 };
 extern struct ol_class afuser_dest_class;
 #endif /* !CLASS_DEFINE */
 
 #ifndef CLASS_DECLARE
+static void do_afuser_dest_mark(struct ol_object *o, 
+void (*mark)(struct ol_object *o))
+{
+  struct afuser_dest *i = (struct afuser_dest *) o;
+  mark((struct ol_object *) i->cfg);
+}
+
 static void do_afuser_dest_free(struct ol_object *o)
 {
   struct afuser_dest *i = (struct afuser_dest *) o;
   ol_string_free(i->username);
+  ol_string_free(i->template_fname);
+  ol_string_free(i->template_output);
 }
 
 struct ol_class afuser_dest_class =
 { STATIC_HEADER,
   &log_dest_driver_class, "afuser_dest", sizeof(struct afuser_dest),
-  NULL,
+  do_afuser_dest_mark,
   do_afuser_dest_free
 };
 #endif /* !CLASS_DECLARE */
diff -ur syslog-ng-1.5.20/src/afuser.h syslog-ng-1.5.20.1/src/afuser.h
--- syslog-ng-1.5.20/src/afuser.h	Sun Feb 25 13:00:22 2001
+++ syslog-ng-1.5.20.1/src/afuser.h	Thu Sep  5 15:48:27 2002
@@ -29,5 +29,7 @@
 #include "syslog-ng.h"
 
 struct log_dest_driver *make_afuser_dest(const char *username);
+void afuser_dest_set_template(struct log_dest_driver *c, char *t);
+void afuser_dest_set_template_escape(struct log_dest_driver *c, int enable);
 
 #endif
Only in syslog-ng-1.5.20/src: cfg-grammar.h
diff -ur syslog-ng-1.5.20/src/cfg-grammar.y syslog-ng-1.5.20.1/src/cfg-grammar.y
--- syslog-ng-1.5.20/src/cfg-grammar.y	Wed Aug 21 16:03:50 2002
+++ syslog-ng-1.5.20.1/src/cfg-grammar.y	Thu Sep 12 10:58:04 2002
@@ -80,7 +80,7 @@
 %token KW_TIME_REOPEN KW_TIME_REAP KW_USE_TIME_RECVD
 %token KW_USE_DNS KW_USE_FQDN KW_GC_BUSY_THRESHOLD 
 %token KW_GC_IDLE_THRESHOLD KW_CREATE_DIRS 
-%token KW_DIR_OWNER KW_DIR_GROUP KW_DIR_PERM KW_FILE_TEMPLATE KW_TEMPLATE_ESCAPE
+%token KW_DIR_OWNER KW_DIR_GROUP KW_DIR_PERM KW_TEMPLATE KW_TEMPLATE_ESCAPE
 %token KW_OWNER KW_GROUP KW_PERM KW_KEEP_ALIVE KW_MAX_CONNECTIONS
 %token KW_LOCALIP KW_IP KW_LOCALPORT KW_PORT KW_DESTPORT 
 %token KW_COMPRESS KW_MAC KW_AUTH KW_ENCRYPT
@@ -136,7 +136,9 @@
 %type	<ptr> dest_afinet_udp_params
 %type	<ptr> dest_afinet_tcp_params
 %type   <ptr> dest_afuser
+%type   <ptr> dest_afuser_params
 %type   <ptr> dest_afprogram
+%type   <ptr> dest_afprogram_params
 %type   <ptr> dest_afremctrl
 
 %type	<ptr> log_items
@@ -408,7 +410,7 @@
 	| KW_DIR_PERM '(' NUMBER ')'		{ affile_set_dir_perm(last_dest_driver, $3); }
 	| KW_CREATE_DIRS '(' yesno ')'		{ affile_set_create_dirs(last_dest_driver, $3); }
 	| KW_REMOVE_IF_OLDER '(' NUMBER ')'	{ affile_set_remove_if_older(last_dest_driver, $3); }
-	| KW_FILE_TEMPLATE '(' string ')'       { affile_set_file_template(last_dest_driver, $3); free($3); }
+	| KW_TEMPLATE '(' string ')'            { affile_set_file_template(last_dest_driver, $3); free($3); }
 	| KW_TEMPLATE_ESCAPE '(' yesno ')'	{ affile_set_template_escape(last_dest_driver, $3); }
 	| KW_FSYNC '(' yesno ')'		{ affile_set_fsync(last_dest_driver, $3); }
 	;
@@ -436,7 +438,7 @@
 	: KW_OWNER '(' string ')'		{ affile_set_owner(last_dest_driver, $3); free($3); }
 	| KW_GROUP '(' string ')'		{ affile_set_group(last_dest_driver, $3); free($3); }
 	| KW_PERM '(' NUMBER ')'		{ affile_set_perm(last_dest_driver, $3); }
-	| KW_FILE_TEMPLATE '(' string ')'       { affile_set_file_template(last_dest_driver, $3); free($3); }
+	| KW_TEMPLATE '(' string ')'            { affile_set_file_template(last_dest_driver, $3); free($3); }
 	| KW_TEMPLATE_ESCAPE '(' yesno ')'	{ affile_set_template_escape(last_dest_driver, $3); }
 	;
 
@@ -448,23 +450,35 @@
 	| KW_TCP '(' dest_afinet_tcp_params ')'			{ $$ = $3; } 
 	;
 
+/* options are common between dgram & stream */
+dest_afunix_option
+	: KW_TEMPLATE '(' string ')'            { afunix_dest_set_template(last_dest_driver, $3); free($3); }
+	| KW_TEMPLATE_ESCAPE '(' yesno ')'	{ afunix_dest_set_template_escape(last_dest_driver, $3); }
+	; 
+
+dest_afunix_options
+	: dest_afunix_options dest_afunix_option
+	|
+	;
+
 dest_afunix_dgram_params
-	: string				{ $$ = make_afunix_dest(
+	: string				{ last_dest_driver = make_afunix_dest(
 							&make_unix_address_c($1)->super, 
 							AFSOCKET_DGRAM);
 							free($1);
 						}
+	dest_afunix_options			{ $$ = last_dest_driver; }
 	;
 
 dest_afunix_stream_params
-	: string				{ $$ = make_afunix_dest(
+	: string				{ last_dest_driver = make_afunix_dest(
 							&make_unix_address_c($1)->super, 
 							AFSOCKET_STREAM);
 							free($1);
 						}
+	dest_afunix_options			{ $$ = last_dest_driver; }
 	;
 
-
 dest_afinet_udp_params
 	: string 	
 	  { 
@@ -486,6 +500,8 @@
 	| KW_LOCALPORT '(' NUMBER ')'		{ afinet_dest_set_localport(last_dest_driver, $3, NULL, NULL); }
 	| KW_PORT '(' NUMBER ')'		{ afinet_dest_set_destport(last_dest_driver, $3, NULL, NULL); }
 	| KW_DESTPORT '(' NUMBER ')'		{ afinet_dest_set_destport(last_dest_driver, $3, NULL, NULL); }
+	| KW_TEMPLATE '(' string ')'            { afinet_dest_set_template(last_dest_driver, $3); free($3); }
+	| KW_TEMPLATE_ESCAPE '(' yesno ')'	{ afinet_dest_set_template_escape(last_dest_driver, $3); }
 	;
 
 dest_afinet_udp_option
@@ -522,13 +538,42 @@
 	| KW_SYNC_FREQ '(' NUMBER ')'		{ afinet_dest_set_syncfreq(last_dest_driver, $3); }
 	;
 
-
 dest_afuser
-	: KW_USER '(' string ')'		{ $$ = make_afuser_dest($3); free($3); }
+	: KW_USER '(' dest_afuser_params ')'	{ $$ = $3; }
+	;
+
+dest_afuser_params
+	: string				{ last_dest_driver = make_afuser_dest($1); free($1); }
+	dest_afuser_options			{ $$ = last_dest_driver; }
+	;
+
+dest_afuser_option
+	: KW_TEMPLATE '(' string ')'            { afuser_dest_set_template(last_dest_driver, $3); free($3); }
+	| KW_TEMPLATE_ESCAPE '(' yesno ')'	{ afuser_dest_set_template_escape(last_dest_driver, $3); }
+	; 
+
+dest_afuser_options
+	: dest_afuser_options dest_afuser_option
+	|
 	;
 
 dest_afprogram
-	: KW_PROGRAM '(' string ')' 		{ $$ = make_afprogram_dest($3); free($3); }
+	: KW_PROGRAM '(' dest_afprogram_params ')'	{ $$ = $3; }
+	;
+
+dest_afprogram_params
+	: string				{ last_dest_driver = make_afprogram_dest($1); free($1); }
+	dest_afprogram_options			{ $$ = last_dest_driver; }
+	;
+
+dest_afprogram_option
+	: KW_TEMPLATE '(' string ')'            { afprogram_dest_set_template(last_dest_driver, $3); free($3); }
+	| KW_TEMPLATE_ESCAPE '(' yesno ')'	{ afprogram_dest_set_template_escape(last_dest_driver, $3); }
+	; 
+
+dest_afprogram_options
+	: dest_afprogram_options dest_afprogram_option
+	|
 	;
 
 dest_afremctrl
diff -ur syslog-ng-1.5.20/src/cfg-lex.c syslog-ng-1.5.20.1/src/cfg-lex.c
--- syslog-ng-1.5.20/src/cfg-lex.c	Wed Aug 21 16:04:18 2002
+++ syslog-ng-1.5.20.1/src/cfg-lex.c	Thu Sep  5 13:15:31 2002
@@ -484,7 +484,7 @@
 	{ "dir_owner",		KW_DIR_OWNER },
 	{ "dir_group",		KW_DIR_GROUP },
         { "dir_perm",           KW_DIR_PERM },
-        { "template",           KW_FILE_TEMPLATE },
+        { "template",           KW_TEMPLATE },
         { "template-escape",	KW_TEMPLATE_ESCAPE },
         { "template_escape",	KW_TEMPLATE_ESCAPE },
  	{ "keep-alive",         KW_KEEP_ALIVE },

--------------Boundary-00=_NOJBWJVQIWAAK32WEVZY--