#line 1026 "../../src/builtin/snarf.m4"
/* -*- buffer-read-only: t -*- vi: set ro:
   THIS FILE IS GENERATED AUTOMATICALLY.  PLEASE DO NOT EDIT.
*/
#line 1026
#ifdef HAVE_CONFIG_H
#line 1026
# include <config.h>
#line 1026
#endif
#line 1026
#include <sys/types.h>
#line 1026

#line 1026
#include "mailfromd.h"
#line 1026
#include "prog.h"
#line 1026
#include "builtin.h"
#line 1026

#line 616 "sa.bi"
static mu_debug_handle_t debug_handle;
#line 1026 "../../src/builtin/snarf.m4"

#line 1066 "../../src/builtin/snarf.m4"

/* End of snarf.m4 */
#line 1 "sa.bi"
/* This file is part of Mailfromd.             -*- c -*-
   Copyright (C) 2006-2025 Sergey Poznyakoff

   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
   the Free Software Foundation; either version 3, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>. */



#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <signal.h>

#include <mailutils/stream.h>

#include "msg.h"
#include "mflib/sa.h"

static size_t sa_score_loc
#line 32 "sa.bi"
;
static size_t sa_threshold_loc
#line 33 "sa.bi"
;
static size_t sa_keywords_loc
#line 34 "sa.bi"
;
static size_t clamav_virus_name_loc
#line 35 "sa.bi"
;
static size_t clamav_stream_max_length_loc
#line 36 "sa.bi"
;

static void
set_xscript(mu_stream_t *pstr)
{
	mu_stream_t tstr = *pstr;

	if (mu_debug_level_p(debug_handle, MU_DEBUG_PROT)) {
		int rc;
		mu_stream_t dstr;

		rc = mu_dbgstream_create(&dstr, MU_DIAG_DEBUG);
		if (rc)
			mu_error(_("cannot create debug stream; "
				   "transcript disabled: %s"),
				 mu_strerror(rc));
		else {
			rc = mu_xscript_stream_create(pstr, tstr, dstr, NULL);
			mu_stream_unref(dstr);
			if (rc)
				mu_error(_("cannot create transcript "
					   "stream: %s"),
					 mu_strerror(rc));
			else
				mu_stream_unref(tstr);
		}
	}
}

static int
spamd_send_stream(mu_stream_t out, mu_stream_t in)
{
	int rc;
	struct mu_buffer_query newbuf, oldbuf;
	int bufchg = 0;
	int xlev;
	int xlevchg = 0;

	/* Ensure effective transport buffering */
	oldbuf.type = MU_TRANSPORT_OUTPUT;
	if (mu_stream_ioctl(out, MU_IOCTL_TRANSPORT_BUFFER,
			    MU_IOCTL_OP_GET, &oldbuf) == 0) {
		newbuf.type = MU_TRANSPORT_OUTPUT;
		newbuf.buftype = mu_buffer_full;
		newbuf.bufsize = 64*1024;
		mu_stream_ioctl(out, MU_IOCTL_TRANSPORT_BUFFER, MU_IOCTL_OP_SET,
				&newbuf);
		bufchg = 1;
	}

	if (!mu_debug_level_p(debug_handle, MU_DEBUG_TRACE9)) {
		/* Mark out the following data as payload */
		xlev = MU_XSCRIPT_PAYLOAD;
		if (mu_stream_ioctl(out, MU_IOCTL_XSCRIPTSTREAM,
				    MU_IOCTL_XSCRIPTSTREAM_LEVEL, &xlev) == 0)
			xlevchg = 1;
	}

	rc = mu_stream_copy(out, in, 0, NULL);

	/* Restore prior transport buffering and xscript level */
	if (bufchg)
		mu_stream_ioctl(out, MU_IOCTL_TRANSPORT_BUFFER,
				MU_IOCTL_OP_SET,  &oldbuf);
	if (xlevchg)
		mu_stream_ioctl(out, MU_IOCTL_XSCRIPTSTREAM,
				MU_IOCTL_XSCRIPTSTREAM_LEVEL, &xlev);
	return rc;
}


