summaryrefslogtreecommitdiffstats
path: root/pigeonhole/src/sieve-tools/sievec.c
blob: d70435dca5e04ec93deb61b51d7e3b21bb704e10 (plain)
1
2
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
 */

#include "lib.h"
#include "array.h"
#include "master-service.h"
#include "master-service-settings.h"
#include "mail-storage-service.h"
#include "mail-user.h"

#include "sieve.h"
#include "sieve-extensions.h"
#include "sieve-script.h"
#include "sieve-tool.h"

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <dirent.h>
#include <sysexits.h>

/*
 * Print help
 */

static void print_help(void)
{
	printf(
"Usage: sievec  [-c <config-file>] [-d] [-D] [-P <plugin>] [-x <extensions>] \n"
"              <script-file> [<out-file>]\n"
	);
}

/*
 * Tool implementation
 */

int main(int argc, char **argv)
{
	struct sieve_instance *svinst;
	struct stat st;
	struct sieve_binary *sbin;
	bool dump = FALSE;
	const char *scriptfile, *outfile;
	int exit_status = EXIT_SUCCESS;
	int c;

	sieve_tool = sieve_tool_init("sievec", &argc, &argv, "DdP:x:u:", FALSE);

	outfile = NULL;
	while ((c = sieve_tool_getopt(sieve_tool)) > 0) {
		switch (c) {
		case 'd':
			/* dump file */
			dump = TRUE;
			break;
		default:
			print_help();
			i_fatal_status(EX_USAGE, "Unknown argument: %c", c);
			break;
		}
	}

	if ( optind < argc ) {
		scriptfile = argv[optind++];
	} else {
		print_help();
		i_fatal_status(EX_USAGE, "Missing <script-file> argument");
	}

	if ( optind < argc ) {
		outfile = argv[optind++];
	} else if ( dump ) {
		outfile = "-";
	}

	svinst = sieve_tool_init_finish(sieve_tool, FALSE, TRUE);

	/* Enable debug extension */
	sieve_enable_debug_extension(svinst);

	if ( stat(scriptfile, &st) == 0 && S_ISDIR(st.st_mode) ) {
		/* Script directory */
		DIR *dirp;
		struct dirent *dp;

		/* Sanity checks on some of the arguments */

		if ( dump )
			i_fatal_status(EX_USAGE,
				"the -d option is not allowed when scriptfile is a directory.");

		if ( outfile != NULL )
			i_fatal_status(EX_USAGE,
				"the outfile argument is not allowed when scriptfile is a directory.");

		/* Open the directory */
		if ( (dirp = opendir(scriptfile)) == NULL )
			i_fatal("opendir(%s) failed: %m", scriptfile);

		/* Compile each sieve file */
		for (;;) {

			errno = 0;
			if ( (dp = readdir(dirp)) == NULL ) {
				if ( errno != 0 )
					i_fatal("readdir(%s) failed: %m", scriptfile);
				break;
			}

			if ( sieve_script_file_has_extension(dp->d_name) ) {
				const char *file;

				if ( scriptfile[strlen(scriptfile)-1] == '/' )
					file = t_strconcat(scriptfile, dp->d_name, NULL);
				else
					file = t_strconcat(scriptfile, "/", dp->d_name, NULL);

				sbin = sieve_tool_script_compile(svinst, file, NULL);

				if ( sbin != NULL ) {
					sieve_save(sbin, TRUE, NULL);
					sieve_close(&sbin);
				}
			}
		}

		/* Close the directory */
		if ( closedir(dirp) < 0 )
			i_fatal("closedir(%s) failed: %m", scriptfile);
	} else {
		/* Script file (i.e. not a directory)
		 *
		 *   NOTE: For consistency, stat errors are handled here as well
		 */
		sbin = sieve_tool_script_compile(svinst, scriptfile, NULL);

		if ( sbin != NULL ) {
			if ( dump )
				sieve_tool_dump_binary_to(sbin, outfile, FALSE);
			else {	
				sieve_save_as(sbin, outfile, TRUE, 0600, NULL);
			}

			sieve_close(&sbin);
		} else {
			exit_status = EXIT_FAILURE;
		}
	}

	sieve_tool_deinit(&sieve_tool);

	return exit_status;
}