#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 65 "dkim.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 "dkim.bi"
/* This file is part of Mailfromd.             -*- c -*-
   Copyright (C) 2020-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/>. */


#ifdef WITH_DKIM
#line 18


#include "dkim.h"
#include "msg.h"

struct msgmod_data {
	mu_message_t msg;
	char const *h_list;
	struct msgmod_closure *e_msgmod;
};

static int
message_replace_body(mu_message_t msg, mu_stream_t stream)
{
	mu_body_t body;
	int rc;

	rc = mu_body_create(&body, msg);
	if (rc) {
		mu_diag_funcall(MU_DIAG_ERROR, "mu_body_create", NULL, rc);
		return rc;
	}

	rc = mu_body_set_stream(body, stream, msg);
	if (rc) {
		mu_body_destroy(&body, msg);
		mu_diag_funcall(MU_DIAG_ERROR, "mu_body_set_stream", NULL, rc);
		return rc;
	}

	rc = mu_message_set_body(msg, body, mu_message_get_owner(msg));
	if (rc) {
		mu_body_destroy(&body, msg);
		mu_diag_funcall(MU_DIAG_ERROR, "mu_message_set_body", NULL, rc);
	}
	return rc;
}

static int
do_msgmod(void *item, void *data)
{
	struct msgmod_closure *msgmod = item;
	struct msgmod_data *md = data;
	mu_header_t hdr;
	mu_stream_t stream;
	int rc;

	
#line 65 "dkim.bi"

#line 65
mu_debug(debug_handle, MU_DEBUG_TRACE6,("%s %s: %s %u",
		  msgmod_opcode_str(msgmod->opcode),
		  SP(msgmod->name), SP(msgmod->value), msgmod->idx));
#line 69

	mu_message_get_header(md->msg, &hdr);

	switch (msgmod->opcode) {
	case header_replace:
		if (!dkim_header_list_match(md->h_list, msgmod->name))
			break;
		if (mu_header_sget_value(hdr, msgmod->name, NULL) == 0) {
			rc = mu_header_insert(hdr, msgmod->name, msgmod->value,
					      NULL,
					      msgmod->idx, MU_HEADER_REPLACE);
			if (rc == MU_ERR_NOENT) {
				rc = mu_header_append(hdr, msgmod->name, msgmod->value);
				if (rc)
					mu_diag_funcall(MU_DIAG_ERROR,
							"mu_header_insert",
							msgmod->name,
							rc);
			} else if (rc) {
				mu_diag_funcall(MU_DIAG_ERROR,
						"mu_header_insert",
						msgmod->name,
						rc);
			}
		} else {
			rc = mu_header_append(hdr, msgmod->name, msgmod->value);
			if (rc)
				mu_diag_funcall(MU_DIAG_ERROR,
						"mu_header_append",
						msgmod->name,
						rc);
		}
		if (rc) {
			md->e_msgmod = msgmod;
			return rc;
		}
		break;

	case header_delete:
		if (!dkim_header_list_match(md->h_list, msgmod->name))
		    break;
		rc = mu_header_remove(hdr, msgmod->name, msgmod->idx);
		if (rc && rc != MU_ERR_NOENT) {
			mu_diag_funcall(MU_DIAG_ERROR,
					"mu_header_remove",
					msgmod->name,
					rc);
			md->e_msgmod = msgmod;
			return rc;
		}
		break;

	case body_repl:
		rc = mu_static_memory_stream_create(&stream, msgmod->value,
						    strlen(msgmod->value));
		if (rc) {
			md->e_msgmod = msgmod;
			return rc;
		}
		rc = message_replace_body(md->msg, stream);
		if (rc) {
			mu_stream_destroy(&stream);
			md->e_msgmod = msgmod;
			return rc;
		}
		break;

	case body_repl_fd:
		rc = mu_fd_stream_create (&stream, "<body_repl_fd>",
					  msgmod->idx,
					  MU_STREAM_READ);
		if (rc) {
			md->e_msgmod = msgmod;
			return rc;
		}
		rc = message_replace_body(md->msg, stream);
		if (rc) {
			mu_stream_destroy(&stream);
			md->e_msgmod = msgmod;
			return rc;
		}
		break;

	case header_add:
	case header_insert:
		if (!dkim_header_list_match(md->h_list, msgmod->name))
		    break;
		md->e_msgmod = msgmod;
		return MU_ERR_USER0;

	case rcpt_add:
	case rcpt_delete:
	case quarantine:
	case set_from:
		break;
	}
	return 0;
}

static size_t dkim_sendmail_commaize_loc
#line 168 "dkim.bi"
;

 
#line 174