static int
spamd_connect(eval_environ_t env, int crlf, mu_stream_t *pstream,
	      const char *host, int port)
{
	int rc;
	char *fname;
	mu_stream_t tstr, istr, ostr;

	if (port) {
		fname = "mu_tcp_stream_create";
		rc = mu_tcp_stream_create(&tstr, host, port, MU_STREAM_RDWR);
	} else {
		fname = "mu_socket_stream_create";
		rc = mu_socket_stream_create(&tstr, host, MU_STREAM_RDWR);
	}

		if (!(rc == 0))
#line 123
		(
#line 123
	env_throw_bi(env, mfe_failure, NULL, "%s: %s",fname,mu_strerror(rc))
#line 123
)
#line 125
;

	mu_stream_set_buffer(tstr, mu_buffer_line, 0);

	if (crlf) {
		rc = mu_filter_create(&istr, tstr, "CRLF",
				      MU_FILTER_DECODE, MU_FILTER_READ);
		if (rc) {
			mu_stream_unref(tstr);
			(
#line 134
	env_throw_bi(env, mfe_failure, NULL, "%s input filter: %s",fname,mu_strerror(rc))
#line 134
);
#line 137
		}
		mu_stream_set_buffer(istr, mu_buffer_line, 0);

		rc = mu_filter_create(&ostr, tstr, "CRLF",
				      MU_FILTER_ENCODE, MU_FILTER_WRITE);
		if (rc) {
			mu_stream_unref(tstr);
			(
#line 144
	env_throw_bi(env, mfe_failure, NULL, "%s output filter: %s",fname,mu_strerror(rc))
#line 144
);
#line 147
		}
		mu_stream_set_buffer(ostr, mu_buffer_line, 0);
		mu_stream_unref(tstr);
	} else {
		istr = tstr;
		ostr = tstr;
		mu_stream_ref(tstr);
	}

	rc = mu_iostream_create(&tstr, istr, ostr);
	mu_stream_unref(istr);
	mu_stream_unref(ostr);
		if (!(rc == 0))
#line 159
		(
#line 159
	env_throw_bi(env, mfe_failure, NULL, "I/O stream: %s",mu_strerror(rc))
#line 159
)
#line 161
;
	mu_stream_set_buffer(tstr, mu_buffer_line, 0);
	set_xscript(&tstr);
	*pstream = tstr;
	return rc;
}

static int
spamd_get_line(mu_stream_t stream, char **pbuffer, size_t *psize)
{
	int rc = mu_stream_getline(stream, pbuffer, psize, NULL);
	if (rc == 0)
		mu_rtrim_class (*pbuffer, MU_CTYPE_SPACE);
	return rc;
}

#define char_to_num(c) (c-'0')

static void
decode_float(long *vn, char *str, int digits)
{
	long v;
	size_t frac = 0;
	size_t base = 1;
	int i;
	int negative = 0;

	for (i = 0; i < digits; i++)
		base *= 10;

	v = strtol(str, &str, 10);
	if (v < 0) {
		negative = 1;
		v = - v;
	}

	v *= base;
	if (*str == '.') {
		for (str++, i = 0; *str && i < digits; i++, str++)
			frac = frac * 10 + char_to_num (*str);
		if (*str) {
			if (char_to_num(*str) >= 5)
				frac++;
		}
		else
			for (; i < digits; i++)
				frac *= 10;
	}
	*vn = v + frac;
	if (negative)
		*vn = - *vn;
}

static int
decode_boolean (char *str)
{
	if (strcasecmp (str, "true") == 0)
		return 1;
	else if (strcasecmp (str, "false") == 0)
		return 0;
	/*else?*/
	return 0;
}

typedef void (*signal_handler_fn)(int);

