42 #define NCBI_USE_ERRCODE_X Connect_SMTP
44 #define MX_SENDMAIL_MAGIC 0xBA8ADEDA
45 #define MX_CRLF "\r\n"
47 #define SMTP_READERR -1
48 #define SMTP_READTMO -2
49 #define SMTP_RESPERR -3
50 #define SMTP_NOCODE -4
51 #define SMTP_BADCODE -5
52 #define SMTP_BADRESP -6
69 assert(response && max_response_len);
77 if (m == 3 && status == eIO_Closed)
94 if (errno ||
code <= 0 || e !=
buf + 3)
98 if (
n > max_response_len)
100 memcpy(response,
buf,
n);
101 if (
n < max_response_len)
112 if (status == eIO_Closed) {
113 if (
n < max_response_len)
114 response[
n++] =
'\n';
120 if (*
buf !=
'\r' &&
n < max_response_len)
121 response[
n++] = *
buf;
123 }
while (*
buf !=
'\n');
128 response[
n - 1] =
'\0';
129 else if (
n < max_response_len)
143 char*
buf,
size_t buf_size,
148 const char* message = 0;
151 message =
"Read error";
154 message =
"Read timed out";
157 message =
"Cannot read response prefix";
160 message =
"No response code detected";
163 message =
"Response code mismatch";
166 message =
"Malformed response";
169 message =
"Unknown error";
175 }
else if (!
code || c ==
code || (alt_code && c == alt_code))
203 if (!(at = strchr(from,
'@'))) {
212 len = (size_t)(at - from);
214 size_t tmp =
len + strlen(at);
226 if ((
len = strlen(at)) <
sizeof(x_buf)) {
227 memcpy(x_buf, at,
len + 1);
255 if ((!(host = getenv(
"HOSTNAME")) && !(host = getenv(
"HOST")))
256 || (
len = strlen(host)) >=
size) {
264 }
else if (1 < (
len = strlen(at)) &&
len <
size)
289 || !(port = (
unsigned int) atoi(
buf)) || port > 65535) {
294 #if defined(NCBI_OS_UNIX) && !defined(NCBI_OS_CYGWIN)
295 strcpy(
buf,
"localhost");
297 strcpy(
buf,
"mailgw");
322 info->mx_options = 0;
341 #define SENDMAIL_RETURN(subcode, reason) \
347 CORE_LOGF_X(subcode, eLOG_Error, ("[SendMail] %s", reason)); \
349 if (info->mx_options & fSendMail_ExtendedErrInfo) { \
350 char* retval = strdup(reason); \
351 return retval ? retval : ""; \
358 #define SENDMAIL_RETURN2(subcode, reason, explanation) \
364 CORE_LOGF_X(subcode, eLOG_Error, \
365 ("[SendMail] %s: %s", reason, explanation)); \
367 if (info->mx_options & fSendMail_ExtendedErrInfo) { \
368 size_t lenr = strlen(reason); \
369 size_t lene = strlen(explanation) + 1; \
370 char* retval = (char*) malloc(lene + 2 + lenr); \
373 memcpy(retval, reason, lenr); \
374 retval[lenr++] = ':'; \
375 retval[lenr++] = ' '; \
376 memcpy(retval + lenr, explanation, lene); \
386 char buf[],
size_t buf_size,
388 const char write_error[],
389 const char proto_error[],
393 while ((c = *to++) !=
'\0') {
396 if (
isspace((
unsigned char) c))
398 while (k < buf_size) {
402 }
else if (c ==
'"' || c ==
'<') {
403 quote = c ==
'<' ?
'>' : c;
406 buf[k++] = c ==
'\t' ?
' ' : c;
409 if (
isspace((
unsigned char) c)) {
410 while (
isspace((
unsigned char)(*to)))
419 (
"[SendMail] Unbalanced delimiters in"
420 " recipient %s for %s: \"%c\" expected",
441 const char* at, *dot;
446 if (!(at = (
const char*) memchr(
info->from,
'@',
len))
447 || at ==
info->from +
len - 1) {
450 if (!(dot = (
const char*) memchr(at + 1,
'.',
451 len - (
size_t)(at -
info->from) - 1))
452 || dot == at + 1 || dot ==
info->from +
len - 1) {
453 return (
size_t)(at -
info->from);
459 #define SENDMAIL_SENDRCPT(what, list, buffer) \
460 s_SendRcpt(sock, list, buffer, sizeof(buffer), what, \
461 "Write error in RCPT (" what ") command", \
462 "Protocol error in RCPT (" what ") command", \
465 #define SENDMAIL_READ_RESPONSE(code, buffer) \
466 s_SockReadResponse(sock, code, 0, buffer, sizeof(buffer), \
467 info->mx_options & fSendMail_ExtendedErrInfo)
475 static const STimeout zero = {0, 0};
490 SENDMAIL_RETURN(7,
"At least one message recipient must be specified");
496 &
info->mx_timeout, &sock,
559 static const char* kMonth[] = {
"Jan",
"Feb",
"Mar",
"Apr",
560 "May",
"Jun",
"Jul",
"Aug",
561 "Sep",
"Oct",
"Nov",
"Dec" };
563 static const char kDateFmt[] =
"%d %%s %Y %H:%M:%S %z" MX_CRLF;
564 time_t now = time(0);
567 #if defined(NCBI_OS_SOLARIS)
569 tm = localtime(&now);
570 #elif defined(HAVE_LOCALTIME_R)
572 localtime_r(&now, tm = &
tmp);
576 tm = (
struct tm*) memcpy(&
tmp, localtime(&now),
sizeof(
tmp));
579 if (strftime(datefmt,
sizeof(datefmt), kDateFmt, tm)) {
580 sprintf(
buffer, datefmt, kMonth[tm->tm_mon]);
617 "[SendMail] Subject ignored in as-is messages");
620 if (!
s_SockWrite(sock,
"X-Mailer: CORE_SendMail (NCBI "
633 if (
info->header && *
info->header) {
634 size_t n = 0, m = strlen(
info->header);
641 if (
info->header[
n] ==
'\n') {
646 if (
info->header[
n] !=
'\r' ||
info->header[
n+1] !=
'\n')
658 const char*
error =
"Custom header write error";
663 error =
"Spurious response while writing custom header";
672 size_t n = 0, m =
info->body_size ?
info->body_size : strlen(body);
683 if (body[
n] ==
'\n') {
688 if (body[
n] !=
'\r' || (
n+1 < m && body[
n+1] !=
'\n')){
689 if (body[
n] ==
'.' && (newline || !
n)) {
705 const char*
error =
"Message body write error";
710 error =
"Spurious response while writing message body";
734 #undef SENDMAIL_READ_RESPONSE
735 #undef SENDMAIL_SENDRCPT
736 #undef SENDMAIL_RETURN2
737 #undef SENDMAIL_RETURN
const char * CORE_SendMailEx(const char *to, const char *subject, const char *body, const SSendMailInfo *uinfo)
Send a message as in CORE_SendMail() but by explicitly specifying all additional parameters of the me...
SSendMailInfo * SendMailInfo_InitEx(SSendMailInfo *info, const char *from, ECORE_Username user)
Initialize SSendMailInfo structure, setting: 'cc', 'bcc', 'header' to NULL (means no recipients/addit...
#define SendMailInfo_Init(i)
const char * CORE_SendMail(const char *to, const char *subject, const char *body)
Send a simple message to recipient(s) defined in 'to', and having: 'subject', which may be empty (bot...
@ fSendMail_NoMxHeader
Don't add standard mail header, just use what user provided.
@ fSendMail_ExtendedErrInfo
Return extended error info that must be free()'d by caller.
@ fSendMail_LogOn
see: fSOCK_LogOn
@ fSendMail_StripNonFQDNHost
Strip host part off the "from" field if it does not look like an FQDN (i.e.
@ fSendMail_Old822Headers
Form "Date:" and "From:" hdrs (usually they are defaulted)
EIO_Status SOCK_SetTimeout(SOCK sock, EIO_Event event, const STimeout *timeout)
Specify timeout for the connection I/O (see SOCK_[Read|Write|Close]()).
void SOCK_DisableOSSendDelay(SOCK sock, int on_off)
Control OS-defined send strategy by disabling/enabling the TCP Nagle algorithm (which is on by defaul...
EIO_Status SOCK_Close(SOCK sock)
Close the SOCK handle, and destroy all relevant internal data.
EIO_Status SOCK_Read(SOCK sock, void *buf, size_t size, size_t *n_read, EIO_ReadMethod how)
Read/peek up to "size" bytes from "sock" to a buffer pointed to by "buf".
int SOCK_gethostname(char *name, size_t namelen)
Same as SOCK_gethostnameEx(,,<current API data logging>)
void SOCK_SetCork(SOCK sock, int on_off)
Control OS-defined send strategy by disabling/enabling the TCP layer to send incomplete network frame...
EIO_Status SOCK_Wait(SOCK sock, EIO_Event event, const STimeout *timeout)
Block on the socket until either the specified "event" is available or "timeout" expires (if "timeout...
EIO_Status SOCK_CreateEx(const char *host, unsigned short port, const STimeout *timeout, SOCK *sock, const void *data, size_t size, TSOCK_Flags flags)
[CLIENT-side] Connect client to another(server-side, listening) socket (socket() + connect() [+ selec...
EIO_Status SOCK_Write(SOCK sock, const void *data, size_t size, size_t *n_written, EIO_WriteMethod how)
Write "size" bytes of "data" to "sock".
const char * SOCK_gethostbyaddr(unsigned int addr, char *name, size_t namelen)
Same as SOCK_gethostbyaddrEx(,,<current API data logging>)
unsigned int TSOCK_Flags
bitwise "OR" of ESOCK_Flags
ECORE_Username
Select which username is the most preferable to obtain from the system.
unsigned int usec
microseconds (modulo 1,000,000)
const char * IO_StatusStr(EIO_Status status)
Get the text form of an enum status value.
const char * CORE_GetUsernameEx(char *buf, size_t bufsize, ECORE_Username username)
Obtain and store in the buffer provided, the best (as possible) user name that matches the requested ...
@ eIO_Timeout
timeout expired before any I/O succeeded
@ eIO_Success
everything is fine, no error occurred
@ eIO_ReadPlain
read readily available data only, wait if none
@ eIO_ReadPersist
read exactly as much as requested, w/waits
@ eIO_WritePersist
write exactly as much as specified, w/waits
@ eIO_ReadWrite
eIO_Read | eIO_Write (also, eCONN_OnFlush)
@ eIO_Close
also serves as an error indicator in SOCK_Poll
unsigned int
A callback function used to compare two keys in a database.
const struct ncbi::grid::netcache::search::fields::SIZE size
double NCBI_simple_atof(const char *s, char **t)
Locale-independent ASCII-to-double conversion of string "s".
char * strncpy0(char *s1, const char *s2, size_t n)
Copy not more than "n" characters from string "s2" into "s1", and return the result,...
const char * ConnNetInfo_GetValueInternal(const char *service, const char *param, char *value, size_t value_size, const char *def_value)
#define CORE_LOGF_X(subcode, level, fmt_args)
#define CORE_LOG_X(subcode, level, message)
static char s_MxHost[CONN_HOST_LEN+1]
static void x_Sendmail_InitEnv(void)
static int s_SockReadResponse(SOCK sock, int code, int alt_code, char *buf, size_t buf_size, int savecode)
static int s_SockRead(SOCK sock, char *response, size_t max_response_len, int savecode)
#define SENDMAIL_READ_RESPONSE(code, buffer)
#define SENDMAIL_RETURN2(subcode, reason, explanation)
static size_t s_FromSize(const SSendMailInfo *info)
static int s_SockWrite(SOCK sock, const char *buf, size_t len)
#define MX_SENDMAIL_MAGIC
static const char * s_SendRcpt(SOCK sock, const char *to, char buf[], size_t buf_size, const char what[], const char write_error[], const char proto_error[], const SSendMailInfo *info)
static void s_MakeFrom(char *buf, size_t size, const char *from, ECORE_Username user)
#define SENDMAIL_RETURN(subcode, reason)
static STimeout s_MxTimeout
#define SENDMAIL_SENDRCPT(what, list, buffer)
static unsigned short s_MxPort
Define optional parameters for communication with sendmail.