From 22ff8a2f3dd704c2728dca07e28524edabc1463c Mon Sep 17 00:00:00 2001 From: Art Cancro Date: Wed, 11 Apr 2018 23:23:51 -0400 Subject: [PATCH] Capture the actual SMTP response from the server, ugly hack using libcurl debug --- citadel/citadel.h | 4 +- citadel/modules/smtp/serv_smtpclient.c | 52 ++++++++++++++++++++++++-- libcitadel/lib/libcitadel.h | 2 +- textclient/textclient.h | 2 +- webcit/webcit.h | 6 +-- 5 files changed, 55 insertions(+), 11 deletions(-) diff --git a/citadel/citadel.h b/citadel/citadel.h index 8c209787d..683b1c8f9 100644 --- a/citadel/citadel.h +++ b/citadel/citadel.h @@ -35,10 +35,10 @@ extern "C" { */ #define CITADEL PACKAGE_STRING -#define REV_LEVEL 917 // This version +#define REV_LEVEL 920 // This version #define REV_MIN 591 // Oldest compatible database #define EXPORT_REV_MIN 760 // Oldest compatible export files -#define LIBCITADEL_MIN 917 // Minimum required version of libcitadel +#define LIBCITADEL_MIN 920 // Minimum required version of libcitadel #define SERVER_TYPE 0 // zero for stock Citadel; other developers please // obtain SERVER_TYPE codes for your implementations diff --git a/citadel/modules/smtp/serv_smtpclient.c b/citadel/modules/smtp/serv_smtpclient.c index a4737c39c..6354461d3 100644 --- a/citadel/modules/smtp/serv_smtpclient.c +++ b/citadel/modules/smtp/serv_smtpclient.c @@ -181,11 +181,31 @@ static size_t upload_source(void *ptr, size_t size, size_t nmemb, void *userp) } +/* + * The libcurl API doesn't provide a way to capture the actual SMTP result message returned + * by the remote server. This is an ugly way to extract it, by capturing debug data from + * the library and filtering on the lines we want. + */ +int ctdl_libcurl_smtp_debug_callback(CURL *handle, curl_infotype type, char *data, size_t size, void *userptr) +{ + if (type != CURLINFO_HEADER_IN) return 0; + if (!userptr) return 0; + char *debugbuf = (char *)userptr; + + int len = strlen(debugbuf); + if (len + size > SIZ) return 0; + + memcpy(&debugbuf[len], data, size); + debugbuf[len+size] = 0; + return 0; +} + + /* * Attempt a delivery to one recipient. * Returns a three-digit SMTP status code. */ -int smtp_attempt_delivery(long msgid, char *recp, char *envelope_from) +int smtp_attempt_delivery(long msgid, char *recp, char *envelope_from, char *response) { struct smtpmsgsrc s; char *fromaddr = NULL; @@ -224,6 +244,7 @@ int smtp_attempt_delivery(long msgid, char *recp, char *envelope_from) curl = curl_easy_init(); if (curl) { + response[0] = 0; if (!IsEmptyStr(envelope_from)) { curl_easy_setopt(curl, CURLOPT_MAIL_FROM, envelope_from); @@ -244,6 +265,9 @@ int smtp_attempt_delivery(long msgid, char *recp, char *envelope_from) curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); // curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_error_buffer); + curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, ctdl_libcurl_smtp_debug_callback); + curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)response); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); // Construct an SMTP URL in the form of: // smtp[s]://target_host/source_host @@ -273,6 +297,25 @@ int smtp_attempt_delivery(long msgid, char *recp, char *envelope_from) recipients = NULL; // this gets reused; avoid double-free curl_easy_cleanup(curl); curl = NULL; // this gets reused; avoid double-free + + /* Trim the error message buffer down to just the actual message */ + char response_code_str[4]; + snprintf(response_code_str, sizeof response_code_str, "%ld", response_code); + char *respstart = strstr(response, response_code_str); + if (respstart == NULL) + { + strcpy(response, smtpstatus(response_code)); + } + else { + strcpy(response, respstart); + char *p; + for (p=response; *p!=0; ++p) + { + if (*p == '\n') *p = ' '; + if (*p == '\r') *p = ' '; + if (!isprint(*p)) *p = ' '; + } + } } } @@ -295,6 +338,7 @@ void smtp_process_one_msg(long qmsgnum) int num_delayed = 0; long deletes[2]; int delete_this_queue = 0; + char server_response[SIZ]; msg = CtdlFetchMessage(qmsgnum, 1, 1); if (msg == NULL) { @@ -366,8 +410,8 @@ void smtp_process_one_msg(long qmsgnum) if ((previous_result == 0) || (previous_result == 4)) { int new_result = 421; extract_token(recp, cfgline, 1, '|', sizeof recp); - new_result = smtp_attempt_delivery(msgid, recp, envelope_from); - syslog(LOG_DEBUG, "smtpclient: recp: <%s> , result: %d (%s)", recp, new_result, smtpstatus(new_result)); + new_result = smtp_attempt_delivery(msgid, recp, envelope_from, server_response); + syslog(LOG_DEBUG, "smtpclient: recp: <%s> , result: %d (%s)", recp, new_result, server_response); if ((new_result / 100) == 2) { ++num_success; } @@ -379,7 +423,7 @@ void smtp_process_one_msg(long qmsgnum) ++num_delayed; } StrBufAppendPrintf(NewInstr, "remote|%s|%ld|%ld (%s)\n", - recp, (new_result / 100) , new_result, smtpstatus(new_result) + recp, (new_result / 100) , new_result, server_response ); } } diff --git a/libcitadel/lib/libcitadel.h b/libcitadel/lib/libcitadel.h index 3e86d07f5..f22e77f10 100644 --- a/libcitadel/lib/libcitadel.h +++ b/libcitadel/lib/libcitadel.h @@ -28,7 +28,7 @@ #include #include -#define LIBCITADEL_VERSION_NUMBER 918 +#define LIBCITADEL_VERSION_NUMBER 920 /* * Here's a bunch of stupid magic to make the MIME parser portable. diff --git a/textclient/textclient.h b/textclient/textclient.h index 671773226..2fa619ee7 100644 --- a/textclient/textclient.h +++ b/textclient/textclient.h @@ -13,7 +13,7 @@ #define UDS "_UDS_" #define DEFAULT_HOST "localhost" #define DEFAULT_PORT "504" -#define CLIENT_VERSION 919 +#define CLIENT_VERSION 920 #define CLIENT_TYPE 0 /* commands we can send to the stty_ctdl() routine */ diff --git a/webcit/webcit.h b/webcit/webcit.h index cc700fa7e..ccfcfb074 100644 --- a/webcit/webcit.h +++ b/webcit/webcit.h @@ -127,9 +127,9 @@ extern char *ssl_cipher_list; #define PORT_NUM 2000 /* port number to listen on */ #define DEVELOPER_ID 0 #define CLIENT_ID 4 -#define CLIENT_VERSION 917 /* This version of WebCit */ -#define MINIMUM_CIT_VERSION 917 /* Minimum required version of Citadel server */ -#define LIBCITADEL_MIN 914 /* Minimum required version of libcitadel */ +#define CLIENT_VERSION 920 /* This version of WebCit */ +#define MINIMUM_CIT_VERSION 920 /* Minimum required version of Citadel server */ +#define LIBCITADEL_MIN 920 /* Minimum required version of libcitadel */ #define DEFAULT_HOST "localhost" /* Default Citadel server */ #define DEFAULT_PORT "504" #define TARGET "webcit01" /* Window target for inline URL's */ -- 2.30.2