static void sieve_ldap_script_binary_write_metadata
(struct sieve_script *script, struct sieve_binary_block *sblock)
{
	struct sieve_ldap_script *lscript =
		(struct sieve_ldap_script *)script;

	sieve_binary_emit_cstring(sblock, lscript->dn);
	if (lscript->modattr == NULL)
		sieve_binary_emit_cstring(sblock, "");
	else
		sieve_binary_emit_cstring(sblock, lscript->modattr);
}
bool ext_include_variables_save
(struct sieve_binary_block *sblock,
	struct sieve_variable_scope_binary *global_vars)
{
	struct sieve_variable_scope *global_scope =
		sieve_variable_scope_binary_get(global_vars);
	unsigned int count = sieve_variable_scope_size(global_scope);
	sieve_size_t jump;

	sieve_binary_emit_unsigned(sblock, count);

	jump = sieve_binary_emit_offset(sblock, 0);

	if ( count > 0 ) {
		unsigned int size, i;
		struct sieve_variable *const *vars =
			sieve_variable_scope_get_variables(global_scope, &size);

		for ( i = 0; i < size; i++ ) {
			sieve_binary_emit_cstring(sblock, vars[i]->identifier);
		}
	}

	sieve_binary_resolve_offset(sblock, jump);

	return TRUE;
}
static bool ext_ihave_binary_save
(const struct sieve_extension *ext, struct sieve_binary *sbin, void *context)
{
	struct ext_ihave_binary_context *binctx =
		(struct ext_ihave_binary_context *) context;
	const char *const *exts;
	unsigned int count, i;

	exts = array_get(&binctx->missing_extensions, &count);

	if ( binctx->block != NULL )
		sieve_binary_block_clear(binctx->block);

	if ( count > 0 ) {
		if ( binctx->block == NULL )
			binctx->block = sieve_binary_extension_create_block(sbin, ext);

		sieve_binary_emit_unsigned(binctx->block, count);

		for ( i = 0; i < count; i++ ) {
			sieve_binary_emit_cstring(binctx->block, exts[i]);
		}
	}

	return TRUE;
}
static bool _sieve_binary_save
(struct sieve_binary *sbin, struct ostream *stream)
{
	struct sieve_binary_header header;
	struct sieve_binary_extension_reg *const *regs;
	struct sieve_binary_block *ext_block;
	unsigned int ext_count, blk_count, i;
	uoff_t block_index;

	blk_count = sieve_binary_block_count(sbin);

	/* Signal all extensions to finish generating their blocks */

	regs = array_get(&sbin->extensions, &ext_count);
	for ( i = 0; i < ext_count; i++ ) {
		const struct sieve_binary_extension *binext = regs[i]->binext;

		if ( binext != NULL && binext->binary_save != NULL )
			binext->binary_save(regs[i]->extension, sbin, regs[i]->context);
	}

	/* Create header */

	header.magic = SIEVE_BINARY_MAGIC;
	header.version_major = SIEVE_BINARY_VERSION_MAJOR;
	header.version_minor = SIEVE_BINARY_VERSION_MINOR;
	header.blocks = blk_count;

	if ( !_save_aligned(sbin, stream, &header, sizeof(header), NULL) ) {
		sieve_sys_error(sbin->svinst, "binary save: failed to save header");
		return FALSE;
	}

	/* Skip block index for now */

	if ( !_save_skip_aligned(sbin, stream,
		sizeof(struct sieve_binary_block_index) * blk_count, &block_index) )
		return FALSE;

	/* Create block containing all used extensions */

	ext_block = sieve_binary_block_get(sbin, SBIN_SYSBLOCK_EXTENSIONS);
	i_assert( ext_block != NULL );
	sieve_binary_block_clear(ext_block);

	ext_count = array_count(&sbin->linked_extensions);
	sieve_binary_emit_unsigned(ext_block, ext_count);

	for ( i = 0; i < ext_count; i++ ) {
		struct sieve_binary_extension_reg * const *ext
			= array_idx(&sbin->linked_extensions, i);

		sieve_binary_emit_cstring
			(ext_block, sieve_extension_name((*ext)->extension));
		sieve_binary_emit_unsigned
			(ext_block, sieve_extension_version((*ext)->extension));
		sieve_binary_emit_unsigned(ext_block, (*ext)->block_id);
	}

	/* Save all blocks into the binary */

	for ( i = 0; i < blk_count; i++ ) {
		if ( !_save_block(sbin, stream, i) )
			return FALSE;
	}

	/* Create the block index */
	o_stream_seek(stream, block_index);
	for ( i = 0; i < blk_count; i++ ) {
		if ( !_save_block_index_record(sbin, stream, i) )
			return FALSE;
	}

	return TRUE;
}