Commit | Line | Data |
---|---|---|
6a8f9482 TK |
1 | /************************************************* |
2 | * Exim - an Internet mail transport agent * | |
3 | *************************************************/ | |
4 | ||
13a64935 | 5 | /* Copyright (c) Wolfgang Breyha 2005 - 2019 |
6a8f9482 TK |
6 | * Vienna University Computer Center |
7 | * wbreyha@gmx.net | |
b9e94344 | 8 | * See the file NOTICE for conditions of use and distribution. |
80fea873 | 9 | * |
13a64935 | 10 | * Copyright (c) The Exim Maintainers 2015 - 2019 |
6a8f9482 TK |
11 | */ |
12 | ||
6a8f9482 TK |
13 | /* Code for calling dccifd. Called from acl.c. */ |
14 | ||
15 | #include "exim.h" | |
16 | #ifdef EXPERIMENTAL_DCC | |
17 | #include "dcc.h" | |
18 | #include "unistd.h" | |
19 | ||
13a64935 WB |
20 | #define DCC_HEADER_LIMIT 120 |
21 | ||
6a8f9482 TK |
22 | int dcc_ok = 0; |
23 | int dcc_rc = 0; | |
24 | ||
25 | /* This function takes a file descriptor and a buffer as input and | |
26 | * returns either 0 for success or errno in case of error. */ | |
27 | ||
13a64935 WB |
28 | int flushbuffer (int socket, gstring *buffer) |
29 | { | |
6a8f9482 | 30 | int retval, rsp; |
13a64935 | 31 | rsp = write(socket, buffer->s, buffer->ptr); |
6a8f9482 | 32 | DEBUG(D_acl) |
13a64935 WB |
33 | debug_printf("DCC: flushbuffer(): Result of the write() = %d\n", rsp); |
34 | if(rsp < 0) { | |
6a8f9482 | 35 | DEBUG(D_acl) |
13a64935 | 36 | debug_printf("DCC: flushbuffer(): Error writing buffer to socket: %s\n", strerror(errno)); |
6a8f9482 | 37 | retval = errno; |
05c39afa JH |
38 | } |
39 | else { | |
6a8f9482 | 40 | DEBUG(D_acl) |
13a64935 | 41 | debug_printf("DCC: flushbuffer(): Wrote buffer to socket:\n%.*s\n", buffer->ptr, buffer->s); |
6a8f9482 TK |
42 | retval = 0; |
43 | } | |
44 | return retval; | |
45 | } | |
46 | ||
55414b25 JH |
47 | int |
48 | dcc_process(uschar **listptr) | |
49 | { | |
6a8f9482 | 50 | int sep = 0; |
55414b25 | 51 | const uschar *list = *listptr; |
6a8f9482 | 52 | FILE *data_file; |
6a8f9482 | 53 | uschar *dcc_default_ip_option = US"127.0.0.1"; |
6a8f9482 | 54 | uschar *dcc_helo_option = US"localhost"; |
1a9312b2 | 55 | uschar *xtra_hdrs = NULL; |
05c39afa | 56 | uschar *override_client_ip = NULL; |
6a8f9482 TK |
57 | |
58 | /* from local_scan */ | |
13a64935 | 59 | int dcc_resplen, retval, sockfd, resp; |
7156b1ef | 60 | unsigned int portnr; |
6a8f9482 TK |
61 | struct sockaddr_un serv_addr; |
62 | struct sockaddr_in serv_addr_in; | |
63 | struct hostent *ipaddress; | |
64 | uschar sockpath[128]; | |
65 | uschar sockip[40], client_ip[40]; | |
13a64935 WB |
66 | gstring *dcc_headers; |
67 | gstring *sendbuf; | |
68 | uschar *dcc_return_text; | |
69 | struct header_line *mail_headers; | |
6a8f9482 | 70 | uschar *dcc_acl_options; |
13a64935 WB |
71 | gstring *dcc_xtra_hdrs; |
72 | gstring *dcc_header_str; | |
6a8f9482 | 73 | |
6a8f9482 | 74 | /* grep 1st option */ |
13a64935 | 75 | if ((dcc_acl_options = string_nextinlist(&list, &sep, NULL, 0))) { |
6a8f9482 | 76 | /* parse 1st option */ |
dc8091e7 | 77 | if ( strcmpic(dcc_acl_options, US"false") == 0 |
13a64935 | 78 | || Ustrcmp(dcc_acl_options, "0") == 0) |
dc8091e7 | 79 | return FAIL; /* explicitly no matching */ |
13a64935 | 80 | } |
dc8091e7 JH |
81 | else |
82 | return FAIL; /* empty means "don't match anything" */ | |
6a8f9482 TK |
83 | |
84 | sep = 0; | |
85 | ||
86 | /* if we scanned this message last time, just return */ | |
dc8091e7 JH |
87 | if (dcc_ok) |
88 | return dcc_rc; | |
6a8f9482 TK |
89 | |
90 | /* open the spooled body */ | |
13a64935 | 91 | for (int i = 0; i < 2; i++) { |
59a93276 JH |
92 | uschar message_subdir[2]; |
93 | set_subdir_str(message_subdir, message_id, i); | |
41313d92 | 94 | if ((data_file = Ufopen( |
13a64935 | 95 | spool_fname(US"input", message_subdir, message_id, US"-D"), "rb"))) |
6a8f9482 | 96 | break; |
13a64935 | 97 | } |
6a8f9482 | 98 | |
13a64935 | 99 | if (!data_file) { |
6a8f9482 TK |
100 | /* error while spooling */ |
101 | log_write(0, LOG_MAIN|LOG_PANIC, | |
13a64935 | 102 | "DCC: error while opening spool file"); |
6a8f9482 | 103 | return DEFER; |
13a64935 | 104 | } |
6a8f9482 TK |
105 | |
106 | /* Initialize the variables */ | |
107 | ||
108 | bzero(sockip,sizeof(sockip)); | |
109 | if (dccifd_address) { | |
110 | if (dccifd_address[0] == '/') | |
111 | Ustrncpy(sockpath, dccifd_address, sizeof(sockpath)); | |
112 | else | |
7156b1ef | 113 | if( sscanf(CS dccifd_address, "%s %u", sockip, &portnr) != 2) { |
6a8f9482 | 114 | log_write(0, LOG_MAIN, |
13a64935 | 115 | "DCC: warning - invalid dccifd address: '%s'", dccifd_address); |
6a8f9482 TK |
116 | (void)fclose(data_file); |
117 | return DEFER; | |
118 | } | |
119 | } | |
120 | ||
13a64935 | 121 | /* dcc_headers is what we send as dccifd options - see man dccifd */ |
6a8f9482 | 122 | /* We don't support any other option than 'header' so just copy that */ |
13a64935 | 123 | dcc_headers = string_cat(NULL, dccifd_options); |
05c39afa | 124 | /* if $acl_m_dcc_override_client_ip is set use it */ |
94431adb | 125 | if (((override_client_ip = expand_string(US"$acl_m_dcc_override_client_ip")) != NULL) && |
05c39afa JH |
126 | (override_client_ip[0] != '\0')) { |
127 | Ustrncpy(client_ip, override_client_ip, sizeof(client_ip)-1); | |
128 | DEBUG(D_acl) | |
129 | debug_printf("DCC: Client IP (overridden): %s\n", client_ip); | |
94431adb | 130 | } |
05c39afa JH |
131 | else if(sender_host_address) { |
132 | /* else if $sender_host_address is available use that? */ | |
133 | Ustrncpy(client_ip, sender_host_address, sizeof(client_ip)-1); | |
134 | DEBUG(D_acl) | |
135 | debug_printf("DCC: Client IP (sender_host_address): %s\n", client_ip); | |
94431adb | 136 | } |
05c39afa JH |
137 | else { |
138 | /* sender_host_address is NULL which means it comes from localhost */ | |
139 | Ustrncpy(client_ip, dcc_default_ip_option, sizeof(client_ip)-1); | |
140 | DEBUG(D_acl) | |
141 | debug_printf("DCC: Client IP (default): %s\n", client_ip); | |
6a8f9482 | 142 | } |
13a64935 WB |
143 | /* build options block */ |
144 | dcc_headers = string_append(dcc_headers, 5, US"\n", client_ip, US"\nHELO ", dcc_helo_option, US"\n"); | |
6a8f9482 TK |
145 | |
146 | /* initialize the other variables */ | |
13a64935 | 147 | mail_headers = header_list; |
6a8f9482 TK |
148 | /* we set the default return value to DEFER */ |
149 | retval = DEFER; | |
150 | ||
1a9312b2 | 151 | /* send a null return path as "<>". */ |
13a64935 WB |
152 | dcc_headers = string_cat (dcc_headers, *sender_address ? sender_address : US"<>"); |
153 | dcc_headers = string_catn(dcc_headers, US"\n", 1); | |
6a8f9482 TK |
154 | |
155 | /************************************** | |
156 | * Now creating the socket connection * | |
157 | **************************************/ | |
158 | ||
05c39afa | 159 | /* If sockip contains an ip, we use a tcp socket, otherwise a UNIX socket */ |
13a64935 | 160 | if(Ustrcmp(sockip, "")) { |
5903c6ff JH |
161 | ipaddress = gethostbyname(CS sockip); |
162 | bzero(CS &serv_addr_in, sizeof(serv_addr_in)); | |
6a8f9482 | 163 | serv_addr_in.sin_family = AF_INET; |
5903c6ff | 164 | bcopy(CS ipaddress->h_addr, CS &serv_addr_in.sin_addr.s_addr, ipaddress->h_length); |
6a8f9482 | 165 | serv_addr_in.sin_port = htons(portnr); |
13a64935 | 166 | if ((sockfd = socket(AF_INET, SOCK_STREAM,0)) < 0) { |
6a8f9482 | 167 | DEBUG(D_acl) |
2369bf9c GF |
168 | debug_printf("DCC: Creating TCP socket connection failed: %s\n", strerror(errno)); |
169 | log_write(0,LOG_PANIC,"DCC: Creating TCP socket connection failed: %s\n", strerror(errno)); | |
6a8f9482 TK |
170 | /* if we cannot create the socket, defer the mail */ |
171 | (void)fclose(data_file); | |
172 | return retval; | |
173 | } | |
174 | /* Now connecting the socket (INET) */ | |
13a64935 | 175 | if (connect(sockfd, (struct sockaddr *)&serv_addr_in, sizeof(serv_addr_in)) < 0) { |
6a8f9482 | 176 | DEBUG(D_acl) |
2369bf9c GF |
177 | debug_printf("DCC: Connecting to TCP socket failed: %s\n", strerror(errno)); |
178 | log_write(0,LOG_PANIC,"DCC: Connecting to TCP socket failed: %s\n", strerror(errno)); | |
6a8f9482 TK |
179 | /* if we cannot contact the socket, defer the mail */ |
180 | (void)fclose(data_file); | |
181 | return retval; | |
182 | } | |
13a64935 WB |
183 | } |
184 | else { | |
6a8f9482 | 185 | /* connecting to the dccifd UNIX socket */ |
806c3df9 | 186 | bzero(&serv_addr, sizeof(serv_addr)); |
6a8f9482 | 187 | serv_addr.sun_family = AF_UNIX; |
f3ebb786 | 188 | Ustrncpy(US serv_addr.sun_path, sockpath, sizeof(serv_addr.sun_path)); |
13a64935 | 189 | if ((sockfd = socket(AF_UNIX, SOCK_STREAM,0)) < 0) { |
6a8f9482 | 190 | DEBUG(D_acl) |
2369bf9c GF |
191 | debug_printf("DCC: Creating UNIX socket connection failed: %s\n", strerror(errno)); |
192 | log_write(0,LOG_PANIC,"DCC: Creating UNIX socket connection failed: %s\n", strerror(errno)); | |
6a8f9482 TK |
193 | /* if we cannot create the socket, defer the mail */ |
194 | (void)fclose(data_file); | |
195 | return retval; | |
196 | } | |
197 | /* Now connecting the socket (UNIX) */ | |
13a64935 | 198 | if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { |
6a8f9482 | 199 | DEBUG(D_acl) |
13a64935 | 200 | debug_printf("DCC: Connecting to UNIX socket failed: %s\n", strerror(errno)); |
2369bf9c | 201 | log_write(0,LOG_PANIC,"DCC: Connecting to UNIX socket failed: %s\n", strerror(errno)); |
6a8f9482 TK |
202 | /* if we cannot contact the socket, defer the mail */ |
203 | (void)fclose(data_file); | |
204 | return retval; | |
205 | } | |
206 | } | |
207 | /* the socket is open, now send the options to dccifd*/ | |
208 | DEBUG(D_acl) | |
13a64935 WB |
209 | debug_printf("DCC: -----------------------------------\nDCC: Socket opened; now sending input\n" |
210 | "DCC: -----------------------------------\n"); | |
6a8f9482 TK |
211 | |
212 | /* let's send each of the recipients to dccifd */ | |
13a64935 | 213 | for (int i = 0; i < recipients_count; i++) { |
6a8f9482 | 214 | DEBUG(D_acl) |
2369bf9c | 215 | debug_printf("DCC: recipient = %s\n",recipients_list[i].address); |
13a64935 | 216 | dcc_headers = string_append(dcc_headers, 2, recipients_list[i].address, "\n"); |
6a8f9482 TK |
217 | } |
218 | /* send a blank line between options and message */ | |
13a64935 | 219 | dcc_headers = string_catn(dcc_headers, US"\n", 1); |
6a8f9482 | 220 | /* Now we send the input buffer */ |
13a64935 | 221 | (void) string_from_gstring(dcc_headers); |
6a8f9482 | 222 | DEBUG(D_acl) |
13a64935 WB |
223 | debug_printf("DCC: ***********************************\nDCC: Sending options:\n%s" |
224 | "DCC: ***********************************\n", dcc_headers->s); | |
225 | if (flushbuffer(sockfd, dcc_headers) != 0) { | |
226 | (void)fclose(data_file); | |
227 | return retval; | |
228 | } | |
6a8f9482 TK |
229 | |
230 | /* now send the message */ | |
6a8f9482 | 231 | /* First send the headers */ |
6a8f9482 | 232 | DEBUG(D_acl) |
13a64935 WB |
233 | debug_printf("DCC: ***********************************\nDCC: Sending headers:\n"); |
234 | sendbuf = string_get(8192); | |
235 | sendbuf = string_catn(sendbuf, mail_headers->text, mail_headers->slen); | |
236 | while((mail_headers=mail_headers->next)) { | |
237 | sendbuf = string_catn(sendbuf, mail_headers->text, mail_headers->slen); | |
6a8f9482 TK |
238 | } |
239 | ||
4c04137d | 240 | /* a blank line separates header from body */ |
13a64935 WB |
241 | sendbuf = string_catn(sendbuf, US"\r\n", 2); |
242 | (void) string_from_gstring(sendbuf); | |
243 | gstring_release_unused(sendbuf); | |
6a8f9482 | 244 | DEBUG(D_acl) |
13a64935 WB |
245 | debug_printf("%sDCC: ***********************************\n", sendbuf->s); |
246 | if (flushbuffer(sockfd, sendbuf) != 0) { | |
247 | (void)fclose(data_file); | |
248 | return retval; | |
249 | } | |
6a8f9482 TK |
250 | |
251 | /* now send the body */ | |
252 | DEBUG(D_acl) | |
13a64935 | 253 | debug_printf("DCC: ***********************************\nDCC: Writing body:\n"); |
6a8f9482 | 254 | (void)fseek(data_file, SPOOL_DATA_START_OFFSET, SEEK_SET); |
13a64935 WB |
255 | |
256 | gstring filebuf = { .size = big_buffer_size, .ptr = 0, .s = big_buffer }; | |
257 | ||
258 | while((filebuf.ptr = fread(filebuf.s, 1, filebuf.size, data_file)) > 0) { | |
259 | if (flushbuffer(sockfd, &filebuf) != 0) { | |
260 | (void)fclose(data_file); | |
261 | return retval; | |
262 | } | |
6a8f9482 TK |
263 | } |
264 | DEBUG(D_acl) | |
13a64935 | 265 | debug_printf("DCC: ***********************************\n"); |
6a8f9482 TK |
266 | |
267 | /* shutdown() the socket */ | |
13a64935 | 268 | if(shutdown(sockfd, SHUT_WR) < 0) { |
6a8f9482 | 269 | DEBUG(D_acl) |
2369bf9c GF |
270 | debug_printf("DCC: Couldn't shutdown socket: %s\n", strerror(errno)); |
271 | log_write(0,LOG_MAIN,"DCC: Couldn't shutdown socket: %s\n", strerror(errno)); | |
6a8f9482 TK |
272 | /* If there is a problem with the shutdown() |
273 | * defer the mail. */ | |
274 | (void)fclose(data_file); | |
275 | return retval; | |
276 | } | |
277 | DEBUG(D_acl) | |
13a64935 WB |
278 | debug_printf("DCC: Input sent.\n" |
279 | "DCC: +++++++++++++++++++++++++++++++++++\n" | |
280 | "DCC: Now receiving output from server\n" | |
281 | "DCC: -----------------------------------\n"); | |
6a8f9482 | 282 | |
13a64935 | 283 | /******************************** |
6a8f9482 TK |
284 | * receiving output from dccifd * |
285 | ********************************/ | |
6a8f9482 TK |
286 | |
287 | /****************************************************************** | |
288 | * We should get 3 lines: * | |
289 | * 1/ First line is overall result: either 'A' for Accept, * | |
290 | * 'R' for Reject, 'S' for accept Some recipients or * | |
291 | * 'T' for a Temporary error. * | |
292 | * 2/ Second line contains the list of Accepted/Rejected * | |
293 | * recipients in the form AARRA (A = accepted, R = rejected). * | |
294 | * 3/ Third line contains the X-DCC header. * | |
295 | ******************************************************************/ | |
296 | ||
13a64935 WB |
297 | int line = 1; /* we start at the first line of the output */ |
298 | int bufoffset; | |
6a8f9482 | 299 | |
13a64935 | 300 | dcc_header_str = string_get(DCC_HEADER_LIMIT + 2); |
6a8f9482 | 301 | /* Let's read from the socket until there's nothing left to read */ |
13a64935 WB |
302 | while((dcc_resplen = read(sockfd, big_buffer, big_buffer_size-1)) > 0) { |
303 | /* fail on read error */ | |
304 | if(dcc_resplen < 0) { | |
305 | DEBUG(D_acl) | |
306 | debug_printf("DCC: Error reading from socket: %s\n", strerror(errno)); | |
307 | (void)fclose(data_file); | |
308 | return retval; | |
309 | } | |
310 | /* make the answer 0-terminated. only needed for debug_printf */ | |
6a8f9482 | 311 | DEBUG(D_acl) |
13a64935 WB |
312 | debug_printf("DCC: Length of the output buffer is: %d\nDCC: Output buffer is:\n" |
313 | "DCC: -----------------------------------\n%.*s\n" | |
314 | "DCC: -----------------------------------\n", dcc_resplen, dcc_resplen, big_buffer); | |
6a8f9482 TK |
315 | |
316 | /* Now let's read each character and see what we've got */ | |
13a64935 | 317 | for(bufoffset = 0; bufoffset < dcc_resplen, line <= 2; bufoffset++) { |
6a8f9482 TK |
318 | /* First check if we reached the end of the line and |
319 | * then increment the line counter */ | |
13a64935 | 320 | if(big_buffer[bufoffset] == '\n') |
6a8f9482 | 321 | line++; |
6a8f9482 TK |
322 | else { |
323 | /* The first character of the first line is the | |
324 | * overall response. If there's another character | |
325 | * on that line it is not correct. */ | |
326 | if(line == 1) { | |
13a64935 | 327 | if(bufoffset == 0) { |
6a8f9482 TK |
328 | /* Now get the value and set the |
329 | * return value accordingly */ | |
13a64935 WB |
330 | switch(big_buffer[bufoffset]) { |
331 | case 'A': | |
332 | DEBUG(D_acl) | |
333 | debug_printf("DCC: Overall result = A\treturning OK\n"); | |
334 | dcc_return_text = US"Mail accepted by DCC"; | |
335 | dcc_result = US"A"; | |
336 | retval = OK; | |
337 | break; | |
338 | case 'R': | |
339 | DEBUG(D_acl) | |
340 | debug_printf("DCC: Overall result = R\treturning FAIL\n"); | |
341 | dcc_return_text = US"Rejected by DCC"; | |
342 | dcc_result = US"R"; | |
343 | retval = FAIL; | |
344 | if(sender_host_name) | |
345 | log_write(0, LOG_MAIN, "H=%s [%s] F=<%s>: rejected by DCC", | |
346 | sender_host_name, sender_host_address, sender_address); | |
347 | else | |
348 | log_write(0, LOG_MAIN, "H=[%s] F=<%s>: rejected by DCC", | |
349 | sender_host_address, sender_address); | |
350 | break; | |
351 | case 'S': | |
352 | DEBUG(D_acl) | |
353 | debug_printf("DCC: Overall result = S\treturning OK\n"); | |
354 | dcc_return_text = US"Not all recipients accepted by DCC"; | |
355 | /* Since we're in an ACL we want a global result | |
356 | * so we accept for all */ | |
357 | dcc_result = US"A"; | |
358 | retval = OK; | |
359 | break; | |
360 | case 'G': | |
361 | DEBUG(D_acl) | |
362 | debug_printf("DCC: Overall result = G\treturning FAIL\n"); | |
363 | dcc_return_text = US"Greylisted by DCC"; | |
364 | dcc_result = US"G"; | |
365 | retval = FAIL; | |
366 | break; | |
367 | case 'T': | |
368 | DEBUG(D_acl) | |
369 | debug_printf("DCC: Overall result = T\treturning DEFER\n"); | |
370 | dcc_return_text = US"Temporary error with DCC"; | |
371 | dcc_result = US"T"; | |
372 | retval = DEFER; | |
373 | log_write(0,LOG_MAIN,"Temporary error with DCC: %s\n", big_buffer); | |
374 | break; | |
375 | default: | |
376 | DEBUG(D_acl) | |
377 | debug_printf("DCC: Overall result = something else\treturning DEFER\n"); | |
378 | dcc_return_text = US"Unknown DCC response"; | |
379 | dcc_result = US"T"; | |
380 | retval = DEFER; | |
381 | log_write(0,LOG_MAIN,"Unknown DCC response: %s\n", big_buffer); | |
382 | break; | |
6a8f9482 TK |
383 | } |
384 | } | |
385 | else { | |
96f5fe4c JH |
386 | /* We're on the first line but not on the first character, |
387 | * there must be something wrong. */ | |
13a64935 WB |
388 | DEBUG(D_acl) debug_printf("DCC: Line = %d but bufoffset = %d != 0" |
389 | " character is %c - This is wrong!\n", line, bufoffset, big_buffer[bufoffset]); | |
390 | log_write(0,LOG_MAIN,"Wrong header from DCC, output is %s\n", big_buffer); | |
6a8f9482 TK |
391 | } |
392 | } | |
393 | else if(line == 2) { | |
394 | /* On the second line we get a list of | |
7390e768 PP |
395 | * answers for each recipient. We don't care about |
396 | * it because we're in an acl and take the | |
1a9312b2 | 397 | * global result. */ |
6a8f9482 | 398 | } |
6a8f9482 TK |
399 | } |
400 | } | |
13a64935 WB |
401 | if(line > 2) { |
402 | /* The third and following lines are the X-DCC header, | |
403 | * so we store it in dcc_header_str up to our limit. */ | |
404 | /* check if buffer contains the end of the header .."\n\n" and truncate it */ | |
405 | if ((big_buffer[dcc_resplen-1] == '\n') && | |
406 | (big_buffer[dcc_resplen-2] == '\n')) | |
407 | dcc_resplen -= 2; | |
408 | dcc_resplen -= bufoffset; | |
409 | if (dcc_header_str->ptr + dcc_resplen > DCC_HEADER_LIMIT) { | |
410 | dcc_resplen = DCC_HEADER_LIMIT - dcc_header_str->ptr; | |
411 | DEBUG(D_acl) debug_printf("DCC: We got more output than we can store" | |
412 | "in the X-DCC header. Truncating at 120 characters.\n"); | |
413 | } | |
414 | dcc_header_str = string_catn(dcc_header_str, &big_buffer[bufoffset], dcc_resplen); | |
415 | } | |
6a8f9482 | 416 | } |
13a64935 WB |
417 | /* We have read everything from the socket. make sure the header ends with "\n" */ |
418 | dcc_header_str = string_catn(dcc_header_str, US"\n", 1); | |
6a8f9482 | 419 | |
13a64935 | 420 | (void) string_from_gstring(dcc_header_str); |
6a8f9482 TK |
421 | /* Now let's sum up what we've got. */ |
422 | DEBUG(D_acl) | |
13a64935 WB |
423 | debug_printf("\nDCC: --------------------------\nDCC: Overall result = %d\n" |
424 | "DCC: X-DCC header: %sReturn message: %s\nDCC: dcc_result: %s\n", | |
425 | retval, dcc_header_str->s, dcc_return_text, dcc_result); | |
6a8f9482 TK |
426 | |
427 | /* We only add the X-DCC header if it starts with X-DCC */ | |
13a64935 WB |
428 | if(!(Ustrncmp(dcc_header_str->s, "X-DCC", 5))) { |
429 | dcc_header = dcc_header_str->s; | |
6a8f9482 | 430 | if(dcc_direct_add_header) { |
13a64935 | 431 | header_add(' ' , "%s", dcc_header_str->s); |
1a9312b2 | 432 | /* since the MIME ACL already writes the .eml file to disk without DCC Header we've to erase it */ |
6a8f9482 TK |
433 | unspool_mbox(); |
434 | } | |
435 | } | |
436 | else { | |
437 | DEBUG(D_acl) | |
13a64935 | 438 | debug_printf("DCC: Wrong format of the X-DCC header: %.*s\n", dcc_header_str->ptr, dcc_header_str->s); |
6a8f9482 TK |
439 | } |
440 | ||
1a9312b2 TK |
441 | /* check if we should add additional headers passed in acl_m_dcc_add_header */ |
442 | if(dcc_direct_add_header) { | |
7156b1ef | 443 | if (((xtra_hdrs = expand_string(US"$acl_m_dcc_add_header")) != NULL) && (xtra_hdrs[0] != '\0')) { |
13a64935 WB |
444 | dcc_xtra_hdrs = string_cat(NULL, xtra_hdrs); |
445 | if (dcc_xtra_hdrs->s[dcc_xtra_hdrs->ptr - 1] != '\n') | |
446 | dcc_xtra_hdrs = string_catn(dcc_xtra_hdrs, US"\n", 1); | |
447 | header_add(' ', "%s", string_from_gstring(dcc_xtra_hdrs)); | |
1a9312b2 | 448 | DEBUG(D_acl) |
13a64935 | 449 | debug_printf("DCC: adding additional headers in $acl_m_dcc_add_header: %.*s", dcc_xtra_hdrs->ptr, dcc_xtra_hdrs->s); |
1a9312b2 TK |
450 | } |
451 | } | |
452 | ||
6a8f9482 TK |
453 | dcc_ok = 1; |
454 | /* Now return to exim main process */ | |
455 | DEBUG(D_acl) | |
13a64935 WB |
456 | debug_printf("DCC: Before returning to exim main process:\nDCC: return_text = %s - retval = %d\n" |
457 | "DCC: dcc_result = %s\n", dcc_return_text, retval, dcc_result); | |
6a8f9482 TK |
458 | |
459 | (void)fclose(data_file); | |
6f0c431a PP |
460 | dcc_rc = retval; |
461 | return dcc_rc; | |
6a8f9482 TK |
462 | } |
463 | ||
464 | #endif |