static signal_handler_fn
set_signal_handler (int sig, signal_handler_fn h)
{
	struct sigaction act, oldact;
	act.sa_handler = h;
	sigemptyset (&act.sa_mask);
	act.sa_flags = 0;
	sigaction (sig, &act, &oldact);
	return oldact.sa_handler;
}

static int got_sigpipe;

static void
sigpipe_handler (int sig)
{
	got_sigpipe = 1;
}

mu_stream_t
open_connection(eval_environ_t env, int crlf, char *urlstr, char **phost)
{
	char *path = NULL;
	short port = 0;
	mu_stream_t str = NULL;
	int rc;

	if (urlstr[0] == '/') {
		path = strdup(urlstr);
		if (!path)
			runtime_error(env, _("not enough memory"));
	} else {
		const char *buf;
		mu_url_t url = NULL;

		rc = mu_url_create(&url, urlstr);
		if (rc)
			(
#line 264
	env_throw_bi(env, mfe_failure, NULL, _("cannot create URL from `%s': %s"),urlstr,mu_strerror(rc))
#line 264
);
#line 267

		if (rc = mu_url_sget_scheme(url, &buf)) {
			mu_url_destroy(&url);
			(
#line 270
	env_throw_bi(env, mfe_url, NULL, _("%s: cannot get scheme: %s"),urlstr,mu_strerror(rc))
#line 270
);
#line 273
		}

		if (strcmp(buf, "file") == 0
		    || strcmp(buf, "socket") == 0) {
			if (rc = mu_url_aget_path(url, &path)) {
				(
#line 278
	env_throw_bi(env, mfe_url, NULL, _("%s: cannot get path: %s"),urlstr,mu_strerror(rc))
#line 278
);
#line 281
			}
		} else if (strcmp(buf, "tcp") == 0) {
			unsigned n;

			if (rc = mu_url_get_port(url, &n)) {
				mu_url_destroy(&url);
				(
#line 287
	env_throw_bi(env, mfe_url, NULL, _("%s: cannot get port: %s"),urlstr,mu_strerror(rc))
#line 287
);
#line 290
			}

			if (n == 0 || (port = n) != n) {
				mu_url_destroy(&url);
				(
#line 294
	env_throw_bi(env, mfe_range, NULL, _("port out of range: %u"),n)
#line 294
);
#line 297
			}

			if (rc = mu_url_aget_host(url, &path)) {
				mu_url_destroy(&url);
				(
#line 301
	env_throw_bi(env, mfe_url, NULL, _("%s: cannot get host: %s"),urlstr,mu_strerror(rc))
#line 301
);
#line 304
			}
		} else
			(
#line 306
	env_throw_bi(env, mfe_url, NULL, _("invalid URL: %s"),buf)
#line 306
);
#line 308

		mu_url_destroy(&url);
	}

	rc = spamd_connect(env, crlf, &str, path, port);
	env_function_cleanup_add(env, CLEANUP_ALWAYS, str, _builtin_stream_cleanup);
	if (rc == 0 && phost) {
		if (port)
			*phost = path;
		else
			*phost = NULL;
	}
	return str;
}


void
#line 324
bi_spamc(eval_environ_t env)
#line 324

#line 324

