diff options
author | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2017-11-19 21:43:52 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-11-19 21:43:52 +0000 |
commit | f7001fb675da1d3588c6731dd705d1175a6c62c9 (patch) | |
tree | 8f9586ebc32b03f172db38feeef267420e5d2840 | |
parent | d9d76b801cb8578867785054adf4234d808fcca2 (diff) | |
parent | 8697fdc0fa9681c7953d2b8421892de8b658ad0c (diff) | |
download | rspamd-f7001fb675da1d3588c6731dd705d1175a6c62c9.tar.gz rspamd-f7001fb675da1d3588c6731dd705d1175a6c62c9.zip |
Merge pull request #1913 from AlexeySa/master
Dlfunc library for Exim
-rw-r--r-- | contrib/exim/dlfunc-json/README | 10 | ||||
-rw-r--r-- | contrib/exim/dlfunc-json/exim-example.txt | 75 | ||||
-rw-r--r-- | contrib/exim/dlfunc-json/rspamd.c | 506 |
3 files changed, 591 insertions, 0 deletions
diff --git a/contrib/exim/dlfunc-json/README b/contrib/exim/dlfunc-json/README new file mode 100644 index 000000000..0e522707a --- /dev/null +++ b/contrib/exim/dlfunc-json/README @@ -0,0 +1,10 @@ +FEATURES +1) Support new http-protocol (/checkv2) +2) Return action, symbols, symbol options, messages, scan time + +INSTALL + +1) Get cJSON.c, cJSON.h, put to dlfunc src dir (https://github.com/DaveGamble/cJSON) +2) Compile dlfunc library: + cc rspamd.c -fPIC -fpic -shared -I/root/rpmbuild/BUILD/exim-4.89/build-Linux-x86_64/ -o exim-rspamd-http-dlfunc.so +3) See exim-example.txt for exim configure diff --git a/contrib/exim/dlfunc-json/exim-example.txt b/contrib/exim/dlfunc-json/exim-example.txt new file mode 100644 index 000000000..e6da3346f --- /dev/null +++ b/contrib/exim/dlfunc-json/exim-example.txt @@ -0,0 +1,75 @@ +acl_smtp_data = acl_check_data + +..... + +acl_check_data: + +..... + +# RSPAMD: START + warn + !authenticated = * + add_header = X-Spam-Checker-Version: Rspamd + add_header = :at_start:Authentication-Results: ip=$sender_host_address:$sender_host_port, host=$sender_host_name, helo=$sender_helo_name, mailfrom=$sender_address + warn + #spam = nobody:true + #set acl_m0_rspamd = $spam_report + set acl_m0_rspamd = ${dlfunc{/usr/local/libexec/exim/exim-rspamd-http-dlfunc.so}{rspamd}{/var/run/rspamd/rspamd.sock}{defer_ok}} + accept + authenticated = * + warn + condition = ${if eq{$acl_m0_rspamd}{}} + logwrite = RSPAMD check failed + add_header = X-Spam-Info: Check failed + warn + condition = ${if match{$acl_m0_rspamd}{\N^rspamd dlfunc:\s*\N}{yes}{no}} + logwrite = RSPAMD check defer: ${sg{$acl_m0_rspamd}{\N^rspamd dlfunc:\s*\N}{}} + add_header = X-Spam-Info: Check deffered + + warn + remove_header = X-Spam-Checker-Version:X-Spam-Status:X-Spam-Info:X-Spam-Result + set acl_m1 = No + warn + condition = ${if !eq{$acl_m0_rspamd}{}} + set acl_m1_yesno = ${if match{$acl_m0_rspamd}{\NAction: (.+?)\n\N}{$1}{}} + set acl_m2_status = ${if eq{$acl_m1_yesno}{reject}{REJECT}{\ + ${if eq{$acl_m1_yesno}{add header}{PROBABLY}{\ + ${if eq{$acl_m1_yesno}{rewrite subject}{PROBABLY}{\ + ${if eq{$acl_m1_yesno}{soft reject}{SOFT}{\ + ${if eq{$acl_m1_yesno}{greylist}{GREYLIST}{NO}}\ + }}\ + }}\ + }}\ + }} + set acl_m1_yesno = ${if eq{$acl_m1_yesno}{}{unknown}{\ + ${if eq{$acl_m1_yesno}{reject}{Yes}{\ + ${if eq{$acl_m1_yesno}{add header}{Yes}{\ + ${if eq{$acl_m1_yesno}{rewrite subject}{Yes}{\ + ${if eq{$acl_m1_yesno}{soft reject}{Probably}{\ + ${if eq{$acl_m1_yesno}{greylist}{Probably}{No}}\ + }}\ + }}\ + }}\ + }}\ + }} + #logwrite = RSPAMD: status: $acl_m2_status + #logwrite = RSPAMD DEBUG: $acl_m0_rspamd + set acl_m0_rspamd = ${sg{$acl_m0_rspamd}{ Action:.+\n}{}} + warn + condition = ${if !eq{$acl_m0_rspamd}{}} + logwrite = RSPAMD: $acl_m2_status, $acl_m0_rspamd + add_header = X-Spam-Result: $acl_m0_rspamd + add_header = X-Spam-Status: $acl_m1_yesno + defer + condition = ${if eq{$acl_m2_status}{GREYLIST}} + log_message = Rspamd $acl_m2_status + message = Try again later. Message greylisted + defer + condition = ${if eq{$acl_m2_status}{SOFT}} + log_message = Rspamd $acl_m2_status + message = Try again later. Message previously greylisted + deny + condition = ${if eq{$acl_m2_status}{REJECT}} + log_message = Rspamd $acl_m2_status + message = This message detected as SPAM and rejected +# RSPAMD: END diff --git a/contrib/exim/dlfunc-json/rspamd.c b/contrib/exim/dlfunc-json/rspamd.c new file mode 100644 index 000000000..0f2ab082f --- /dev/null +++ b/contrib/exim/dlfunc-json/rspamd.c @@ -0,0 +1,506 @@ +/* +Copyright (c) 2013-2015, Alexey Savelyev <info@homeweb.ru> +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Based on source code from http://www.ols.es/exim/dlext/ by David Saez <david@ols.es>, +source code of exim by Philip Hazel <ph10@cam.ac.uk> +and source code of exiscan by Tom Kistner <tom@duncanthrax.net> +and source code of Victor Ustugov http://mta.org.ua/ +*/ + +#include "exim.h" + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <stdarg.h> +#include <errno.h> +#include "cJSON.h" +#include "cJSON.c" + +#define RSPAMD_TIMEOUT 120 + +extern uschar *tod_stamp(int); +//extern BOOL split_spool_directory; /* TRUE to use multiple subdirs */ +//extern uschar *spool_directory; /* Name of spool directory */ +//extern uschar message_subdir[]; /* Subdirectory for messages */ + +//------------------------------------------------------------------------- + +int strpos(char *hay, char *needle, int offset) +{ + char haystack[strlen(hay)]; + strncpy(haystack, hay+offset, strlen(hay)-offset); + char *p = strstr(haystack, needle); + if (p) + return p - haystack+offset; + return -1; +} + +int rspamd(uschar **yield, int argc, uschar *argv[]) { + char *arg_socket_addr; + char *arg_defer_ok; + int defer_ok; + int rspamd_command; + char tcp_addr[15]; + int tcp_port; + FILE *mbox_file = NULL; +// unsigned long mbox_size; + off_t mbox_size; + uschar *s, *p; + header_line *my_header, *header_new, *header_last, *tmp_headerlist; + header_line *last_received = NULL; + uschar *address; + uschar *helo; + uschar *sender_host_name; + uschar *authenticated_id; + char mbox_path[512]; + int max_len, len; + int rspamd_sock = 0; + struct hostent *he; + struct in_addr in; + struct sockaddr_un server; +#ifndef NO_POLL_H + int result; + struct pollfd pollfd; +#endif + int offset; + uschar spamd_buffer[32600]; + uschar spamd_buffer2[32600]; + time_t start; + size_t read, wrote; + int i, j, c; + + arg_socket_addr = argv[0]; + arg_defer_ok = argv[1]; + + if (argc < 2) { + defer_ok = 0; + } else if ( + (strcmpic(arg_defer_ok,US"1") == 0) + || (strcmpic(arg_defer_ok,US"yes") == 0) + || (strcmpic(arg_defer_ok,US"true") == 0) + || (strcmpic(arg_defer_ok,US"defer_ok") == 0) + ) { + defer_ok = 1; + } else { + defer_ok = 0; + } +//debug_printf(" defer_ok: %d\n", defer_ok); + + if ((arg_socket_addr == NULL) || (arg_socket_addr[0] == 0)) { + log_write(0, LOG_MAIN|LOG_PANIC, + "rspamd dlfunc: Socket address expected"); + *yield = string_sprintf("rspamd dlfunc: Socket address expected"); + goto RETURN_DEFER; + } + +// get message body stream + + if (split_spool_directory == 0) { + sprintf(mbox_path, "%s/input/%s-D", spool_directory, message_id); + } else { + sprintf(mbox_path, "%s/input/%s/%s-D", spool_directory, message_subdir, message_id); + } +//debug_printf(" Open spool file: %s\n", mbox_path); + mbox_file = fopen(mbox_path,"rb"); + + if (!mbox_file) { + *yield = string_sprintf("rspamd dlfunc: Unable to spool message '%s'", mbox_path); + return(defer_ok ? OK : ERROR); + } + + (void)fseek(mbox_file, 0, SEEK_END); + mbox_size = ftell(mbox_file); +//debug_printf(" Total spool file size: %d\n", mbox_size); + mbox_size -= SPOOL_DATA_START_OFFSET; +//debug_printf(" Spool file size: %d\n", mbox_size); +//debug_printf(" fseek %d, %d\n", SPOOL_DATA_START_OFFSET, SEEK_SET); + (void)fseek(mbox_file, SPOOL_DATA_START_OFFSET, SEEK_SET); + + start = time(NULL); +/* socket does not start with '/' -> network socket */ + if (arg_socket_addr[0] != '/') { + if (sscanf(CS arg_socket_addr, "%s %u", tcp_addr, &tcp_port) != 2 ) { + log_write(0, LOG_MAIN|LOG_PANIC, + "rspamd dlfunc: Invalid rspamd address: '%s'", arg_socket_addr); + *yield = string_sprintf("rspamd dlfunc: Invalid rspamd address: '%s'", arg_socket_addr); + goto RETURN_DEFER; + } + + /* Lookup the host */ + if((he = gethostbyname(CS tcp_addr)) == 0) { + log_write(0, LOG_MAIN|LOG_PANIC, + "rspamd dlfunc: failed to lookup host '%s'", tcp_addr); + *yield = string_sprintf("rspamd dlfunc: failed to lookup host '%s'", tcp_addr); + goto RETURN_DEFER; + } + + in = *(struct in_addr *) he->h_addr_list[0]; + +/* contact a rspamd */ + + if ((rspamd_sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) { + log_write(0, LOG_MAIN|LOG_PANIC, + "rspamd dlfunc: TCP socket creation failed: %s", strerror(errno)); + *yield = string_sprintf("rspamd dlfunc: TCP socket creation failed: %s", strerror(errno)); + goto RETURN_DEFER; + }; + + if (ip_connect(rspamd_sock, AF_INET, (uschar*)inet_ntoa(in), tcp_port, 5, FALSE) < 0) { + log_write(0, LOG_MAIN|LOG_PANIC, + "rspamd dlfunc: connection to %s, port %u failed: %s", tcp_addr, tcp_port, strerror(errno)); + *yield = string_sprintf("rspamd dlfunc: connection to %s, port %u failed: %s", tcp_addr, tcp_port, strerror(errno)); + goto RETURN_DEFER; + } + +//debug_printf(" Use TCP socket %s:%d\n", tcp_addr, tcp_port); + } else { + if ((rspamd_sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + log_write(0, LOG_MAIN|LOG_PANIC, + "rspamd dlfunc: Unable to acquire socket (%s)", strerror(errno)); + *yield = string_sprintf("rspamd dlfunc: Unable to acquire socket (%s)", strerror(errno)); + goto RETURN_DEFER; + } + + server.sun_family = AF_UNIX; + Ustrcpy(server.sun_path, arg_socket_addr); + + if (connect(rspamd_sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) { + log_write(0, LOG_MAIN|LOG_PANIC, + "rspamd dlfunc: Unable to connect to UNIX socket %s (%s)", socket, strerror(errno) ); + *yield = string_sprintf("rspamd dlfunc: Unable to connect to UNIX socket %s (%s)", socket, strerror(errno) ); + goto RETURN_DEFER; + } + +//debug_printf(" Use UNIX Domain socket %s\n", arg_socket_addr); + } + +// now we are connected to rspamd on rspamd_sock + + memset(spamd_buffer2, 0, sizeof(spamd_buffer2)); + offset = 0; + + // headers list + tmp_headerlist = NULL; + header_last = NULL; + for (my_header = header_list; my_header; my_header = my_header->next) { + if ((my_header->type != '*') && (my_header->type != htype_old)) { + header_new = store_get(sizeof(header_line)); + header_new->text = my_header->text; + + header_new->slen = my_header->slen; + header_new->type = my_header->type; + header_new->next = NULL; + //debug_printf(" copy header item: '%s'\n", my_header->text); + + max_len = sizeof(spamd_buffer2) - offset - 1; + len = my_header->slen; + if (len > max_len) len = max_len; + Ustrncpy(spamd_buffer2 + offset, my_header->text, len); + offset += len; + + if (header_last != NULL) header_last->next = header_new; + header_last = header_new; + } + } + + s = string_sprintf("\n"); + max_len = sizeof(spamd_buffer2) - offset - 1; + len = Ustrlen(s); + if (len > max_len) len = max_len; + Ustrncpy(spamd_buffer2 + offset, s, len); + offset += len; + +//debug_printf(" Headers size: %d\n", offset); + mbox_size += offset; +//debug_printf(" Total message size: %d\n", mbox_size); + +// copy request to buffer + memset(spamd_buffer, 0, sizeof(spamd_buffer)); + string_format(spamd_buffer, + sizeof(spamd_buffer), + "POST /checkv2 HTTP/1.0\r\nContent-length: " OFF_T_FMT "\r\nPass: all\r\nQueue-Id: %s\r\nFrom: %s\r\nRecipient-Number: %d\r\n", + mbox_size, message_id, sender_address, recipients_count); + for (i = 0; i < recipients_count; i ++) + string_format(spamd_buffer+Ustrlen(spamd_buffer), sizeof(spamd_buffer)-Ustrlen(spamd_buffer), "Rcpt: %s\r\n", recipients_list[i].address); + if ((helo = expand_string(US"$sender_helo_name")) != NULL && *helo != '\0') + string_format(spamd_buffer+Ustrlen(spamd_buffer), sizeof(spamd_buffer)-Ustrlen(spamd_buffer), "Helo: %s\r\n", helo); + + if ((sender_host_name = expand_string(US"$sender_host_name")) != NULL && *sender_host_name != '\0') + string_format(spamd_buffer+Ustrlen(spamd_buffer), sizeof(spamd_buffer)-Ustrlen(spamd_buffer), "Hostname: %s\r\n", sender_host_name); + //else + //string_format(spamd_buffer+Ustrlen(spamd_buffer), sizeof(spamd_buffer)-Ustrlen(spamd_buffer), "Hostname: unknown\r\n"); + + if (sender_host_address != NULL) + + string_format(spamd_buffer+Ustrlen(spamd_buffer), sizeof(spamd_buffer)-Ustrlen(spamd_buffer), "IP: %s\r\n", sender_host_address); + string_format(spamd_buffer+Ustrlen(spamd_buffer), sizeof(spamd_buffer)-Ustrlen(spamd_buffer), "Pass: all\r\n"); + + //authenticated_id + if ((authenticated_id = expand_string(US"$authenticated_id")) != NULL && *authenticated_id != '\0') + string_format(spamd_buffer+Ustrlen(spamd_buffer), sizeof(spamd_buffer)-Ustrlen(spamd_buffer), "User: %s\r\n", authenticated_id); + + string_format(spamd_buffer+Ustrlen(spamd_buffer), sizeof(spamd_buffer)-Ustrlen(spamd_buffer), "\r\n"); + +//debug_printf(" Send to socket: %s", spamd_buffer); +// send our request + if (send(rspamd_sock, spamd_buffer, Ustrlen(spamd_buffer), 0) < 0) { + log_write(0, LOG_MAIN|LOG_PANIC, + "rspamd dlfunc: rspamd send failed: %s", strerror(errno)); + goto RETURN_DEFER; + } + + /* + * now send the data buffer and spool file + */ + + Ustrcpy(big_buffer, "sending data block"); +//debug_printf("sending data block\n"); + +//debug_printf(" Send to socket: %s", spamd_buffer2); + wrote = send(rspamd_sock, spamd_buffer2, strlen(spamd_buffer2), 0); + if (wrote == -1) goto WRITE_FAILED; +//debug_printf(" wrote to socket %d bytes\n", wrote); + + /* + * Note: poll() is not supported in OSX 10.2. + */ + +#ifndef NO_POLL_H + pollfd.fd = rspamd_sock; + pollfd.events = POLLOUT; +#endif +// (void)fcntl(rspamd_sock, F_SETFL, O_NONBLOCK); + do { + read = fread(spamd_buffer,1,sizeof(spamd_buffer),mbox_file); +if (read < sizeof(spamd_buffer)) spamd_buffer[read] = 0; +//debug_printf(" Read from spool file: %s", spamd_buffer); + if (read > 0) { + offset = 0; +again: + +#ifndef NO_POLL_H + result = poll(&pollfd, 1, 1000); + if (result == -1 && errno == EINTR) + continue; + else if (result < 1) { + if (result == -1) + log_write(0, LOG_MAIN|LOG_PANIC, + "rspamd dlfunc: %s on rspamd socket", strerror(errno)); + else { + if (time(NULL) - start < RSPAMD_TIMEOUT) + goto again; + log_write(0, LOG_MAIN|LOG_PANIC, + "rspamd dlfunc: timed out writing rspamd socket"); + *yield = string_sprintf("rspamd dlfunc: timed out writing rspamd socket"); + } + goto RETURN_DEFER; + } +#endif + wrote = send(rspamd_sock, spamd_buffer + offset, read - offset, 0); +//debug_printf(" Send to socket %d bytes: %s", read - offset, spamd_buffer + offset); +//debug_printf(" wrote to socket %d bytes\n", wrote); + if (wrote == -1) goto WRITE_FAILED; + if (offset + wrote != read) { + offset += wrote; + goto again; + } + } + } while (!feof(mbox_file) && !ferror(mbox_file)); + + if (ferror(mbox_file)) { + log_write(0, LOG_MAIN|LOG_PANIC, + "rspamd dlfunc: error reading spool file: %s", strerror(errno)); + *yield = string_sprintf("rspamd dlfunc: error reading spool file: %s", strerror(errno)); + goto RETURN_DEFER; + } + + /* + read rspamd response using what's left of the timeout. + */ + +//debug_printf("read rspamd response using what's left of the timeout (%d sec)\n", RSPAMD_TIMEOUT - time(NULL) + start); + + memset(spamd_buffer, 0, sizeof(spamd_buffer)); + offset = 0; + while ((i = ip_recv(rspamd_sock, + spamd_buffer + offset, + sizeof(spamd_buffer) - offset - 1, + RSPAMD_TIMEOUT - time(NULL) + start)) > 0 + ) { + //debug_printf(" read %d bytes from socket\n", i); + offset += i; + } +//debug_printf(" total read %d bytes from socket\n", offset); + +/* error handling */ + if((i <= 0) && (errno != 0)) { + log_write(0, LOG_MAIN|LOG_PANIC, + "rspamd dlfunc: error reading from rspamd socket: %s", strerror(errno)); + *yield = string_sprintf("rspamd dlfunc: error reading from rspamd socket: %s", strerror(errno)); + goto RETURN_DEFER; + } + +//debug_printf("read from socket: %s\n", spamd_buffer); + + if (rspamd_sock > 0) { + (void)close(rspamd_sock); + rspamd_sock = 0; + } + if (mbox_file != NULL) { + (void)fclose(mbox_file); + mbox_file = NULL; + } + + //Parse http response code + if (strstr(spamd_buffer, "HTTP/1.1 200 OK") == NULL && strstr(spamd_buffer, "HTTP/1.0 200 OK") == NULL) { + *yield = string_sprintf("rspamd dlfunc: HTTP return code != 200: %s", spamd_buffer); + goto RETURN_DEFER; + } + + //Parse http response + int pos = strpos(spamd_buffer, "\r\n\r\n", 0); + if (pos == -1) { + *yield = string_sprintf("rspamd dlfunc: HTTP response error: %s", spamd_buffer); + goto RETURN_DEFER; + } + char *json_answer = string_sprintf("%s", spamd_buffer +pos+4); + + //Parse json + cJSON *json = NULL; + json = cJSON_Parse(json_answer); + + if (!json) { + *yield = string_sprintf("rspamd dlfunc: Json parse error, json: %s", spamd_buffer); + goto RETURN_DEFER; + } + + //Score + cJSON *score = cJSON_GetObjectItem(json, "score"); + if(!cJSON_IsNumber(score)) { + *yield = string_sprintf("rspamd dlfunc: Json parse error, no found 'score'"); + goto RETURN_DEFER; + } + //required_score + cJSON *required_score = cJSON_GetObjectItem(json, "required_score"); + if(!cJSON_IsNumber(required_score)) { + *yield = string_sprintf("rspamd dlfunc: Json parse error, no found 'required_score'"); + goto RETURN_DEFER; + } + //Action + cJSON *action = cJSON_GetObjectItem(json, "action"); + if(!cJSON_IsString(action)) { + *yield = string_sprintf("rspamd dlfunc: Json parse error, no found 'action'"); + goto RETURN_DEFER; + } + *yield = string_sprintf("[%.2f / %.2f]", score->valuedouble, required_score->valuedouble); + + //Parse scan time + cJSON *time_real = cJSON_GetObjectItem(json, "time_real"); + cJSON *time_virtual = cJSON_GetObjectItem(json, "time_virtual"); + if(cJSON_IsNumber(time_real) && cJSON_IsNumber(time_virtual)) *yield = string_sprintf("%s [time: %.6f, %.6f]", *yield, time_real->valuedouble, time_virtual->valuedouble); + + *yield = string_sprintf("%s\n Action: %s\n", *yield, action->valuestring); + + cJSON *symbol = NULL; + cJSON *symbol_name = NULL; + cJSON *symbol_score = NULL; + cJSON *symbol_options = NULL; + cJSON *option = NULL; + + //parse symbols + cJSON *symbols = cJSON_GetObjectItem(json, "symbols"); + for(i=0; i<cJSON_GetArraySize(symbols); i++) { + symbol = cJSON_GetArrayItem(symbols, i); + symbol_name = cJSON_GetObjectItem(symbol, "name"); + symbol_score = cJSON_GetObjectItem(symbol, "score"); + symbol_options = cJSON_GetObjectItem(symbol, "options"); + + if(cJSON_IsString(symbol_name)) *yield = string_sprintf("%s %s", *yield, symbol_name->valuestring); + if(cJSON_IsNumber(symbol_score)) *yield = string_sprintf("%s(%.2f)", *yield, symbol_score->valuedouble); + + //parse options + c = cJSON_GetArraySize(symbol_options); + if(c > 0) *yield = string_sprintf("%s[", *yield); + for(j=0; j<c; j++) { + option = cJSON_GetArrayItem(symbol_options, j); + if(cJSON_IsString(option)) { + *yield = string_sprintf("%s%s", *yield, option->valuestring); + if(j < c-1) *yield = string_sprintf("%s, ", *yield); + } + } + if(c > 0) *yield = string_sprintf("%s]", *yield); + + *yield = string_sprintf("%s\n", *yield); + } + + //Parse messages + cJSON *mess = NULL; + cJSON *messages = cJSON_GetObjectItem(json, "messages"); + c = cJSON_GetArraySize(messages); + for(i=0; i<c; i++) { + mess = cJSON_GetArrayItem(messages, i); + if(cJSON_IsString(mess)) *yield = string_sprintf("%s %s", *yield, mess->valuestring); + if(i < c-1) *yield = string_sprintf("%s\n", *yield); + } + + return OK; + +/* Come here if any call to read_response, other than a response after the data +phase, failed. Analyse the error, and if isn't too bad, send a QUIT +command. Wait for the response with a short timeout, so we don't wind up this +process before the far end has had time to read the QUIT. */ + +WRITE_FAILED: +{ + log_write(0, LOG_MAIN|LOG_PANIC, + "rspamd dlfunc: %s on rspamd socket", strerror(errno)); + *yield = string_sprintf("rspamd dlfunc: %s on rspamd socket", strerror(errno)); + goto RETURN_DEFER; +} + +RESPONSE_FAILED: +{ + int code; + int save_errno; + int more_errno; + uschar message_buffer[256]; + uschar *message; + + save_errno = errno; + + message = &message_buffer[0]; + + log_write(0, LOG_MAIN|LOG_PANIC, "rspamd dlfunc: %s", message); + *yield = string_sprintf("rspamd dlfunc: %s", message); + + goto RETURN_DEFER; +} + +RETURN_DEFER: +{ + if (rspamd_sock > 0) { + (void)close(rspamd_sock); + rspamd_sock = 0; + } + if (mbox_file != NULL) { + (void)fclose(mbox_file); + mbox_file = NULL; + } + + return(defer_ok ? OK : ERROR); +} + + return OK; +} |