static char rcsid[] = "@(#)$Id: mailer.c,v 1.7 2006/04/09 07:37:36 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.7 $ $State: Exp $
*
* Author: Kari Hurtta <hurtta+elm@posti.FMI.FI> (was hurtta+elm@ozone.FMI.FI)
*****************************************************************************/
#include "def_mailer.h"
#include "s_elm.h"
#include "mailer_imp.h"
#ifdef USE_DLOPEN
#include "shared_imp.h"
#endif
DEBUG_VAR(Debug,__FILE__,"mailer");
#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif
static unsigned char *s2us P_((char *str));
static unsigned char *s2us(str)
char *str;
{
return (unsigned char *)str;
}
int MO_default_value (M,L,value,set)
struct mailer_config *M;
struct mailer_option_list *L;
char **value;
int set;
{
if (set) {
if (!value) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmMailerOptionValue,
"Mailer option %s requires value"),
L->field);
return 0;
}
if (L->malloced) {
free(*(L->value));
*(L->value) = NULL;
}
*(L->value) = safe_strdup(*value);
L->malloced = 1;
}
else {
*value = *(L->value);
}
return 1;
}
#if ANSI_C
#define S_(x) static x;
#else
#define S_(x)
#endif
S_(mailer_set_option default_set_option)
static int default_set_option(M,X,value)
struct mailer_config *M;
struct mailer_option_list *X;
char *value;
{
int r ;
r = X->value_func(M,X,&value,1);
return r;
}
S_(mailer_init_hook default_mailer_init)
static int default_mailer_init P_((struct mailer_config *M,
struct mail_send_state *C,
struct mailer_info *I));
S_(mailer_init_hook submitmail_mailer_init)
static int submitmail_mailer_init P_((struct mailer_config *M,
struct mail_send_state *C,
struct mailer_info *I));
S_(mailer_close_hook default_mailer_close)
static void default_mailer_close P_((struct mailer_config *M,
struct mail_send_state *C));
S_(mailer_info_init_hook default_mailer_info_init)
static int default_mailer_info_init P_((struct mailer_config *M,
struct mailer_info *I));
S_(mailer_info_close_hook null_mailer_info_close)
static void null_mailer_info_close(M,I)
struct mailer_config *M;
struct mailer_info *I;
{
/* Nothing */
}
/* Return
-1 if caller should result with default data (return 1)
-2 if caller should just test passwd
0 if failure
1 is succees
*/
S_(mailer_info_verify_addr default_mailer_info_verify_addr)
static int default_mailer_info_verify_addr(M,I,text,result)
struct mailer_config *M;
struct mailer_info *I;
CONST char *text;
struct addr_item *result;
{
return -2; /* caller does job */
}
S_(mailer_info_gen_def_ef default_mailer_info_gen_def_ef)
static void default_mailer_info_gen_def_ef(M,I,X)
struct mailer_config *M;
struct mailer_info *I;
struct mailer_env_from *X;
{
/* Nothing */
}
S_(mailer_info_set_ef default_mailer_info_set_ef)
static void default_mailer_info_set_ef(M,I,X,value)
struct mailer_config *M;
struct mailer_info *I;
struct mailer_env_from *X;
CONST char *value;
{
/* Sets env from without checking */
X->mail_from = strmcpy(X->mail_from,value);
}
/* Return
1 == mailer restarted, reconnect succeed -- reask info
0 == mailer not disconnected
-1 == mailer disconnected, reconnect failed
*/
S_(mailer_info_restart_hook default_mailer_info_rs_hook)
static int default_mailer_info_rs_hook P_((struct mailer_config *M,
struct mailer_info *I));
static int default_mailer_info_rs_hook(M,I)
struct mailer_config *M;
struct mailer_info *I;
{
return 0; /* Assume not restarted */
}
S_(mailer_info_set_ef sendmail_mailer_info_set_ef)
static void sendmail_mailer_info_set_ef P_((struct mailer_config *M,
struct mailer_info *I,
struct mailer_env_from *X,
const char *value));
S_(mailer_info_verify_addr sendmail_mailer_info_verify_addr)
static int sendmail_mailer_info_verify_addr P_((struct mailer_config *M,
struct mailer_info *I,
const char *text,
struct addr_item *result));
S_(mailer_info_query_hook default_mailer_info_query)
static int default_mailer_info_query P_((struct mailer_config *M,
struct mailer_info *I,
enum MI_query query));
S_(mailer_info_query_hook sendmail_mailer_info_query)
static int sendmail_mailer_info_query P_((struct mailer_config *M,
struct mailer_info *I,
enum MI_query query));
S_(mailer_backend_hook unknown_mailer_backend)
static int unknown_mailer_backend P_((struct mailer_config *M,
struct mail_send_state **C,
int encoding_top,
char * title,
sending_message_func *sm));
S_(mailer_backend_hook sendmail_mailer_backend)
static int sendmail_mailer_backend P_((struct mailer_config *M,
struct mail_send_state **C,
int encoding_top,
char * title,
sending_message_func *sm));
S_(mailer_backend_hook submitmail_mailer_backend)
static int submitmail_mailer_backend P_((struct mailer_config *M,
struct mail_send_state **C,
int encoding_top,
char * title,
sending_message_func *sm));
S_(mailer_backend_hook execmail_mailer_backend)
static int execmail_mailer_backend P_((struct mailer_config *M,
struct mail_send_state **C,
int encoding_top,
char * title,
sending_message_func *sm));
static struct mailer_config * selected_mailer = NULL;
static char * unknown_mailer_path = DEFAULT_MAILER_PATH;
static char * sendmail_mailer_path = SENDMAIL_MAILER_PATH;
static char * submitmail_mailer_path = SUBMITMAIL_MAILER_PATH;
static char * execmail_mailer_path = EXECMAIL_MAILER_PATH;
static enum bodytypes {
have_7bit = 0, have_8bit = 1, have_binary = 2
} sendmail_supported_bodytype = have_7bit;
static int sendmail_supports_dsn = 0;
static int sendmail_verify_address = 0;
static int MO_sendmail_bodytype P_((struct mailer_config * M,
struct mailer_option_list * L,
char **value,int set));
static int MO_sendmail_bodytype (M,L,value,set)
struct mailer_config *M;
struct mailer_option_list *L;
char **value;
int set;
{
static char *sendmail_bodytypes[] = { "7bit", "8bit", "binary" };
static int value_set = 0;
if (set) {
int i;
if (!*value) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmMailerOptionValue,
"Mailer option %s requires value"),
L->field);
return 0;
}
for (i = 0;
i < sizeof sendmail_bodytypes / sizeof (sendmail_bodytypes[0]);
i++) {
if (0 == strcmp(sendmail_bodytypes[i],*value)) {
sendmail_supported_bodytype = (enum bodytypes)i;
value_set = 1;
return 1;
}
}
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmSendmailBadBodytype,
"Bad supported-bodytype %s for sendmail"),
*value);
return 0;
}
else {
if (sendmail_supported_bodytype < have_7bit ||
sendmail_supported_bodytype > have_binary)
panic("MAILER PANIC",__FILE__,__LINE__,
"MO_sendmail_bodytype",
"Bad supported-bodytype",0);
*value = sendmail_bodytypes[sendmail_supported_bodytype];
if (sendmail_supported_bodytype > have_7bit)
return 1; /* Give value always */
}
return value_set; /* Return calue only if set at lweast once */
}
static int MO_sendmail_dsn P_((struct mailer_config * M,
struct mailer_option_list * L,
char **value,int set));
static int MO_sendmail_dsn (M,L,value,set)
struct mailer_config *M;
struct mailer_option_list *L;
char **value;
int set;
{
static char *no_yes[] = { "no", "yes" };
static int value_set = 0;
if (set) {
if (!*value)
sendmail_supports_dsn = 1;
else if (0 == strcmp(*value,no_yes[0]))
sendmail_supports_dsn = 0;
else if (0 == strcmp(*value,no_yes[1]))
sendmail_supports_dsn = 1;
else {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmSendmailBadDsn,
"Bad supports-dsn=%s for sendmail"),
*value);
return 0;
}
value_set = 1;
} else {
/* Do not return option if sendmail_supports_dsn is not supported */
if (sendmail_supports_dsn) {
*value = no_yes[1];
return 1;
}
*value = no_yes[0]; /* Only show if supports-dsn=no or
supports-dsn=yes is given at least once
*/
}
return value_set;
}
static int MO_sendmail_verify P_((struct mailer_config * M,
struct mailer_option_list * L,
char **value,int set));
static int MO_sendmail_verify (M,L,value,set)
struct mailer_config *M;
struct mailer_option_list *L;
char **value;
int set;
{
static char *no_yes[] = { "no", "yes" };
static int value_set = 0;
if (set) {
if (!*value)
sendmail_verify_address = 1;
else if (0 == strcmp(*value,no_yes[0]))
sendmail_verify_address = 0;
else if (0 == strcmp(*value,no_yes[1]))
sendmail_verify_address = 1;
else {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmSendmailBadVerify,
"Bad verify=%s for sendmail"),
*value);
return 0;
}
value_set = 1;
} else {
if (sendmail_verify_address) {
*value = no_yes[1];
return 1;
}
*value = no_yes[0]; /* Only show if verify=no or
verify=yes is given at least once
*/
}
return value_set;
}
static int MO_dont_add_from P_((struct mailer_config * M,
struct mailer_option_list * L,
char **value,int set));
static int MO_dont_add_from (M,L,value,set)
struct mailer_config *M;
struct mailer_option_list *L;
char **value;
int set;
{
static char *yes_dont[] = { "yes", "dont" };
static int value_set = 0;
if (set) {
if (!*value)
M -> mailer_bits &= ~MB_DONT_ADD_FROM;
else if (0 == strcmp(*value,yes_dont[0]))
M -> mailer_bits &= ~MB_DONT_ADD_FROM;
else if (0 == strcmp(*value,yes_dont[1]))
M -> mailer_bits |= MB_DONT_ADD_FROM;
else {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadAddFrom,
"Bad add-from=%s for %s"),
*value, M->mailer_type);
return 0;
}
value_set = 1;
} else {
*value = yes_dont[ (M -> mailer_bits & MB_DONT_ADD_FROM) ?
1 : 0 ];
if (M -> mailer_bits & MB_DONT_ADD_FROM)
return 1;
/* Do not show add-from=yes if it is not set explicity */
}
return value_set;
}
static int MO_use_domain P_((struct mailer_config * M,
struct mailer_option_list * L,
char **value,int set));
static int MO_use_domain (M,L,value,set)
struct mailer_config *M;
struct mailer_option_list *L;
char **value;
int set;
{
static char *no_yes[] = { "no", "yes" };
static int value_set = 0;
if (set) {
if (!*value)
M -> mailer_bits |= MB_USE_DOMAIN;
else if (0 == strcmp(*value,no_yes[0]))
M -> mailer_bits &= ~MB_USE_DOMAIN;
else if (0 == strcmp(*value,no_yes[1]))
M -> mailer_bits |= MB_USE_DOMAIN;
else {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadUseDomain,
"Bad use-domain=%s for %s"),
*value, M->mailer_type);
return 0;
}
value_set = 1;
} else {
*value = no_yes[ (M -> mailer_bits & MB_USE_DOMAIN) ?
1 : 0 ];
if (!(M -> mailer_bits & MB_USE_DOMAIN))
return 1;
/* Do not show use-domain=yes if it is not set explicity */
}
return value_set;
}
int MO_allow_set_sender (M,L,value,set)
struct mailer_config *M;
struct mailer_option_list *L;
char **value;
int set;
{
static char *no_yes[] = { "no", "yes" };
static int value_set = 0;
if (set) {
if (!*value)
M -> mailer_bits |= MB_ALLOW_SET_SENDER;
else if (0 == strcmp(*value,no_yes[0]))
M -> mailer_bits &= ~MB_ALLOW_SET_SENDER;
else if (0 == strcmp(*value,no_yes[1]))
M -> mailer_bits |= MB_ALLOW_SET_SENDER;
else {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadAllowSetSender,
"Bad allow-set-sender=%s for %s"),
*value, M->mailer_type);
return 0;
}
value_set = 1;
} else {
*value = no_yes[ (M -> mailer_bits & MB_ALLOW_SET_SENDER) ?
1 : 0 ];
if (M -> mailer_bits & MB_ALLOW_SET_SENDER)
return 1;
/* Do not show use-domain=no if it is not set explicity */
}
return value_set;
}
static struct mailer_option_list UNKNOWN_options[] = {
{ "path", &unknown_mailer_path, MO_default_value, 0 },
{ "add-from", NULL, MO_dont_add_from, 0 },
{ "use-domain", NULL, MO_use_domain, 0 },
{ NULL, NULL, MO_default_value, 0 }
};
static struct mailer_option_list SENDMAIL_options[] = {
{ "path", &sendmail_mailer_path, MO_default_value, 0 },
{ "add-from", NULL, MO_dont_add_from, 0 },
{ "use-domain", NULL, MO_use_domain, 0 },
{ "supported-bodytype", NULL, MO_sendmail_bodytype, 0 },
{ "supports-dsn", NULL, MO_sendmail_dsn, 0 },
{ "verify", NULL, MO_sendmail_verify, 0 },
{ "allow-set-sender",NULL, MO_allow_set_sender, 0 },
{ NULL, NULL, MO_default_value, 0 }
};
static struct mailer_option_list SUBMITMAIL_options[] = {
{ "path", &submitmail_mailer_path, MO_default_value, 0 },
{ "add-from", NULL, MO_dont_add_from, 0 },
{ "use-domain", NULL, MO_use_domain, 0 },
{ NULL, NULL, MO_default_value, 0 }
};
static struct mailer_option_list EXECMAIL_options[] = {
{ "path", &execmail_mailer_path, MO_default_value, 0 },
{ "add-from", NULL, MO_dont_add_from, 0 },
{ "use-domain", NULL, MO_use_domain, 0 },
{ NULL, NULL, MO_default_value, 0 }
};
static struct mailer_config MAILERS[] = {
{ "unknown", &(UNKNOWN_options[0]), default_set_option,
default_mailer_init, default_mailer_close, unknown_mailer_backend,
&unknown_mailer_path,
default_mailer_info_init, null_mailer_info_close,
default_mailer_info_query, default_mailer_info_verify_addr,
default_mailer_info_gen_def_ef, default_mailer_info_set_ef,
default_mailer_info_rs_hook,
MB_USE_DOMAIN
},
{ "sendmail", &(SENDMAIL_options[0]), default_set_option,
default_mailer_init, default_mailer_close, sendmail_mailer_backend,
&sendmail_mailer_path,
default_mailer_info_init, null_mailer_info_close,
sendmail_mailer_info_query, sendmail_mailer_info_verify_addr,
default_mailer_info_gen_def_ef, sendmail_mailer_info_set_ef,
default_mailer_info_rs_hook,
MB_DONT_ADD_FROM
},
{ "submitmail", &(SUBMITMAIL_options[0]), default_set_option,
submitmail_mailer_init, default_mailer_close, submitmail_mailer_backend,
&submitmail_mailer_path,
default_mailer_info_init, null_mailer_info_close,
default_mailer_info_query, default_mailer_info_verify_addr,
default_mailer_info_gen_def_ef, default_mailer_info_set_ef,
default_mailer_info_rs_hook,
MB_USE_DOMAIN
},
{ "execmail", &(EXECMAIL_options[0]), default_set_option,
default_mailer_init, default_mailer_close, execmail_mailer_backend,
&execmail_mailer_path,
default_mailer_info_init, null_mailer_info_close,
default_mailer_info_query, default_mailer_info_verify_addr,
default_mailer_info_gen_def_ef, default_mailer_info_set_ef,
default_mailer_info_rs_hook,
MB_DONT_ADD_FROM
}
};
static int valid_mailer P_((struct mailer_config *T));
static int valid_mailer(T)
struct mailer_config *T;
{
int x;
for (x = 0; x < (sizeof MAILERS) / sizeof (MAILERS[0]); x++)
if (T == &MAILERS[x])
return 1;
#ifdef USE_DLOPEN
for (x = 0; x < shared_MCF_type_count; x++)
if (T == shared_MCF_types[x].T)
return 1;
#endif
return 0;
}
static int default_mailer_info_init(M,I)
struct mailer_config *M;
struct mailer_info *I;
{
if (M->mailer_path) {
/* CHECK that mailer is executable ... */
if (! *(M->mailer_path) ||
!(*(M->mailer_path))[0] ||
0 == strcmp(*(M->mailer_path),"none")
) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmNoMailerPath,
"Mailer path for %s not specified"),
M->mailer_type);
return 0;
}
if (0 != access(*(M->mailer_path),EXECUTE_ACCESS)) {
int err = errno;
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmNotExecutable,
"%s not executable: %s"),
*(M->mailer_path),error_description(err));
return 0;
}
}
return 1;
}
static int default_mailer_info_query(M,I,query)
struct mailer_config *M;
struct mailer_info *I;
enum MI_query query;
{
/* Answer to universal queries */
switch(query) {
case MI_DONT_ADD_FROM:
return (M -> mailer_bits & MB_DONT_ADD_FROM) ? 1 : 0;
case MI_USE_DOMAIN:
return (M -> mailer_bits & MB_USE_DOMAIN) ? 1 : 0;
}
return 0; /* Not available */
}
static int sendmail_mailer_info_query(M,I,query)
struct mailer_config *M;
struct mailer_info *I;
enum MI_query query;
{
switch(query) {
case MI_HAVE_8BITMIME:
return sendmail_supported_bodytype >= have_8bit;
case MI_HAVE_BINARYMIME:
return sendmail_supported_bodytype >= have_binary;
case MI_HAVE_DSN:
return sendmail_supports_dsn;
}
return default_mailer_info_query(M,I,query);
}
static char * delay_parsing_info = NULL;
static int check_mailer P_((void));
static int check_mailer()
{
if (selected_mailer)
return 1;
if (delay_parsing_info) {
int r = mailerfunc(&delay_parsing_info,-1,0,NULL);
free(delay_parsing_info); delay_parsing_info = NULL;
return r;
}
return 0;
}
#ifdef ANSI_C
option_func mailerfunc;
#endif
int mailerfunc(value,enter,lineno,filename)
char **value;
int enter;
int lineno;
char *filename;
{
int ok = 1;
if (enter) {
int i;
char * WALK;
char * temp = safe_strdup(*value);
char * f = mime_parse_content_opts(temp, &WALK);
if (!f) {
free(temp);
return 0;
}
for (i = 0; i < (sizeof MAILERS) / sizeof (MAILERS[0]); i++)
if (0 == strcmp(f,MAILERS[i].mailer_type))
break;
if (i >= (sizeof MAILERS) / sizeof (MAILERS[0])) {
#ifdef USE_DLOPEN
if (enter > 0) {
DPRINT(Debug,8,(&Debug,"mailerfunc: Parsing delayed\n"));
selected_mailer = NULL;
delay_parsing_info = strmcpy(delay_parsing_info,*value);
free(temp);
return 1;
}
selected_mailer = loc_mailer_type(f);
if (selected_mailer)
goto found_shared;
#endif
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmUnknowMailerType,
"Unknown mailer type %s"),
f);
free(temp);
mark_flocal_changed(mailerfunc);
return 0;
}
selected_mailer = &(MAILERS[i]);
#ifdef USE_DLOPEN
found_shared:
#endif
DPRINT(Debug,8,(&Debug,
"mailerfunc: Selected %s\n",
selected_mailer->mailer_type));
while (NULL != (f = mime_parse_content_opts(NULL, &WALK))) {
char * q = strchr(f,'=');
if (q) {
char * x = q;
while (x > f && ' ' == *(x-1))
x--;
*x = '\0';
q++;
while (' ' == *q)
q++;
}
for (i = 0; selected_mailer->list[i].field; i++)
if ( 0 == strcmp(f,selected_mailer->list[i].field))
break;
if (!selected_mailer->list[i].field) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmUnknowMailerOption,
"Unknown mailer option %s"),
f);
ok = 0;
continue;
}
if (q) {
char * val = dequote_opt(q,strlen(q));
if (!selected_mailer->m_set_option(selected_mailer,
&(selected_mailer->list[i]),
val))
ok = 0;
free(val);
} else {
if (!selected_mailer->m_set_option(selected_mailer,
&(selected_mailer->list[i]),
NULL))
ok = 0;
}
}
if (selected_mailer->mailer_path &&
(!*(selected_mailer -> mailer_path) ||
!(*(selected_mailer -> mailer_path))[0] ||
0 == strcmp(*(selected_mailer -> mailer_path),"none"))) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmNoMailerPath,
"Mailer path for %s not specified"),
selected_mailer->mailer_type);
ok = 0;
}
free(temp);
} else {
if (delay_parsing_info) {
*value = delay_parsing_info;
DPRINT(Debug,8,(&Debug,
"mailerfunc: Returning delayed parsing info\n"));
} else {
/* static pointer to buffer accross invocations */
static char * return_buffer = NULL;
int i;
if (!check_mailer())
selected_mailer = &(MAILERS[0]);
return_buffer = strmcpy(return_buffer,selected_mailer->mailer_type);
for (i = 0; selected_mailer->list[i].field; i++) {
char * value = NULL;
if (selected_mailer->
list[i].value_func(selected_mailer,
& (selected_mailer->list[i]),
&value,0)) {
return_buffer = strmcat(return_buffer,"; ");
if (value) {
char *Q = elm_message(FRM("%s=%Q"),
selected_mailer->list[i].field,
value);
return_buffer = strmcat(return_buffer,Q);
free(Q);
} else
return_buffer = strmcat(return_buffer,
selected_mailer->list[i].field);
}
}
*value = return_buffer;
}
}
return ok;
}
void init_default_mailer()
{
char * p;
char * type;
/* INIT default mailer if not given on configuration file */
if (check_mailer())
return;
p = strrchr(DEFAULT_MAILER_PATH,'/');
if (p)
p++;
else {
DPRINT(Debug,1,(&Debug,
"On mailer path %s have not / character!!",
DEFAULT_MAILER_PATH));
p = DEFAULT_MAILER_PATH;
}
if (0 == strcmp(p,"sendmail"))
type = "sendmail";
else if (0 == strcmp(p,"submit"))
type = "submitmail";
else if (0 == strcmp(p,"execmail"))
type = "execmail";
else
type = "unknown";
if (!mailerfunc(&type,1,0,NULL) ||
!check_mailer()) {
DPRINT(Debug,1,(&Debug,
"Calling of mailerfunc for setting of default mailer failed"));
return;
}
if (selected_mailer -> mailer_path) {
*(selected_mailer -> mailer_path) = DEFAULT_MAILER_PATH;
if (!*(selected_mailer -> mailer_path) ||
!(*(selected_mailer -> mailer_path))[0] ||
0 == strcmp(*(selected_mailer -> mailer_path),"none")) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmNoMailerPath1,
"Give mailer path for mailer = %s on global elm.rc"),
selected_mailer->mailer_type);
/* wait that message will be noticed ... */
#if POLL_METHOD
wait_for_timeout(2);
#else
sleep(2);
#endif
}
} else {
DPRINT(Debug,1,(&Debug,"Mailer type %s do not have mailer path!\n",
selected_mailer -> mailer_type));
}
#if defined(DEFAULT_8BITMIME)
sendmail_supported_bodytype = have_8bit;
#endif
#if defined(DEFAULT_BINARYMIME)
sendmail_supported_bodytype = have_binary;
#endif
#if defined(DEFAULT_DSN)
sendmail_supports_dsn = 1;
#endif
#if defined(DEFAULT_DONT_ADD_FROM)
selected_mailer -> mailer_bits |= MB_DONT_ADD_FROM;
#else
selected_mailer -> mailer_bits &= ~MB_DONT_ADD_FROM;
#endif
#if defined(DEFAULT_USE_DOMAIN)
selected_mailer -> mailer_bits |= MB_USE_DOMAIN;
#else
selected_mailer -> mailer_bits &= ~MB_USE_DOMAIN;
#endif
}
static void delete_mail_info P_((struct mailer_info *S));
struct mailer_info *get_mailer_info() {
struct mailer_info * ret;
if (!check_mailer()) {
DPRINT(Debug,7,(&Debug,"No mailer available\n"));
return NULL;
}
DPRINT(Debug,8,(&Debug,
"get_mailer_info: Current mailer %s\n",
selected_mailer->mailer_type));
ret = safe_malloc (sizeof (*ret));
/* bzero is defined on hdrs/defs.h */
bzero((void *)ret, sizeof (*ret));
ret->magic = MAILER_INFO_magic;
ret->mailer_type = selected_mailer;
ret->delete_pending = 0;
ret->p.ptr = NULL;
ret->first = NULL;
ret->first_e = NULL;
DPRINT(Debug,7,(&Debug,
"Initialising info for %s mailer, info=%p\n",
ret->mailer_type->mailer_type,ret));
if (! ret->mailer_type->mi_init_hook(ret->mailer_type,ret)) {
/* FAILURE */
ret->delete_pending = 1;
delete_mail_info(ret);
return NULL;
}
return ret;
}
static void delete_mail_info(S)
struct mailer_info *S;
{
if (S->magic != MAILER_INFO_magic)
panic("MAILER PANIC",__FILE__,__LINE__,"delete_mail_info",
"Bad magic number (mailer info)",0);
if (S->first)
panic("MAILER PANIC",__FILE__,__LINE__,"delete_mail_info",
"mailer send state list not empty",
0);
if (S->first_e)
panic("MAILER PANIC",__FILE__,__LINE__,"delete_mail_info",
"mailer env from list not empty",
0);
if (!valid_mailer(S->mailer_type))
panic("MAILER PANIC",__FILE__,__LINE__,"delete_mail_info",
"Bad mailer type",
0);
DPRINT(Debug,7,(&Debug,
"Deleting info for %s mailer, info=%p\n",
S->mailer_type->mailer_type,S));
S->mailer_type->mi_close_hook(S->mailer_type,S);
if (S->p.ptr) {
DPRINT(Debug,1,(&Debug,
"delete_mail_info: WARNING: Private data (S->p.ptr) not free'ed\n"));
}
/* bzero is defined on hdrs/defs.h */
bzero((void *)S, sizeof (*S));
free(S);
}
static int can_delete_mailer_info P_((struct mailer_info **S));
static int can_delete_mailer_info(S)
struct mailer_info **S;
{
if ((*S)->first)
return 0;
if ((*S)->first_e)
return 0;
delete_mail_info(*S);
return 1;
}
void free_mailer_info(S)
struct mailer_info **S;
{
if (*S) {
if ((*S)->magic != MAILER_INFO_magic)
panic("MAILER PANIC",__FILE__,__LINE__,"free_mail_info",
"Bad magic number (mailer info)",0);
(*S)->delete_pending = 1;
if (! can_delete_mailer_info(S)) {
DPRINT(Debug,7,(&Debug,
"delaying deleting of mail info -> delete_pending, info=%s\n",
*S));
}
*S = NULL;
}
}
int query_mailer_info(I,query)
struct mailer_info *I;
enum MI_query query;
{
int ret;
if (I->magic != MAILER_INFO_magic)
panic("MAILER PANIC",__FILE__,__LINE__,"query_mailer_info",
"Bad magic number (mailer info)",0);
if (!valid_mailer(I->mailer_type))
panic("MAILER PANIC",__FILE__,__LINE__,"query_mailer_info",
"Bad mailer type",
0);
ret = I->mailer_type->mi_query_hook(I->mailer_type,I,query);
return ret;
}
/* -1 if connection lost
0 if OK
1 if mailer reinitialized and query_mailer_info()
need to be called again
*/
int mailer_restarted(I)
struct mailer_info *I;
{
int ret;
if (I->magic != MAILER_INFO_magic)
panic("MAILER PANIC",__FILE__,__LINE__,"mailer_restarted",
"Bad magic number (mailer info)",0);
if (!valid_mailer(I->mailer_type))
panic("MAILER PANIC",__FILE__,__LINE__,"mailer_restarted",
"Bad mailer type",
0);
ret = I->mailer_type->mi_restart_hook(I->mailer_type,I);
return ret;
}
static int default_mailer_init(M,C,I)
struct mailer_config *M;
struct mail_send_state *C;
struct mailer_info *I;
{
FILE * F;
char *tmp;
if (C->magic != MAILER_magic)
panic("MAILER PANIC",__FILE__,__LINE__,"default_mailer_init",
"Bad magic number (mail send state)",0);
tmp = give_dt_estr_as_str(&temp_dir_e,"tmpdir");
if (!tmp)
tmp = "/tmp/";
C->fname = elm_message(FRM("%selm.snd-%d"),
tmp, getpid ());
if (!C->fname) {
DPRINT(Debug,1,(&Debug,
"couldn't make temp file nam! (mail)\n"));
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCouldNotMakeTemp,
"Sorry - couldn't make temp file name."));
return 0;
}
F = safeopen_rdwr(C->fname);
if (!F) {
int err = errno;
DPRINT(Debug,1, (&Debug,
"Attempt to open file %s for writing failed! (write_header_info)\n",
C->fname));
DPRINT(Debug,1, (&Debug, "** %s **\n\n", error_description(err)));
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmErrorTryingToWrite,
"Error %s encountered trying to write to %s."),
error_description(err), C->fname);
return 0;
}
out_state_clear(& (C->OUT), STATE_out_file);
set_out_state_file(F,& (C->OUT));
return 1; /* OK */
}
static void default_mailer_close(M,C)
struct mailer_config *M;
struct mail_send_state *C;
{
/* close assigned FD FD */
if (C->OUT.magic) {
FILE *F = out_state_FILE(& (C->OUT));
if (F) {
out_state_destroy(& (C->OUT));
fclose(F);
}
}
}
void free_mail_send_state(S)
struct mail_send_state **S;
{
struct mail_send_state *X = *S;
if (X) {
int i;
if (X->magic != MAILER_magic)
panic("MAILER PANIC",__FILE__,__LINE__,"free_mail_send_state",
"Bad magic number (mail send state)",0);
if (!valid_mailer(X->mailer_type))
panic("MAILER PANIC",__FILE__,__LINE__,"free_mail_send_state",
"Bad mailer type",
0);
X->mailer_type->m_close_hook(X->mailer_type,X);
for (i = 0; i < X->addr_count; i++) {
if (X->addrs[i]) {
free(X->addrs[i]);
X->addrs[i] = NULL;
}
}
if (X->addrs) {
free(X->addrs);
X->addrs = NULL;
X->addr_count = 0;
}
if (X->fname) {
unlink(X->fname);
free(X->fname);
X->fname = NULL;
}
if (X->mail_from) {
free(X->mail_from);
X->mail_from = NULL;
}
/* destroy if assigned */
if (X->OUT.magic) {
DPRINT(Debug,1,(&Debug,
"free_mail_send_state: out state is probably leaking\n"));
out_state_destroy(& (X->OUT));
}
if (X->head) {
struct mail_send_state * prev = NULL, *walk;
for (walk = X->head->first; walk; walk = walk -> next) {
if (walk == X)
break;
prev = walk;
}
if (walk != X)
panic("MAILER PANIC",__FILE__,__LINE__,"free_mail_send_state",
"State not in list of mailer_info",0);
if (!prev)
X->head->first = X->next;
else
prev->next = X->next;
if (X->head->delete_pending && can_delete_mailer_info(& (X->head))) {
DPRINT(Debug,7,(&Debug,
"delete_pending -> deleting mail info"));
}
X->head = NULL;
X->next = NULL;
}
/* bzero is defined on hdrs/defs.h */
bzero((void *)X, sizeof (*X));
free(X);
X = NULL;
}
*S = X;
}
S_(end_handler no_end_handler)
static void no_end_handler(fd,title,rs,ret,exit_stat)
union any_fd fd;
char * title;
struct run_state *rs;
int ret;
int exit_stat;
{
/* Nothing */
}
/* Return NULL if no editor (and no value either) */
struct mailer_env_from * mailer_get_env_from(I)
struct mailer_info *I;
{
struct mailer_env_from * ret = NULL;
int flags = 0;
if (I->magic != MAILER_INFO_magic)
panic("MAILER PANIC",__FILE__,__LINE__,"mailer_env_from",
"Bad magic number (mailer info)",0);
if (!valid_mailer(I->mailer_type))
panic("MAILER PANIC",__FILE__,__LINE__,"mailer_env_from",
"Bad mailer type", 0);
if (0 != (I->mailer_type->mailer_bits & MB_ALLOW_SET_SENDER))
flags |= MAILER_ef_can_set;
if (0 != (I->mailer_type->mailer_bits & MB_REQ_DEFAULT_SENDER))
flags |= MAILER_ef_need_default;
if (0 == flags)
return NULL;
ret = safe_malloc (sizeof (*ret));
/* bzero is defined on hdrs/defs.h */
bzero((void *)ret, sizeof (*ret));
ret->magic = MAILER_ef_magic;
ret->mail_from = NULL;
ret->flags = flags;
ret->head = I;
ret->next = I->first_e;
I->first_e = ret;
if (MAILER_ef_need_default | ret->flags)
I->mailer_type->mi_def_env_from(I->mailer_type,
I,ret);
return ret;
}
void mailer_free_env_from(X)
struct mailer_env_from **X;
{
struct mailer_env_from * E = *X;
if (E) {
if (MAILER_ef_magic != E->magic)
panic("MAILER PANIC",__FILE__,__LINE__,"mailer_free_env_from",
"Bad magic number (env from)",0);
if (E->mail_from) {
free(E->mail_from);
E->mail_from = NULL;
}
if (E->head) {
struct mailer_env_from * prev = NULL, *walk;
for (walk = E->head->first_e; walk; walk = walk -> next) {
if (walk == E)
break;
prev = walk;
}
if (walk != E)
panic("MAILER PANIC",__FILE__,__LINE__,"mailer_free_env_from",
"Env from not in list of mailer_info",0);
if (!prev)
E->head->first_e = E->next;
else
prev->next = E->next;
if (E->head->delete_pending && can_delete_mailer_info(& (E->head))) {
DPRINT(Debug,7,(&Debug,
"delete_pending -> deleting mail info"));
}
E->head = NULL;
E->next = NULL;
}
E->magic = 0; /* Set bad value */
free(E);
E = NULL;
}
*X = E;
}
/* return temporary pointer value -- do not free
return NULL if currently no value set (use implicit default)
*/
CONST char * mailer_env_from_value(X,can_edit)
struct mailer_env_from *X;
int *can_edit;
{
if (MAILER_ef_magic != X->magic)
panic("MAILER PANIC",__FILE__,__LINE__,"mailer_free_env_from",
"Bad magic number (env from)",0);
if (can_edit)
*can_edit = 0 != (X->flags & MAILER_ef_can_set);
return X->mail_from;
}
int env_from_changed(X)
struct mailer_env_from *X;
{
if (MAILER_ef_magic != X->magic)
panic("MAILER PANIC",__FILE__,__LINE__,"env_from_changed",
"Bad magic number (env from)",0);
return 0 != (X->flags & MAILER_ef_changed);
}
void mailer_env_from_change(X,value)
struct mailer_env_from *X;
CONST char * value;
{
if (MAILER_ef_magic != X->magic)
panic("MAILER PANIC",__FILE__,__LINE__,"mailer_env_from_change",
"Bad magic number (env from)",0);
if (MAILER_INFO_magic != X->head->magic)
panic("MAILER PANIC",__FILE__,__LINE__,"mailer_env_from_change",
"Bad magic number (mailer info)",0);
if (!valid_mailer(X->head->mailer_type))
panic("MAILER PANIC",__FILE__,__LINE__,"mailer_env_from_change",
"Bad mailer type",0);
if (0 == (X->flags & MAILER_ef_can_set)) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmChangingEnvSenderNotAllowed,
"Changing of envelope sender for mailer %s not allowed: %s"),
X->head->mailer_type->mailer_type, value);
return;
}
if (0 != (MB_USE_DOMAIN & X->head->mailer_type->mailer_bits) &&
0 != strcmp(value,"<>") &&
NULL == strchr(value,'@')) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmEnvSenderDomainRequired,
"Mailer %s requires domain part on envelope sender: %s"),
X->head->mailer_type->mailer_type, value);
return;
}
X->head->mailer_type->mi_set_env_from(X->head->mailer_type,
X->head,X,value);
X->flags |= MAILER_ef_changed;
}
struct mail_send_state * mailer_init(addr_args,dsn,verbose,info,env_from)
char **addr_args;
int dsn;
int verbose;
struct mailer_info *info;
struct mailer_env_from *env_from;
{
struct mail_send_state *ret;
int i;
int count;
ret = safe_malloc (sizeof (*ret));
/* bzero is defined on hdrs/defs.h */
bzero((void *)ret, sizeof (*ret));
ret->magic = MAILER_magic;
if (info) {
if (info->magic != MAILER_INFO_magic)
panic("MAILER PANIC",__FILE__,__LINE__,"mailer_init",
"Bad magic number (mailer info)",0);
ret->mailer_type = info->mailer_type;
ret->head = info;
ret->next = info->first;
info->first = ret;
} else {
ret->mailer_type = selected_mailer;
ret->head = NULL;
ret->next = NULL;
}
for (count = 0; addr_args[count]; count++);
ret->addrs = safe_malloc(sizeof (* (ret->addrs)) * (count+1));
for (i = 0; i < count; i++)
ret->addrs[i] = safe_strdup(addr_args[i]);
ret->addrs[count] = NULL;
ret->addr_count = count;
ret->dsn = dsn;
ret->verbose = verbose;
ret->fname = NULL;
ret->mail_from = NULL;
if (env_from) {
if (MAILER_ef_magic != env_from->magic)
panic("MAILER PANIC",__FILE__,__LINE__,"mailer_init",
"Bad magic number (env from)",0);
if (env_from->mail_from)
ret->mail_from = safe_strdup(env_from->mail_from);
}
ret->OUT.magic = 0; /* Nothing set */
ret->orig_func = no_end_handler;
DPRINT(Debug,5,(&Debug,
"Initialising sending via %s mailer, %d recipients\n",
ret->mailer_type->mailer_type,
ret->addr_count));
if (!valid_mailer(ret->mailer_type))
panic("MAILER PANIC",__FILE__,__LINE__,"mailer_init",
"Bad mailer type",
0);
if (!ret->mailer_type->m_init_hook(ret->mailer_type,
ret,info)) {
free_mail_send_state(&ret);
}
return ret;
}
CONST char *get_mailer_path(X)
struct mail_send_state *X;
{
if (X->magic != MAILER_magic)
panic("MAILER PANIC",__FILE__,__LINE__,"get_mailer_path",
"Bad magic number (mail send state)",0);
if (X->mailer_type->mailer_path &&
*(X->mailer_type->mailer_path) &&
(*(X->mailer_type->mailer_path))[0])
return *(X->mailer_type->mailer_path);
return X->mailer_type->mailer_type;
}
out_state_t *get_mail_outfd(X)
struct mail_send_state *X;
{
if (X->magic != MAILER_magic)
panic("MAILER PANIC",__FILE__,__LINE__,"get_mail_outfd",
"Bad magic number (mail send state)",0);
return &(X->OUT);
}
S_(end_handler call_end_handler)
static void call_end_handler(fd,title,rs,ret,exit_stat)
union any_fd fd;
char * title;
struct run_state *rs;
int ret;
int exit_stat;
{
if (fd.mail_fd->magic != MAILER_magic)
panic("MAILER PANIC",__FILE__,__LINE__,"call_end_handler",
"Bad magic number (mail send state)",0);
DPRINT(Debug,7,(&Debug,
"Finished sending mail via %s mailer, ret=%d exit_stat=%d\n",
fd.mail_fd->mailer_type->mailer_type,
ret,exit_stat));
fd.mail_fd->orig_func(fd,title,rs,ret,exit_stat);
free_mail_send_state(&(fd.mail_fd));
}
static int backend_tail P_((struct mailer_config *M,
struct mail_send_state **C,
char * title,
sending_message_func *sm,
const char **argv));
static int backend_tail(M,C,title,sm,argv)
struct mailer_config *M;
struct mail_send_state **C;
char * title;
sending_message_func *sm;
CONST char **argv;
{
struct run_state RS;
int options = SY_ENV_SHELL;
int ret;
union any_fd FD;
if ((*C)->magic != MAILER_magic)
panic("MAILER PANIC",__FILE__,__LINE__,"backend_tail",
"Bad magic number (mail send state)",0);
FD.mail_fd = *C;
if (!(*C)->verbose)
options |= SY_NOTTY;
out_state_fseek (&((*C)->OUT), 0);
#ifdef _POSIX_VERSION
/* Synzronize underlying file descriptor */
fflush(out_state_FILE(&((*C)->OUT)));;
#else
seek(fileno(out_state_FILE(&((*C)->OUT))),0,0);
#endif
ret=start_run(&RS, options, argv, fileno(out_state_FILE(&((*C)->OUT))),-1);
if (ret) {
int backgrounded = 0;
int exit_code;
ret = run_already_done(&RS,&exit_code);
if (0 == ret) {
sm(0);
#ifdef BACKGROUD_PROCESSES /* We assume POSIX in here */
if (background_wait_time) {
int tmp;
DPRINT(Debug,4, (&Debug,
"Sleeping ( %d seconds ) for completion!\n",
background_wait_time));
#if POLL_METHOD
tmp = wait_for_timeout(background_wait_time);
if (!tmp) {
DPRINT(Debug,4,(&Debug,
" -- sleeping interrupted\n"));
}
#else
tmp = sleep(background_wait_time);
/* POSIX sleep returns time in left on
* interrupt -- when sendmail terminates
* we will get interrupt (SIGCHLD signal)
*/
if (tmp > 0) {
DPRINT(Debug,4,(&Debug,
" -- sleeping interrupted, %d seconds left!\n",
tmp));
} else if (tmp < 0) {
DPRINT(Debug,4,(&Debug,
" -- sleeping failed?\n"));
}
#endif
ret = run_already_done(&RS,&exit_code);
if (0 == ret)
ret = maybe_background(&RS,&exit_code,
FD,title,call_end_handler);
if (0 == ret) {
sm(1);
backgrounded = 1;
*C = NULL; /* call_end_handler may free
mail_send_state
*/
}
} else
#endif
ret = wait_end(&RS,&exit_code);
}
if (!backgrounded) {
call_end_handler(FD,title,&RS,ret,exit_code);
*C = NULL; /* call_end_handler free'ed mail_send_state
*/
}
} else {
if (RS.save_errno)
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmFailErrno,
"Failed: %.30s: %.40s"),
argv[0],error_description(RS.save_errno));
else
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCantStart,
"Can't start %.30s"),
argv[0]);
free_mail_send_state(C);
}
return ret;
}
static int unknown_mailer_backend(M,C,encoding_top,title,sm)
struct mailer_config *M;
struct mail_send_state **C;
int encoding_top;
char * title;
sending_message_func *sm;
{
char *mailerflags[20];
CONST char **argv;
int mf_idx=0;
int r;
if ((*C)->magic != MAILER_magic)
panic("MAILER PANIC",__FILE__,__LINE__,"unknown_mailer_backend",
"Bad magic number (mail send state)",0);
mailerflags[mf_idx++] = unknown_mailer_path;
mailerflags[mf_idx] = NULL;
argv = join_argv(mailerflags,(*C)->addrs);
r = backend_tail(M,C,title,sm,argv);
free(argv);
return r;
}
static int sendmail_mailer_backend(M,C,encoding_top,title,sm)
struct mailer_config *M;
struct mail_send_state **C;
int encoding_top;
char * title;
sending_message_func *sm;
{
char t[80];
int r;
char *mailerflags[22];
CONST char **argv;
int mf_idx=0;
if ((*C)->magic != MAILER_magic)
panic("MAILER PANIC",__FILE__,__LINE__,"sendmail_mailer_backend",
"Bad magic number (mail send state)",0);
mailerflags[mf_idx++] = sendmail_mailer_path;
mailerflags[mf_idx++] = "-oi";
mailerflags[mf_idx++] = "-oem";
if ((*C)->mail_from && 0 != ( M -> mailer_bits & MB_ALLOW_SET_SENDER)) {
mailerflags[mf_idx++] = "-f";
mailerflags[mf_idx++] = (*C)->mail_from;
}
if ((*C)->verbose)
mailerflags[mf_idx++] = "-v";
if (metoo)
mailerflags[mf_idx++] = "-om";
if (sendmail_supported_bodytype >= have_8bit) {
if (encoding_top == ENCODING_8BIT)
mailerflags[mf_idx++] = "-B8BITMIME";
}
if (sendmail_supported_bodytype >= have_binary) {
if (encoding_top == ENCODING_BINARY)
/* With -BBINARYMIME lines must terminate with \r\n
* Unix's \n is _NOT_ sufficient - K E H */
mailerflags[mf_idx++] = "-BBINARYMIME";
}
if (sendmail_supports_dsn) {
if ((*C)->dsn & DSN_FULL) {
mailerflags[mf_idx++] = "-R";
mailerflags[mf_idx++] = "full";
} else if ((*C)->dsn & DSN_HDRS) {
mailerflags[mf_idx++] = "-R";
mailerflags[mf_idx++] = "hdrs";
}
if ((*C)->dsn & DSN_NEVER) {
mailerflags[mf_idx++] = "-N";
mailerflags[mf_idx++] = "never";
} else if ((*C)->dsn & (DSN_SUCCESS|DSN_FAILURE|DSN_DELAY)) {
t[0] = '\0';
if ((*C)->dsn & DSN_SUCCESS)
strfcat(t,"success", sizeof t);
if ((*C)->dsn & DSN_FAILURE) {
if (t[0]) strfcat(t,",", sizeof t);
strfcat(t,"failure", sizeof t);
}
if ((*C)->dsn & DSN_DELAY) {
if (t[0]) strfcat(t,",", sizeof t);
strfcat(t,"delay", sizeof t);
}
mailerflags[mf_idx++] = "-N";
mailerflags[mf_idx++] = t;
}
}
mailerflags[mf_idx++] = "--";
mailerflags[mf_idx] = NULL;
argv = join_argv(mailerflags,(*C)->addrs);
r = backend_tail(M,C,title,sm,argv);
free(argv);
return r;
}
/* Return
-1 if caller should result with default data (return 1)
-2 if caller should just test passwd
0 if failure
1 is succees
*/
static int sendmail_mailer_info_verify_addr(M,I,text,result)
struct mailer_config *M;
struct mailer_info *I;
CONST char *text;
struct addr_item *result;
{
CONST char *mailerflags[5];
int mf_idx=0;
struct run_state RS;
int ret,exit_code;
if (I->magic != MAILER_INFO_magic)
panic("MAILER PANIC",__FILE__,__LINE__,
"sendmail_mailer_info_verify_addr",
"Bad magic number (mailer info)",0);
if (!sendmail_verify_address) {
DPRINT(Debug,4,(&Debug,
"Don't call %s for verify -- falling back to default addr verify\n",
sendmail_mailer_path));
return -2; /* caller does job */
}
mailerflags[mf_idx++] = sendmail_mailer_path;
mailerflags[mf_idx++] = "-bv";
/* Do not treat -xyc as option */
mailerflags[mf_idx++] = "--";
mailerflags[mf_idx++] = text;
mailerflags[mf_idx] = NULL;
ret = start_run(&RS,SY_NOTTY|SY_ENV_SHELL,mailerflags,-1,-1);
if (!ret) {
DPRINT(Debug,4,(&Debug,
"Can't run %s for address verify -- falling back to default addr verify\n",
sendmail_mailer_path));
return -2; /* caller does job */
}
ret = wait_end(&RS,&exit_code);
if (ret < 0) {
DPRINT(Debug,4,(&Debug,
"%s died on signal %d -- falling back to default addr verify\n",
sendmail_mailer_path,-ret));
return -2; /* caller does job */
}
if (0 == ret) {
DPRINT(Debug,4,(&Debug,
"%s lost? -- falling back to default addr verify\n",
sendmail_mailer_path));
return -2; /* caller does job */
}
/* -1 is success, but caller should fill fullname */
return exit_code == 0 ? -1 : 0;
}
static void sendmail_mailer_info_set_ef(M,I,X,value)
struct mailer_config *M;
struct mailer_info *I;
struct mailer_env_from *X;
CONST char *value;
{
CONST char *mailerflags[5];
int mf_idx=0;
struct run_state RS;
int ret,exit_code;
if (0 == strcmp(value,"<>")) {
/* Null envelope sender is only valid as sender (not as recipient)
so do not verify it
*/
X->mail_from = strmcpy(X->mail_from,value);
return;
}
if (I->magic != MAILER_INFO_magic)
panic("MAILER PANIC",__FILE__,__LINE__,
"sendmail_mailer_info_set_ef",
"Bad magic number (mailer info)",0);
mailerflags[mf_idx++] = sendmail_mailer_path;
mailerflags[mf_idx++] = "-bv";
/* Do not treat -xyc as option */
mailerflags[mf_idx++] = "--";
mailerflags[mf_idx++] = value;
mailerflags[mf_idx] = NULL;
ret = start_run(&RS,SY_NOTTY|SY_ENV_SHELL,mailerflags,-1,-1);
if (!ret) {
DPRINT(Debug,4,(&Debug,
"Can't run %s for address verify -- sendmail_mailer_info_set_ef failed\n",
sendmail_mailer_path));
goto failure;
}
ret = wait_end(&RS,&exit_code);
if (ret < 0) {
DPRINT(Debug,4,(&Debug,
"%s died on signal %d -- sendmail_mailer_info_set_ef failed\n",
sendmail_mailer_path,-ret));
goto failure;
}
if (0 == ret) {
DPRINT(Debug,4,(&Debug,
"%s lost? -- sendmail_mailer_info_set_ef failed\n",
sendmail_mailer_path));
goto failure;
}
if (exit_code == 0) {
X->mail_from = strmcpy(X->mail_from,value);
DPRINT(Debug,8,(&Debug,
" .. envelope sender=%s\n",
X->mail_from));
} else {
DPRINT(Debug,4,(&Debug,
"... exit code %d -- envelope sender address %s bad?\n",
exit_code,value));
failure:
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmChangingSendmEnvSenderFailed,
"Changing of envelope sender for sendmail failed: %s"),
value);
}
}
static int submitmail_mailer_init(M,C,I)
struct mailer_config *M;
struct mail_send_state *C;
struct mailer_info *I;
{
int i;
if (C->magic != MAILER_magic)
panic("MAILER PANIC",__FILE__,__LINE__,"submitmail_mailer_init",
"Bad magic number (mail send state)",0);
if (!default_mailer_init(M,C,I))
return 0;
/* WARNING: Untested --
code copied from do_mmdf_addresses() on src/reply.c
*/
for (i = 0; i < C -> addr_count; i++) {
state_puts(C -> addrs[i],&(C->OUT)); state_putc('\n',&(C->OUT));
}
state_putc('\n',&(C->OUT));
return 1; /* OK */
}
static int submitmail_mailer_backend(M,C,encoding_top,title,sm)
struct mailer_config *M;
struct mail_send_state **C;
int encoding_top;
char * title;
sending_message_func *sm;
{
int r;
CONST char *mailerflags[20];
int mf_idx=0;
if ((*C)->magic != MAILER_magic)
panic("MAILER PANIC",__FILE__,__LINE__,"submitmail_mailer_backend",
"Bad magic number (mail send state)",0);
/* WARNING: Untested --
code copied from mail_backend() on src/mailmsg2.c
*/
mailerflags[mf_idx++] = submitmail_mailer_path;
mailerflags[mf_idx++] = "-mlrnv";
mailerflags[mf_idx] = NULL;
r = backend_tail(M,C,title,sm,mailerflags);
return r;
}
static int execmail_mailer_backend(M,C,encoding_top,title,sm)
struct mailer_config *M;
struct mail_send_state **C;
int encoding_top;
char * title;
sending_message_func *sm;
{
int r;
char *mailerflags[20];
CONST char **argv;
int mf_idx=0;
if ((*C)->magic != MAILER_magic)
panic("MAILER PANIC",__FILE__,__LINE__,"execmail_mailer_backend",
"Bad magic number (mail send state)",0);
/* WARNING: Untested --
code copied from mail_backend() on src/mailmsg2.c
*/
mailerflags[mf_idx++] = execmail_mailer_path;
if ((*C)->verbose)
mailerflags[mf_idx++] = "-d";
if (metoo)
mailerflags[mf_idx++] = "-m";
argv = join_argv(mailerflags,(*C)->addrs);
r = backend_tail(M,C,title,sm,argv);
free(argv);
return r;
}
int mail_backend2(mail_fd,func,encoding_top,title,
sm)
struct mail_send_state **mail_fd;
end_handler *func;
int encoding_top;
char * title;
sending_message_func *sm;
{
int r;
if ((*mail_fd)->magic != MAILER_magic)
panic("MAILER PANIC",__FILE__,__LINE__,"mail_backend2",
"Bad magic number (mail send state)",0);
DPRINT(Debug,7,(&Debug,
"Sending mail via %s mailer, %d recipients\n",
(*mail_fd)->mailer_type->mailer_type,
(*mail_fd)->addr_count));
(*mail_fd)->orig_func = func;
if (!valid_mailer((*mail_fd)->mailer_type))
panic("MAILER PANIC",__FILE__,__LINE__,"mail_backend2",
"Bad mailer type",
0);
r = (*mail_fd)->mailer_type->m_backend_hook((*mail_fd)->mailer_type,
mail_fd,encoding_top,
title,sm);
return r;
}
# ifdef PWDINSYS
# include <sys/pwd.h>
# else
# include <pwd.h>
# endif
/* Should return 1 if verify succees and fields of result to be filled
-- caller should free fields of result
Returns 0 on failure
*/
int verify_mailer_addr(I,text,result, errcode)
struct mailer_info *I;
CONST char *text;
struct addr_item *result;
enum mailer_errcode * errcode;
{
int ret = 0;
if (I->magic != MAILER_INFO_magic)
panic("MAILER PANIC",__FILE__,__LINE__,"verify_mailer_addr",
"Bad magic number (mailer info)",0);
/* bzero is defined on hdrs/defs.h */
bzero((void *)result, sizeof (*result));
result -> addr = NULL;
result -> fullname = NULL;
result -> comment = NULL;
*errcode = MAILER_NOT_AVAIL;
if (!valid_mailer(I->mailer_type))
panic("MAILER PANIC",__FILE__,__LINE__,"verify_mailer_addr",
"Bad mailer type",
0);
/* Returns
-1 if caller should result with default data (return 1)
-2 if caller should just test passwd
0 if failure
1 is succees
*/
ret = I->mailer_type->mi_verify_addr(I->mailer_type,I,text,result);
DPRINT(Debug,7,(&Debug,"Address %s verify result %d%s\n",
text,ret,
ret < 0 ? " (use default processing)" : ""));
if (result->addr) {
DPRINT(Debug,7,(&Debug,
" ... resulting address %s\n",
result->addr));
}
if (0 == ret)
*errcode = MAILER_NOT_EXIST;
if (ret > 0)
*errcode = MAILER_OK;
if (ret < 0) {
struct passwd * P = getpwnam(text);
if (P)
*errcode = MAILER_OK;
if (P && ! result -> fullname ) {
char * N = get_fullname1(P,text);
/* FIXME: Posible wrong charset */
if (N) {
result -> fullname = new_string2(system_charset,s2us(N));
}
ret = 1;
} else {
ret = ret == -1 ? 1 : 0;
}
}
if (ret && !result->addr) {
DPRINT(Debug,7,(&Debug,
" ... filling resulting address\n",
text));
result->addr = safe_strdup(text);
if (I->mailer_type->mi_query_hook(I->mailer_type,I,
MI_USE_DOMAIN)) {
result->addr = strmcat(result->addr,"@");
result->addr = strmcat(result->addr,hostfullname);
DPRINT(Debug,7,(&Debug,
" ... %s => %s\n",
text,result->addr));
}
}
return ret;
}
/* Should return 1 if verify succees and fields of result to be filled
-- caller should free fields of result
Returns 0 on failure
*/
int verify_mailer_domaddr(I,text,result, errcode)
struct mailer_info *I;
CONST char *text;
struct addr_item *result;
enum mailer_errcode * errcode;
{
int ret = 0;
if (I->magic != MAILER_INFO_magic)
panic("MAILER PANIC",__FILE__,__LINE__,"verify_mailer_domaddr",
"Bad magic number (mailer info)",0);
/* bzero is defined on hdrs/defs.h */
bzero((void *)result, sizeof (*result));
result -> addr = NULL;
result -> fullname = NULL;
result -> comment = NULL;
*errcode = MAILER_NOT_AVAIL;
if (!valid_mailer(I->mailer_type))
panic("MAILER PANIC",__FILE__,__LINE__,"verify_mailer_domaddr",
"Bad mailer type",
0);
/* Returns
-1 if caller should result with default data (return 1)
-2 if caller should just test passwd
0 if failure
1 is succees
*/
ret = I->mailer_type->mi_verify_addr(I->mailer_type,I,text,result);
DPRINT(Debug,7,(&Debug,"Address %s verify result %d%s\n",
text,ret,
ret < 0 ? " (use default processing)" : ""));
if (result->addr) {
DPRINT(Debug,7,(&Debug,
" ... resulting address %s\n",
result->addr));
}
if (0 == ret)
*errcode = MAILER_NOT_EXIST;
if (ret > 0)
*errcode = MAILER_OK;
if (-1 == ret)
ret = 1;
if (-2 == ret)
ret = 0;
if (ret && !result->addr) {
DPRINT(Debug,7,(&Debug,
" ... filling resulting address\n",
text));
result->addr = safe_strdup(text);
}
return ret;
}
char * kludge_addr(char **addr) {
char * ptr = *addr;
int l = strlen(ptr);
char *res;
ptr = safe_realloc(ptr,l + 1 + 2 + l + 1);
res = ptr + l + 1;
res[0] = '<';
strfcpy(res+1,ptr,l+1);
res[l+1] = '>';
res[l+2] = '\0';
*addr = ptr;
return res;
}
char **argv_from_headers (headers)
struct mailing_headers * headers;
{
int count =
headers->to.addrs_len +
headers->cc.addrs_len + headers->bcc.addrs_len;
char **res;
int idx = 0,i;
struct addr_item *p;
DPRINT(Debug,6,
(&Debug, "argv_from_headers, count=%d\n",count));
res = safe_malloc((count + 1) * sizeof (char *));
dump_expanded_address(6,"argv_from_headers -- enter (to)",headers->to);
for (p = headers->to.addrs;
p < headers->to.addrs + headers->to.addrs_len;
p++) {
if (p->addr[0] == '-' || p->addr[0] == '@' ||
p->addr[0] == '\0')
/* Modify p->addr so that there is space
* alloced also for <addr> form
*/
res[idx++] = kludge_addr(&p->addr);
else
res[idx++] = p->addr;
}
dump_expanded_address(6,"argv_from_headers -- enter (cc)",headers->cc);
for (p = headers->cc.addrs;
p < headers->cc.addrs + headers->cc.addrs_len;
p++) {
if (p->addr[0] == '-' || p->addr[0] == '@' ||
p->addr[0] == '\0')
/* Modify p->addrs so that there is space
* alloced also for <addr> form
*/
res[idx++] = kludge_addr(&p->addr);
else
res[idx++] = p->addr;
}
dump_expanded_address(6,"argv_from_headers -- enter (bcc)",headers->bcc);
for (p = headers->bcc.addrs;
p < headers->bcc.addrs + headers->bcc.addrs_len;
p++) {
if (p->addr[0] == '-' || p->addr[0] == '@' ||
p->addr[0] == '\0')
/* Modify p->addrs so that there is space
* alloced also for <addr> form
*/
res[idx++] = kludge_addr(&p->addr);
else
res[idx++] = p->addr;
}
res[idx] = NULL;
DPRINT(Debug,6,
(&Debug, " idx=%d\n",idx));
for (i = 0; i < idx; i++)
DPRINT(Debug,6,
(&Debug, " [%d]=%s\n",i,res[i]));
dump_expanded_address(7,"argv_from_headers -- leave (to)",headers->to);
dump_expanded_address(7,"argv_from_headers -- leave (cc)",headers->cc);
dump_expanded_address(7,"argv_from_headers -- leave (bcc)",headers->bcc);
return res;
}
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1