#line 324 "sa.bi"
{
#line 324
	
#line 324

#line 324
        long  nmsg;
#line 324
        char * MFL_DATASEG urlstr;
#line 324
        long  prec;
#line 324
        long  command;
#line 324
        
#line 324

#line 324
        get_numeric_arg(env, 0, &nmsg);
#line 324
        get_string_arg(env, 1, &urlstr);
#line 324
        get_numeric_arg(env, 2, &prec);
#line 324
        get_numeric_arg(env, 3, &command);
#line 324
        
#line 324
        adjust_stack(env, 4);
#line 324

#line 324

#line 324
	if (builtin_module_trace(BUILTIN_IDX_sa))
#line 324
		prog_trace(env, "spamc %lu %s %lu %lu",nmsg, urlstr, prec, command);;
#line 324

{
	mu_message_t msg;
	mu_stream_t mstr;
	mu_off_t msize;
	size_t lines;
	mu_stream_t ostr;
	signal_handler_fn handler;
	char *buffer = NULL;
	size_t bufsize = 0;
	size_t n;
	char version_str[19];
	char spam_str[6], score_str[21], threshold_str[21];
	long version;
	int result;
	long score, threshold;
	char *cmdstr;
	int rc;

	msg = bi_message_from_descr(env, nmsg);
	rc = mu_message_get_streamref(msg, &mstr);
		if (!(rc == 0))
#line 345
		(
#line 345
	env_throw_bi(env, mfe_failure, "spamc", "mu_stream_get_streamref: %s",mu_strerror (rc))
#line 345
)
#line 348
;
	env_function_cleanup_add(env, CLEANUP_ALWAYS, mstr, _builtin_stream_cleanup);

	rc = mu_stream_size(mstr, &msize);
		if (!(rc == 0))
#line 352
		(
#line 352
	env_throw_bi(env, mfe_failure, "spamc", "mu_stream_size: %s",mu_strerror (rc))
#line 352
)
#line 355
;

	ostr = open_connection(env, 1, urlstr, NULL);

	/* And that, finally, gets the number of lines */
	rc = mu_message_lines(msg, &lines);
		if (!(rc == 0))
#line 361
		(
#line 361
	env_throw_bi(env, mfe_failure, "spamc", "mu_message_lines: %s",mu_strerror (rc))
#line 361
)
#line 364
;
	msize += lines;

	switch (command) {
	case SA_REPORT:
		cmdstr = "REPORT";
		break;
	case SA_SYMBOLS:
		cmdstr = "SYMBOLS";
		break;
	case SA_LEARN_SPAM:
	case SA_LEARN_HAM:
	case SA_FORGET:
		cmdstr = "TELL";
		break;
	default:
		(
#line 380
	env_throw_bi(env, mfe_failure, "spamc", _("unknown command: %ld"),command)
#line 380
);
#line 382
	}
	mu_stream_printf(ostr, "%s SPAMC/1.2\n", cmdstr);

	switch (command) {
	case SA_LEARN_SPAM:
		mu_stream_printf(ostr,
				 "Message-class: spam\n"
				 "Set: local\n");
		break;
	case SA_LEARN_HAM:
		mu_stream_printf(ostr,
				 "Message-class: ham\n"
				 "Set: local\n");
		break;
	case SA_FORGET:
		mu_stream_printf(ostr,
				 "Remove: local\n");
	}

	mu_stream_printf(ostr, "Content-length: %lu\n",
			 (unsigned long) msize);
	/*FIXME: spamd_send_command(ostr, "User: %s", ??) */
	got_sigpipe = 0;
	handler = set_signal_handler(SIGPIPE, sigpipe_handler);
	mu_stream_write(ostr, "\n", 1, NULL);
	rc = spamd_send_stream(ostr, mstr);
		if (!(rc == 0))
#line 408
		(
#line 408
	env_throw_bi(env, mfe_failure, "spamc", _("send stream failed: %s"),mu_strerror(rc))
#line 408
)
#line 411
;

	mu_stream_shutdown(ostr, MU_STREAM_WRITE);
	set_signal_handler(SIGPIPE, handler);

	env_function_cleanup_add(env, CLEANUP_ALWAYS, buffer, NULL);
	spamd_get_line(ostr, &buffer, &bufsize);
	if (got_sigpipe)
		(
#line 419
	env_throw_bi(env, mfe_failure, "spamc", _("remote side has closed connection"))
#line 419
);

		if (!(sscanf(buffer, "SPAMD/%18s %d %*s", version_str,
#line 421
			 &result) == 2))
#line 421
		(
#line 421
	env_throw_bi(env, mfe_failure, "spamc", _("spamd responded with bad string '%s'"),buffer)
#line 421
)
#line 425
;

	decode_float(&version, version_str, 1);
		if (!(version >= 10))
#line 428
		(
#line 428
	env_throw_bi(env, mfe_failure, "spamc", _("unsupported SPAMD version: %s"),version_str)
#line 428
)
#line 431
;

		if (!(result == 0))
#line 433
		(
#line 433
	env_throw_bi(env, mfe_failure, "spamc", "%s",buffer)
#line 433
)
#line 433
;

	spamd_get_line(ostr, &buffer, &bufsize);

	switch (command) {
	case SA_REPORT:
	case SA_SYMBOLS:
			if (!(sscanf(buffer, "Spam: %5s ; %20s / %20s",
#line 440
				 spam_str, score_str, threshold_str) == 3))
#line 440
		(
#line 440
	env_throw_bi(env, mfe_failure, "spamc", _("spamd responded with bad Spam header '%s'"),buffer)
#line 440
)
#line 444
;

		result = decode_boolean(spam_str);
		decode_float(&score, score_str, prec);
		decode_float(&threshold, threshold_str, prec);

		mf_c_val(*env_data_ref(env, sa_score_loc),long) = (score);
		mf_c_val(*env_data_ref(env, sa_threshold_loc),long) = (threshold);

		/* Skip newline */
		spamd_get_line(ostr, &buffer, &bufsize);
		break;

	case SA_LEARN_SPAM:
	case SA_LEARN_HAM:
		result = !!strcmp(buffer, "DidSet: local");
		break;

	case SA_FORGET:
		result = !!strcmp(buffer, "DidRemove: local");
		break;
	}

	switch (command) {
	case SA_REPORT:
		heap_obstack_begin(env);
		while (mu_stream_getline(ostr, &buffer, &bufsize, &n) == 0
		       && n > 0)
			heap_obstack_grow(env, buffer, n);
		do { char __c = 0; heap_obstack_grow(env, &__c, 1); } while(0);
		mf_c_val(*env_data_ref(env, sa_keywords_loc),ptr) = (mf_c_val(heap_obstack_finish(env), ptr));//FIXME
		break;

	case SA_SYMBOLS:
		/* Read symbol list */
		spamd_get_line(ostr, &buffer, &bufsize);
		
#line 480
{ size_t __off;
#line 480
  const char *__s = buffer;
#line 480
  if (__s)
#line 480
     strcpy((char*)env_data_ref(env, __off = heap_reserve(env, strlen(__s) + 1)), __s);
#line 480
  else
#line 480
     __off = 0;
#line 480
  mf_c_val(*env_data_ref(env, sa_keywords_loc),size) = (__off); }
#line 480
;
	}

	/* Just in case */
	while (mu_stream_getline(ostr, &buffer, &bufsize, &n) == 0
	       && n > 0)
		/* Drain input */;

	
#line 488
do {
#line 488
  push(env, (STKVAL)(mft_number)(result));
#line 488
  goto endlab;
#line 488
} while (0);
}
endlab:
#line 490
        env_function_cleanup_flush(env, CLEANUP_RETURN);
#line 490
	return;
#line 490
}

