tidying: coverity issues
[exim.git] / src / src / spool_mbox.c
CommitLineData
8523533c
TK
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
3386088d 5/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003 - 2015 */
8523533c
TK
6/* License: GPL */
7
8/* Code for setting up a MBOX style spool file inside a /scan/<msgid>
9sub directory of exim's spool directory. */
10
11#include "exim.h"
12#ifdef WITH_CONTENT_SCAN
13
14/* externals, we must reset them on unspooling */
15#ifdef WITH_OLD_DEMIME
16extern int demime_ok;
17extern struct file_extension *file_extensions;
18#endif
19
20extern int malware_ok;
21extern int spam_ok;
22
23int spool_mbox_ok = 0;
6e3b198d 24uschar spooled_message_id[MESSAGE_ID_LENGTH+1];
8523533c 25
8544e77a
PP
26/* returns a pointer to the FILE, and puts the size in bytes into mbox_file_size
27 * normally, source_file_override is NULL */
8523533c 28
0f0c8159
JH
29FILE *
30spool_mbox(unsigned long *mbox_file_size, const uschar *source_file_override)
31{
3c51463e
JH
32uschar message_subdir[2];
33uschar buffer[16384];
34uschar *temp_string;
35uschar *mbox_path;
36FILE *mbox_file = NULL;
37FILE *data_file = NULL;
38FILE *yield = NULL;
39header_line *my_headerlist;
40struct stat statbuf;
41int i, j;
42void *reset_point = store_get(0);
43
44mbox_path = string_sprintf("%s/scan/%s/%s.eml", spool_directory, message_id,
45 message_id);
46
47/* Skip creation if already spooled out as mbox file */
48if (!spool_mbox_ok)
49 {
50 /* create temp directory inside scan dir, directory_make works recursively */
51 temp_string = string_sprintf("scan/%s", message_id);
52 if (!directory_make(spool_directory, temp_string, 0750, FALSE))
53 {
54 log_write(0, LOG_MAIN|LOG_PANIC, "%s", string_open_failed(errno,
55 "scan directory %s/scan/%s", spool_directory, temp_string));
56 goto OUT;
57 }
8e669ac1 58
3c51463e
JH
59 /* open [message_id].eml file for writing */
60 mbox_file = modefopen(mbox_path, "wb", SPOOL_MODE);
61 if (mbox_file == NULL)
62 {
63 log_write(0, LOG_MAIN|LOG_PANIC, "%s", string_open_failed(errno,
64 "scan file %s", mbox_path));
65 goto OUT;
66 }
67
68 /* Generate mailbox headers. The $received_for variable is (up to at least
69 Exim 4.64) never set here, because it is only set when expanding the
70 contents of the Received: header line. However, the code below will use it
71 if it should become available in future. */
72
73 temp_string = expand_string(
74 US"From ${if def:return_path{$return_path}{MAILER-DAEMON}} ${tod_bsdinbox}\n"
75 "${if def:sender_address{X-Envelope-From: <${sender_address}>\n}}"
76 "${if def:recipients{X-Envelope-To: ${recipients}\n}}");
77
78 if (temp_string != NULL)
f951fd57 79 {
3c51463e
JH
80 i = fwrite(temp_string, Ustrlen(temp_string), 1, mbox_file);
81 if (i != 1)
82 {
1ac6b2e7 83 log_write(0, LOG_MAIN|LOG_PANIC, "Error/short write while writing \
3c51463e 84 mailbox headers to %s", mbox_path);
1ac6b2e7 85 goto OUT;
3c51463e 86 }
1ac6b2e7 87 }
f951fd57 88
3c51463e
JH
89 /* write all header lines to mbox file */
90 my_headerlist = header_list;
91 for (my_headerlist = header_list; my_headerlist != NULL;
92 my_headerlist = my_headerlist->next)
93 {
94 /* skip deleted headers */
95 if (my_headerlist->type == '*') continue;
96
97 i = fwrite(my_headerlist->text, my_headerlist->slen, 1, mbox_file);
98 if (i != 1)
99 {
100 log_write(0, LOG_MAIN|LOG_PANIC, "Error/short write while writing \
101 message headers to %s", mbox_path);
f951fd57 102 goto OUT;
3c51463e
JH
103 }
104 }
8e669ac1 105
3c51463e
JH
106 /* End headers */
107 if (fwrite("\n", 1, 1, mbox_file) != 1)
108 {
109 log_write(0, LOG_MAIN|LOG_PANIC, "Error/short write while writing \
110 message headers to %s", mbox_path);
111 goto OUT;
112 }
21a04aa3 113
3c51463e
JH
114 /* copy body file */
115 if (source_file_override == NULL)
116 {
117 message_subdir[1] = '\0';
118 for (i = 0; i < 2; i++)
119 {
120 message_subdir[0] = (split_spool_directory == (i == 0))? message_id[5] : 0;
121 temp_string = string_sprintf("%s/input/%s/%s-D", spool_directory,
122 message_subdir, message_id);
123 data_file = Ufopen(temp_string, "rb");
124 if (data_file != NULL) break;
125 }
126 }
127 else
128 data_file = Ufopen(source_file_override, "rb");
8523533c 129
3c51463e
JH
130 if (data_file == NULL)
131 {
132 log_write(0, LOG_MAIN|LOG_PANIC, "Could not open datafile for message %s",
133 message_id);
f951fd57 134 goto OUT;
3c51463e
JH
135 }
136
137 /* The code used to use this line, but it doesn't work in Cygwin.
8523533c 138
3c51463e
JH
139 (void)fread(data_buffer, 1, 18, data_file);
140
141 What's happening is that spool_mbox used to use an fread to jump over the
142 file header. That fails under Cygwin because the header is locked, but
143 doing an fseek succeeds. We have to output the leading newline
144 explicitly, because the one in the file is parted of the locked area. */
8523533c 145
3c51463e
JH
146 if (!source_file_override)
147 (void)fseek(data_file, SPOOL_DATA_START_OFFSET, SEEK_SET);
148
149 do
150 {
151 j = fread(buffer, 1, sizeof(buffer), data_file);
152
153 if (j > 0)
154 {
155 i = fwrite(buffer, j, 1, mbox_file);
156 if (i != 1)
157 {
158 log_write(0, LOG_MAIN|LOG_PANIC, "Error/short write while writing \
159 message body to %s", mbox_path);
160 goto OUT;
161 }
162 }
163 } while (j > 0);
164
165 (void)fclose(mbox_file);
166 mbox_file = NULL;
167
8d468c4c
JH
168 Ustrncpy(spooled_message_id, message_id, sizeof(spooled_message_id));
169 spooled_message_id[sizeof(spooled_message_id)-1] = '\0';
3c51463e
JH
170 spool_mbox_ok = 1;
171 }
172
173/* get the size of the mbox message and open [message_id].eml file for reading*/
174if (Ustat(mbox_path, &statbuf) != 0 ||
175 (yield = Ufopen(mbox_path,"rb")) == NULL)
176 {
177 log_write(0, LOG_MAIN|LOG_PANIC, "%s", string_open_failed(errno,
178 "scan file %s", mbox_path));
179 goto OUT;
180 }
181
182*mbox_file_size = statbuf.st_size;
183
184OUT:
185if (data_file) (void)fclose(data_file);
186if (mbox_file) (void)fclose(mbox_file);
187store_reset(reset_point);
188return yield;
8523533c
TK
189}
190
3c51463e
JH
191
192
193
8523533c 194/* remove mbox spool file, demimed files and temp directory */
8e669ac1 195
3c51463e
JH
196void
197unspool_mbox(void)
198{
199
200/* reset all exiscan state variables */
201#ifdef WITH_OLD_DEMIME
202demime_ok = 0;
203demime_errorlevel = 0;
204demime_reason = NULL;
205file_extensions = NULL;
206#endif
8e669ac1 207
3c51463e
JH
208spam_ok = 0;
209malware_ok = 0;
8e669ac1 210
3c51463e
JH
211if (spool_mbox_ok && !no_mbox_unspool)
212 {
213 uschar *mbox_path;
214 uschar *file_path;
215 int n;
216 struct dirent *entry;
217 DIR *tempdir;
218
219 mbox_path = string_sprintf("%s/scan/%s", spool_directory, spooled_message_id);
220
221 tempdir = opendir(CS mbox_path);
222 if (!tempdir)
223 {
224 debug_printf("Unable to opendir(%s): %s\n", mbox_path, strerror(errno));
225 /* Just in case we still can: */
f951fd57 226 rmdir(CS mbox_path);
3c51463e
JH
227 return;
228 }
229 /* loop thru dir & delete entries */
230 while((entry = readdir(tempdir)) != NULL)
231 {
232 uschar *name = US entry->d_name;
233 if (Ustrcmp(name, US".") == 0 || Ustrcmp(name, US"..") == 0) continue;
234
235 file_path = string_sprintf("%s/%s", mbox_path, name);
236 debug_printf("unspool_mbox(): unlinking '%s'\n", file_path);
237 n = unlink(CS file_path);
238 }
239
240 closedir(tempdir);
241
242 /* remove directory */
243 rmdir(CS mbox_path);
244 store_reset(mbox_path);
245 }
246spool_mbox_ok = 0;
8523533c
TK
247}
248
249#endif