void
#line 177
bi_dkim_sign(eval_environ_t env)
#line 177

#line 177

#line 177 "dkim.bi"
{
#line 177
	
#line 177

#line 177
        char *  d;
#line 177
        char *  s;
#line 177
        char *  keyfile;
#line 177
        char *  canon_h;
#line 177
        char *  canon_b;
#line 177
        char *  headers;
#line 177
        char *  algo;
#line 177
        
#line 177
        long __bi_argcnt;
#line 177
        get_numeric_arg(env, 0, &__bi_argcnt);
#line 177
        get_string_arg(env, 1, &d);
#line 177
        get_string_arg(env, 2, &s);
#line 177
        get_string_arg(env, 3, &keyfile);
#line 177
        if (__bi_argcnt > 3)
#line 177
                get_string_arg(env, 4, &canon_h);
#line 177
        if (__bi_argcnt > 4)
#line 177
                get_string_arg(env, 5, &canon_b);
#line 177
        if (__bi_argcnt > 5)
#line 177
                get_string_arg(env, 6, &headers);
#line 177
        if (__bi_argcnt > 6)
#line 177
                get_string_arg(env, 7, &algo);
#line 177
        
#line 177
        adjust_stack(env, __bi_argcnt + 1);
#line 177

#line 177

#line 177
	if (builtin_module_trace(BUILTIN_IDX_dkim))
#line 177
		prog_trace(env, "dkim_sign %s %s %s %s %s %s %s",d, s, keyfile, ((__bi_argcnt > 3) ? canon_h : ""), ((__bi_argcnt > 4) ? canon_b : ""), ((__bi_argcnt > 5) ? headers : ""), ((__bi_argcnt > 6) ? algo : ""));;
#line 179

{
	struct dkim_signature sig = {
		.v = DKIM_VERSION,
		.d = d,
		.s = s,
		.canon = { DKIM_CANON_SIMPLE, DKIM_CANON_SIMPLE },
		.q = DKIM_QUERY_METHOD,
		.l = DKIM_LENGTH_ALL
	};
	static char default_headers[] =
		"From:From:"
		"Reply-To:Reply-To:"
		"Subject:Subject:"
		"Date:Date:"
		"To:"
		"Cc:"
		"Resent-Date:"
		"Resent-From:"
		"Resent-To:"
		"Resent-Cc:"
		"In-Reply-To:"
		"References:"
		"List-Id:"
		"List-Help:"
		"List-Unsubscribe:"
		"List-Subscribe:"
		"List-Post:"
		"List-Owner:"
		"List-Archive";
	mu_message_t msg;
	int rc;
	char *sighdr, *p;
	struct mu_locus_range locus;

	env_get_locus(env, &locus);

	if ((__bi_argcnt > 6)) {
		sig.algo = dkim_algo(algo);
			if (!(sig.algo != -1))
#line 218
		(
#line 218
	env_throw_bi(env, mfe_failure, "dkim_sign", _("bad signing algorithm: %s"),algo)
#line 218
)
#line 220
;
		sig.a = algo;
	} else {
		sig.algo = DKIM_ALGO_DEFAULT;
		sig.a = (char*) dkim_algo_str[sig.algo];
	}
	
	if ((__bi_argcnt > 3)) {
		sig.canon[0] = dkim_str_to_canon_type(canon_h, NULL);
		if (sig.canon[0] == DKIM_CANON_ERR)
			(
#line 230
	env_throw_bi(env, mfe_failure, "dkim_sign", _("bad canonicalization type: %s"),canon_h)
#line 230
);
#line 232
	}
	if ((__bi_argcnt > 4)) {
		sig.canon[1] = dkim_str_to_canon_type(canon_b, NULL);
		if (sig.canon[1] == DKIM_CANON_ERR)
			(
#line 236
	env_throw_bi(env, mfe_failure, "dkim_sign", _("bad canonicalization type: %s"),canon_b)
#line 236
);
#line 238
	}

	sig.h = ((__bi_argcnt > 5) ? headers : default_headers);
	bi_get_current_message(env, &msg);
	if (env_msgmod_count(env)) {
		struct msgmod_data mdat;

		rc = mu_message_create_copy(&mdat.msg, msg);
		if (rc) {
			mu_diag_funcall(MU_DIAG_ERROR,
					"mu_message_create_copy",
					NULL, rc);
			(
#line 250
	env_throw_bi(env, mfe_failure, "dkim_sign", "mu_message_create_copy: %s",mu_strerror(rc))
#line 250
);
#line 253
		}
		mdat.h_list = sig.h;
		mdat.e_msgmod = 0;
		rc = env_msgmod_apply(env, do_msgmod, &mdat);
		if (rc) {
			mu_message_unref(mdat.msg);
			if (rc == MU_ERR_USER0) {
				(
#line 260
	env_throw_bi(env, mfe_badmmq, "dkim_sign", _("MMQ incompatible with dkim_sign: %s on %s, value %s"),msgmod_opcode_str(mdat.e_msgmod->opcode),mdat.e_msgmod->name,SP(mdat.e_msgmod->value))
#line 260
);
#line 265
			} else if (mdat.e_msgmod) {
				(
#line 266
	env_throw_bi(env, mfe_failure, "dkim_sign", _("%s failed on %s, value %s: %s"),msgmod_opcode_str(mdat.e_msgmod->opcode),mdat.e_msgmod->name,SP(mdat.e_msgmod->value),mu_strerror(rc))
#line 266
);
#line 272
			} else
				(
#line 273
	env_throw_bi(env, mfe_failure, "dkim_sign", _("error: %s"),mu_strerror(rc))
#line 273
);
#line 276
		}
		msg = mdat.msg;
	} else
		mu_message_ref(msg);

	if (mf_c_val(*env_data_ref(env, dkim_sendmail_commaize_loc),int) ) {
		mu_message_t sm_msg;
		rc = sendmail_address_normalize(msg, &sm_msg);
		mu_message_unref(msg);
			if (!(rc == 0))
#line 285
		(
#line 285
	env_throw_bi(env, mfe_failure, "dkim_sign", _("Sendmail address header postprocessing failed: %s"),mu_strerror(rc))
#line 285
)
#line 287
;
		msg = sm_msg;
	}

	rc = mfd_dkim_sign(msg, &sig, keyfile, &sighdr);
	mu_message_unref(msg);
		if (!(rc == 0))
#line 293
		(
#line 293
	env_throw_bi(env, mfe_failure, "dkim_sign", _("DKIM failed"))
#line 293
)
#line 293
;

	p = strchr(sighdr, ':');
	*p++ = 0;
	while (mu_isblank(*p))
		p++;

	trace("%s%s:%u: %s %d \"%s: %s\"",
	      mailfromd_msgid(env_get_context(env)),
	      locus.beg.mu_file, locus.beg.mu_line,
	      msgmod_opcode_str(header_insert),
	      0,
	      sighdr, p);
	env_msgmod_append(env, header_insert, sighdr, p, 0);
	free(sighdr);
}

#line 309
        env_function_cleanup_flush(env, CLEANUP_RETURN);
#line 309
	return;
#line 309
}