static int
clamav_send_stream(mu_stream_t out, mu_stream_t in, mu_off_t insize,
		   size_t chunk_size)
{
	int rc;
	struct mu_buffer_query newbuf, oldbuf;
	int bufchg = 0;
	int xlev;
	int xlevchg = 0;
	signal_handler_fn handler;

	got_sigpipe = 0;
	handler = set_signal_handler(SIGPIPE, sigpipe_handler);

	/* Ensure effective transport buffering */
	oldbuf.type = MU_TRANSPORT_OUTPUT;
	if (mu_stream_ioctl(out, MU_IOCTL_TRANSPORT_BUFFER,
			    MU_IOCTL_OP_GET, &oldbuf) == 0) {
		newbuf.type = MU_TRANSPORT_OUTPUT;
		newbuf.buftype = mu_buffer_full;
		newbuf.bufsize = 64*1024;
		mu_stream_ioctl(out, MU_IOCTL_TRANSPORT_BUFFER, MU_IOCTL_OP_SET,
				&newbuf);
		bufchg = 1;
	}

	if (!mu_debug_level_p(debug_handle, MU_DEBUG_TRACE9)) {
		/* Mark out the following data as payload */
		xlev = MU_XSCRIPT_PAYLOAD;
		if (mu_stream_ioctl(out, MU_IOCTL_XSCRIPTSTREAM,
				    MU_IOCTL_XSCRIPTSTREAM_LEVEL, &xlev) == 0)
			xlevchg = 1;
	}

	while (1) {
		mu_off_t n = insize > chunk_size ? chunk_size : insize;
		mu_off_t wrsize;
		uint32_t size = htonl(n);

		rc = mu_stream_write(out, &size, sizeof(size), NULL);
		if (rc || n == 0)
			break;

		rc = mu_stream_copy(out, in, n, &wrsize);
		if (rc)
			break;
		insize -= wrsize;
	}

	/* Restore prior transport buffering and xscript level */
	if (bufchg)
		mu_stream_ioctl(out, MU_IOCTL_TRANSPORT_BUFFER,
				MU_IOCTL_OP_SET,  &oldbuf);
	if (xlevchg)
		mu_stream_ioctl(out, MU_IOCTL_XSCRIPTSTREAM,
				MU_IOCTL_XSCRIPTSTREAM_LEVEL, &xlev);

	set_signal_handler(SIGPIPE, handler);

	return rc;
}