static size_t dkim_explanation_code_loc
#line 311 "dkim.bi"
;
static size_t dkim_explanation_loc
#line 312 "dkim.bi"
;
static size_t dkim_verified_signature_loc
#line 313 "dkim.bi"
;
static size_t dkim_signing_algorithm_loc
#line 314 "dkim.bi"
;


void
#line 317
bi_dkim_verify(eval_environ_t env)
#line 317

#line 317

#line 317 "dkim.bi"
{
#line 317
	
#line 317

#line 317
        long  nmsg;
#line 317
        
#line 317

#line 317
        get_numeric_arg(env, 0, &nmsg);
#line 317
        
#line 317
        adjust_stack(env, 1);
#line 317

#line 317

#line 317
	if (builtin_module_trace(BUILTIN_IDX_dkim))
#line 317
		prog_trace(env, "dkim_verify %lu",nmsg);;
#line 317

{
	mu_message_t msg = bi_message_from_descr(env, nmsg);
	char *sig;
	char const *algo;
	int result = mfd_dkim_verify(msg, &sig, &algo);
	mf_c_val(*env_data_ref(env, dkim_explanation_code_loc),long) = (result);
	
#line 324
{ size_t __off;
#line 324
  const char *__s = dkim_explanation_str[result];
#line 324
  if (__s)
#line 324
     strcpy((char*)env_data_ref(env, __off = heap_reserve(env, strlen(__s) + 1)), __s);
#line 324
  else
#line 324
     __off = 0;
#line 324
  mf_c_val(*env_data_ref(env, dkim_explanation_loc),size) = (__off); }
#line 324
;
	
#line 325
{ size_t __off;
#line 325
  const char *__s = algo;
#line 325
  if (__s)
#line 325
     strcpy((char*)env_data_ref(env, __off = heap_reserve(env, strlen(__s) + 1)), __s);
#line 325
  else
#line 325
     __off = 0;
#line 325
  mf_c_val(*env_data_ref(env, dkim_signing_algorithm_loc),size) = (__off); }
#line 325
;
	if (dkim_result_trans[result] == DKIM_VERIFY_OK) {
		
#line 327
{ size_t __off;
#line 327
  const char *__s = sig;
#line 327
  if (__s)
#line 327
     strcpy((char*)env_data_ref(env, __off = heap_reserve(env, strlen(__s) + 1)), __s);
#line 327
  else
#line 327
     __off = 0;
#line 327
  mf_c_val(*env_data_ref(env, dkim_verified_signature_loc),size) = (__off); }
#line 327
;
	} else {
		
#line 329
{ size_t __off;
#line 329
  const char *__s = "";
#line 329
  if (__s)
#line 329
     strcpy((char*)env_data_ref(env, __off = heap_reserve(env, strlen(__s) + 1)), __s);
#line 329
  else
#line 329
     __off = 0;
#line 329
  mf_c_val(*env_data_ref(env, dkim_verified_signature_loc),size) = (__off); }
#line 329
;
	}
	
#line 331
do {
#line 331
  push(env, (STKVAL)(mft_number)(dkim_result_trans[result]));
#line 331
  goto endlab;
#line 331
} while (0);
}
endlab:
#line 333
        env_function_cleanup_flush(env, CLEANUP_RETURN);
#line 333
	return;
#line 333
}

extern int dkim_read_priv_key(char const *priv_file);

void
#line 337
bi_dkim_read_priv_key(eval_environ_t env)
#line 337

#line 337

#line 337 "dkim.bi"
{
#line 337
	
#line 337

#line 337
        char *  priv_file;
#line 337
        
#line 337

#line 337
        get_string_arg(env, 0, &priv_file);
#line 337
        
#line 337
        adjust_stack(env, 1);
#line 337

#line 337

#line 337
	if (builtin_module_trace(BUILTIN_IDX_dkim))
#line 337
		prog_trace(env, "dkim_read_priv_key %s",priv_file);;
#line 337

{
	
#line 339
do {
#line 339
  push(env, (STKVAL)(mft_number)(dkim_read_priv_key(priv_file)));
#line 339
  goto endlab;
#line 339
} while (0);
}
endlab:
#line 341
        env_function_cleanup_flush(env, CLEANUP_RETURN);
#line 341
	return;
#line 341
}

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

#line 1026

#line 1026
#endif /* WITH_DKIM */
#line 1026

#line 1026
void
#line 1026
dkim_init_builtin(void)
#line 1026
{
#line 1026
		debug_handle = mu_debug_register_category("bi_dkim");
#line 1026

#line 1026
#ifdef WITH_DKIM
#line 1026
	pp_define("WITH_DKIM");
#line 1026
	#line 168 "dkim.bi"
	builtin_variable_install("dkim_sendmail_commaize", dtype_number, SYM_VOLATILE, &dkim_sendmail_commaize_loc);
#line 177 "dkim.bi"
va_builtin_install_ex("dkim_sign", bi_dkim_sign, STATMASK(smtp_state_eom), dtype_unspecified, 7, 4, MFD_BUILTIN_CAPTURE|0, dtype_string, dtype_string, dtype_string, dtype_string, dtype_string, dtype_string, dtype_string);
#line 311 "dkim.bi"
	builtin_variable_install("dkim_explanation_code", dtype_number, SYM_VOLATILE, &dkim_explanation_code_loc);
#line 312 "dkim.bi"
	builtin_variable_install("dkim_explanation", dtype_string, SYM_VOLATILE, &dkim_explanation_loc);
#line 313 "dkim.bi"
	builtin_variable_install("dkim_verified_signature", dtype_string, SYM_VOLATILE, &dkim_verified_signature_loc);
#line 314 "dkim.bi"
	builtin_variable_install("dkim_signing_algorithm", dtype_string, SYM_VOLATILE, &dkim_signing_algorithm_loc);
#line 317 "dkim.bi"
va_builtin_install_ex("dkim_verify", bi_dkim_verify, 0, dtype_number, 1, 0, 0|0, dtype_number);
#line 337 "dkim.bi"
va_builtin_install_ex("dkim_read_priv_key", bi_dkim_read_priv_key, 0, dtype_number, 1, 0, 0|0, dtype_string);

#line 1026 "../../src/builtin/snarf.m4"
	
#line 1026
	 long n = 1;
#line 1026
	 ds_init_variable("dkim_sendmail_commaize", &n);
#line 1026

#line 1026
#endif /* WITH_DKIM */
#line 1026
}
#line 1026 "../../src/builtin/snarf.m4"