void
#line 555
bi_clamav(eval_environ_t env)
#line 555

#line 555

#line 555 "sa.bi"
{
#line 555
	
#line 555

#line 555
        long  nmsg;
#line 555
        char * MFL_DATASEG urlstr;
#line 555
        
#line 555

#line 555
        get_numeric_arg(env, 0, &nmsg);
#line 555
        get_string_arg(env, 1, &urlstr);
#line 555
        
#line 555
        adjust_stack(env, 2);
#line 555

#line 555

#line 555
	if (builtin_module_trace(BUILTIN_IDX_sa))
#line 555
		prog_trace(env, "clamav %lu %s",nmsg, urlstr);;
#line 555

{
	mu_message_t msg;
	mu_stream_t mstr;
	mu_off_t msize;
	mu_stream_t cstr;
	char *buffer = NULL;
	size_t bufsize = 0;
	char *host;
	int rc;
	char *p;

	msg = bi_message_from_descr(env, nmsg);
	rc = mu_message_get_streamref(msg, &mstr);
		if (!(rc == 0))
#line 569
		(
#line 569
	env_throw_bi(env, mfe_failure, "clamav", "mu_stream_get_streamref: %s",mu_strerror (rc))
#line 569
)
#line 572
;
	env_function_cleanup_add(env, CLEANUP_ALWAYS, mstr, _builtin_stream_cleanup);

	rc = mu_stream_size(mstr, &msize);
		if (!(rc == 0))
#line 576
		(
#line 576
	env_throw_bi(env, mfe_failure, "clamav", "mu_stream_size: %s",mu_strerror (rc))
#line 576
)
#line 579
;

	env_function_cleanup_add(env, CLEANUP_ALWAYS, buffer, NULL);
	cstr = open_connection(env, 0, urlstr, &host);

	mu_stream_printf(cstr, "nINSTREAM\n");
	mu_stream_flush(cstr);
	rc = clamav_send_stream(cstr, mstr, msize,
				mf_c_val(*env_data_ref(env, clamav_stream_max_length_loc),long) );

		if (!(rc == 0))
#line 589
		(
#line 589
	env_throw_bi(env, mfe_failure, "clamav", _("sending to stream failed: %s"),mu_strerror(rc))
#line 589
)
#line 592
;

	rc = spamd_get_line(cstr, &buffer, &bufsize);
	//FIXME MF_CLEANUP(cstr);
		if (!(rc == 0))
#line 596
		(
#line 596
	env_throw_bi(env, mfe_failure, "clamav", _("error reading clamav response: %s"),mu_strerror(rc))
#line 596
)
;

	p = strrchr(buffer, ' ');
		if (!(p))
#line 600
		(
#line 600
	env_throw_bi(env, mfe_failure, "clamav", _("unknown clamav response: %s"),buffer)
#line 600
)
;
	++p;
	if (strncmp(p, "OK", 2) == 0)
		rc = 0;
	else if (strncmp(p, "FOUND", 5) == 0) {
		char *s;

		*--p = '\0';
		s = strrchr(buffer, ' ');
		if (!s)
			s = buffer;
		else
			s++;
		
#line 614
{ size_t __off;
#line 614
  const char *__s = s;
#line 614
  if (__s)
#line 614
     strcpy((char*)env_data_ref(env, __off = heap_reserve(env, strlen(__s) + 1)), __s);
#line 614
  else
#line 614
     __off = 0;
#line 614
  mf_c_val(*env_data_ref(env, clamav_virus_name_loc),size) = (__off); }
#line 614
;

		
#line 616 "sa.bi"

#line 616
mu_debug(debug_handle, MU_DEBUG_TRACE1,("%sclamav found %s",
			  mailfromd_msgid(env_get_context(env)), s));
#line 619
		rc = 1;
	} else if (strncmp(p, "ERROR", 5) == 0) {
		/* FIXME: mf code */
		(
#line 622
	env_throw_bi(env, mfe_failure, "clamav", _("clamav error: %s"),buffer)
#line 622
);
	} else {
		(
#line 624
	env_throw_bi(env, mfe_failure, "clamav", _("unknown clamav response: %s"),buffer)
#line 624
);
#line 627
	}
	
#line 628
do {
#line 628
  push(env, (STKVAL)(mft_number)(rc));
#line 628
  goto endlab;
#line 628
} while (0);
}
endlab:
#line 630
        env_function_cleanup_flush(env, CLEANUP_RETURN);
#line 630
	return;
#line 630
}

 
#line 1026 "../../src/builtin/snarf.m4"

#line 1026

#line 1026

#line 1026
void
#line 1026
sa_init_builtin(void)
#line 1026
{
#line 1026
		debug_handle = mu_debug_register_category("bi_sa");
#line 1026

#line 1026
	#line 32 "sa.bi"
	builtin_variable_install("sa_score", dtype_number, SYM_VOLATILE, &sa_score_loc);
#line 33 "sa.bi"
	builtin_variable_install("sa_threshold", dtype_number, SYM_VOLATILE, &sa_threshold_loc);
#line 34 "sa.bi"
	builtin_variable_install("sa_keywords", dtype_string, SYM_VOLATILE, &sa_keywords_loc);
#line 35 "sa.bi"
	builtin_variable_install("clamav_virus_name", dtype_string, SYM_VOLATILE, &clamav_virus_name_loc);
#line 36 "sa.bi"
	builtin_variable_install("clamav_stream_max_length", dtype_number, SYM_VOLATILE, &clamav_stream_max_length_loc);
#line 324 "sa.bi"
va_builtin_install_ex("spamc", bi_spamc, 0, dtype_number, 4, 0, 0|0, dtype_number, dtype_string, dtype_number, dtype_number);
#line 555 "sa.bi"
va_builtin_install_ex("clamav", bi_clamav, 0, dtype_number, 2, 0, 0|0, dtype_number, dtype_string);

#line 1026 "../../src/builtin/snarf.m4"
	
#line 1026
	 long n = 4096;
#line 1026
	 ds_init_variable("clamav_stream_max_length", &n);
#line 1026
	 
#line 1026
}
#line 1026 "../../src/builtin/snarf.m4"

