/* $Id: smtp.cpp,v 1.38 2004/01/02 03:54:01 fesnel Exp $ */
/*******************************************************************************
 *   This program is part of a library used by the Archimedes email client     * 
 *                                                                             *
 *   Copyright : (C) 1995-1998 Gennady B. Sorokopud (gena@NetVision.net.il)    *
 *               (C) 1995 Ugen. J. S. Antsilevich (ugen@latte.worldbank.org)   *
 *               (C) 1998-2004 by the Archimedes Project                       *
 *                   http://sourceforge.net/projects/archimedes                *
 *                                                                             *
 *             --------------------------------------------                    *
 *                                                                             *
 *   This program is free software; you can redistribute it and/or modify      *
 *   it under the terms of the GNU Library General Public License as published *
 *   by the Free Software Foundation; either version 2 of the License, or      *
 *   (at your option) any later version.                                       *
 *                                                                             *
 *   This program is distributed in the hope that it will be useful,           *
 *   but WITHOUT ANY WARRANTY, without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *   GNU Library General Public License for more details.                      *
 *                                                                             *
 *   You should have received a copy of the GNU Library General Public License *
 *   along with this program; if not, write to the Free Software               *
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307, USA.  *
 *                                                                             *
 ******************************************************************************/


#include <fmail.h>
#include <umail.h>
#include <cfgfile.h>
#include <connectionManager.h>
#include <smtp_auth.h>

#ifdef USE_GPASSWD
#include <gpasswd.h>
extern gPasswd Passwd;
#endif

#ifdef WITH_THREADS
#include <pthread.h>
extern pthread_mutex_t send_mutex;
#endif

extern cfgfile Config;
extern class connectionManager ConMan;

void get_smtp_host_info (char * , struct _smtp_account * *);

static struct _smtp_account *smtp_account; 
static int  auth_required = 0;
static char response[255];
static char smtp_auth_list[255];
static char true_host[MAX_HOST+1];

static int smtpsock = -1;
static int smtpcap = 0;
#define SMTP_ESMTP  0x01    /* ESMTP server     */
#define SMTP_DSN    0x02    /* DSN is supported */
FILE *smtp_in = NULL;
FILE *smtp_out = NULL;

#if STDC_HEADERS || defined(HAVE_STDARG_H)
int smtp_command(char *fmt, ...)
#else
int smtp_command(char *fmt, va_dcl va_list)
#endif
{
	int res, ehlo = 0;
	char buf[255];
	va_list ap;

#if STDC_HEADERS || defined(HAVE_STDARG_H)
	va_start(ap, fmt);
#else
	va_start(ap);
#endif

	if (fmt) {
		vsnprintf(response, sizeof(response), fmt, ap);

		if (logging & LOG_SMTP)
			display_msg(MSG_LOG, "smtp", "-> %-.127s", response);
		if (putline(response, smtp_out) == -1)
			return -1;
	}

	if (!strncmp(response, "EHLO ", 5))
		ehlo = 1;

	response[0] = '\0';
	response[3] = '-';

	while (response[3] == '-') {
		if (getline(response, sizeof(response), smtp_in) == NULL)
			return -1;

		if (logging & LOG_SMTP)
			display_msg(MSG_LOG, "smtp", "<- %-.127s", response);

		if (ehlo) {
			if (response[3] != '-')
				break;

			res = atoi(response);
			if (res != 250)
				continue;

			snprintf(buf, sizeof(buf), "%s", response + 4);
			if (!strncasecmp(buf, "DSN", 3))
				smtpcap |= SMTP_DSN;

			else if (!strncasecmp(buf, "AUTH", 4)) 
			{
				int maxlen = sizeof(smtp_auth_list) - 1 ;
				auth_required = 1;   /* Server requires authentication */
				strncpy(smtp_auth_list, (const char *) (buf+5) , maxlen);
				smtp_auth_list[maxlen] = '\0';
			}
		}
	}

	res = -1;
	sscanf(response, "%d%s", &res, buf);

	if (res == -1) {
		display_msg(MSG_WARN, "smtp", "%-.127s", response);
		return -1;
	}

	return res;
}

void smtp_close()
{
	ConMan.del_cinfo(smtpsock);
	smtpsock = -1;

	if (smtp_in != NULL)
		fclose(smtp_in);

	smtp_in = NULL;
	smtp_out = NULL;
}

void smtp_end()
{
	if (smtp_command("QUIT") != 221)
		display_msg(MSG_WARN, "smtp", "%-.127s", response);

	smtp_close();
}


int smtp_init(struct _mail_msg *msg)
{
	char bfr[1024];
	char default_smtp_port[] = DEFAULT_SMTP_PORT;
	char *smtp_port;
	char *buf=bfr;
	char *ptr,*addr ;
	char *smtp_host;
	char *proxy_host, *proxy_port;
	char *p, *p1;

	bfr[0] = '\0';

	if (smtpsock != -1) {
		display_msg(MSG_WARN, "smtp", "SMTP busy");
		return -1;
	}

	strncpy(bfr, Config.get("smtphost", "127.0.0.1").c_str(), sizeof(bfr));
	while((ptr=strchr(buf,','))!=0L)
	{
		*ptr++=0;
		if((addr=strchr(buf,'+'))!=0L)
		{
			*addr++=0;
			if(strstr(msg->header->From->addr,buf))
			{
				buf=addr;
				break;
			}
		}
		buf=ptr;
	}

	smtp_host = buf;
	smtp_port = const_cast<char *>(Config.get("smtport",DEFAULT_SMTP_PORT).c_str());
	if (!smtp_port)
		smtp_port = default_smtp_port;

	/* check if smtp_host  corresponds to a smtp account */
	smtp_account = NULL;
	get_smtp_host_info (smtp_host, &smtp_account) ;
	if (smtp_account) {
		if ( smtp_account->flags & SMTP_AUTH && 
		    smtp_account->flags & SMTP_AUTH_SRC ) {
			char * name = smtp_account->src_name;
			if (get_src_info( name, smtp_account->username, 
				smtp_account->password) ) {
				display_msg(MSG_WARN, "smtp", 
				    "could not get authentication data from source account\n%s",
				    name);
				smtp_close();
				return -1;
			}
		}
	  
		smtp_host = smtp_account->hostname ;
		if (smtp_account->service)
			smtp_port = smtp_account->service;
	}	

	/* 
	   at this point we could implement a secure tunnel from a local
	   proxy_host:proxy_port to the remote smtp_host:smtp_port
	   using e.g. stunnel, and talk to  the local 
	   proxy_host:proxy_port instead... (not yet implemented)
	*/
	proxy_host = smtp_host;
	proxy_port = smtp_port;
	smtpsock = ConMan.host_connect(proxy_host, proxy_port, NULL); 

	if (smtpsock == -1)
		return -2;

	if ((smtp_in = fdopen(smtpsock, "r+")) == NULL) {
		display_msg(MSG_WARN, "smtp", "fdopen failed");
		smtp_close();
		return -1;
	}

	smtp_out = smtp_in;

	true_host[0] = '\0';
	if (smtp_command(NULL) != 220) {
		display_msg(MSG_WARN, "smtp", "%-.127s", response);
		smtp_close();
		return -1;
	}

	/* if host  is an ESMTP server, store the name it reports */
	p = response + 4;
	if ((p1 = strstr(p,"ESMTP")) != NULL ) {
		*p1 = '\0';
		strncpy(true_host,p,MAX_HOST);
		true_host[MAX_HOST] = '\0';
	}

	/* initialize  global authentication  variables */
	auth_required = 0;
	smtp_auth_list[0] = '\0';

	smtpcap = 0;
	if (smtp_command("EHLO %s", getmyhostname()) != 250) {
		if (smtp_command("HELO %s", getmyhostname()) != 250) {
			display_msg(MSG_WARN, "smtp", "%-.127s", response);
			smtp_close();
			return -1;
		}
	} else {
		/* ESMTP server */
		smtpcap |= SMTP_ESMTP;

	}
	/* do smpt RFC2554 or "AUTH=LOGIN" authentication if necessary,
	 and if smtp_account is configured for this */
	if(smtp_account) {
		if (auth_required && (smtp_account->flags & SMTP_AUTH )) {
			if (smtp_authenticate(smtp_host,smtp_auth_list)){
				display_msg(MSG_WARN, "smtp",
					    "required authentication failed"
					    " (smtp account \"%s\")",
					    smtp_account->name);
			}
		}
	}
	return 0;
}

int send_rcpt_to(struct _mail_addr *addr, int usedsn)
{
	if (usedsn) {
		if (smtp_command
		    ("RCPT TO: <%s> NOTIFY=SUCCESS,FAILURE,DELAY ORCPT=rfc822;%s",
			addr->addr, addr->addr) != 250) {
			display_msg(MSG_WARN, "smtp", "%-.127s", response);
			return -1;
		}
	} else if (smtp_command("RCPT TO: <%s>", addr->addr) != 250) {
		display_msg(MSG_WARN, "smtp", "%-.127s", response);
		return -1;
	}

	return 0;
}

void *smtp_send_message(void *arg)
{
	struct _mail_msg *msg = (struct _mail_msg *) arg;
	struct _mail_addr *addr;
	struct _head_field *hf;
	time_t lt;
	int retval, usedsn = 0;
	char id[32], buf[100], *envid;

#ifdef WITH_THREADS
	if (pthread_mutex_trylock(&send_mutex) == EBUSY) {
		display_msg(MSG_LOG,NULL, "Send Already In Progress, Must Wait Till It Completes");
		return NULL;        //A Send Thread is already in progress
	}
#endif
	
	lt = time(NULL);

	switch (smtp_init(msg)) {
	case -1:
		send_message_finalizer(msg, -1);
		return NULL;
		
	case -2:
		send_message_finalizer(msg, -2);
			return NULL;
	}
	
	if ((smtpcap & SMTP_ESMTP) && (smtpcap & SMTP_DSN) &&
	    ((hf = find_field(msg, "Return-Receipt-To")) != NULL) &&
		Config.getInt("smtpdsn", 0)) {
		usedsn = 1;
		delete_all_fields(msg, "X-DSN-Envid");
		delete_all_fields(msg, "Return-Receipt-To");
	}
	
	if (usedsn) {
		if ((hf = find_field(msg, "Message-ID")) == NULL) {
			strftime(id, 31, "%Y%m%d%H%M%S", localtime(&lt));
			snprintf(buf, sizeof(buf), "<XFMail-DSN.%s.%s>", id,
				 msg->header->From->addr);
			add_field(msg, "Message-ID", buf);
			envid = buf;
		}
		envid = hf->f_line;
		retval = smtp_command("MAIL FROM: <%s> RET=HDRS ENVID=%s",
				      msg->header->From->addr, envid);
	} else {
		retval = smtp_command("MAIL FROM: <%s>", msg->header->From->addr);
	}

	if(retval == 530) {  /* server requires smtp authentication */
		int retry = 0;
		while (retry < 3) {
			retry ++;
			retval = smtp_authenticate(true_host,smtp_auth_list);
			if (retval != 535 || retry == 3)
				break;
			display_msg(MSG_WARN, "smtp",
				    "authentication attempt %d"
				    " failed (3 allowed)",
				    retry);
		}
		if (!retval)  /* successful authentication */
			if (usedsn) {
				retval = smtp_command("MAIL FROM: <%s> RET=HDRS ENVID=%s",
						      msg->header->From->addr, envid);
			} else {
				retval = smtp_command("MAIL FROM: <%s>",
						      msg->header->From->addr);
			}
	}

	if (retval != 250) {
		display_msg(MSG_WARN, "smtp", "%-.127s", response);
		smtp_end();
		send_message_finalizer(msg, -1);
		return NULL;
	}

	addr = msg->header->To;
	while (addr) {
	if (send_rcpt_to(addr, usedsn) == -1) {
		smtp_end();
		send_message_finalizer(msg, -1);
		return NULL;
	}
	addr = addr->next_addr;
	}

	addr = msg->header->Cc;
	while (addr) {
	if (send_rcpt_to(addr, usedsn) == -1) {
		smtp_end();
		send_message_finalizer(msg, -1);
		return NULL;
	}
	addr = addr->next_addr;
	}

	addr = msg->header->Bcc;
	while (addr) {
	if (send_rcpt_to(addr, usedsn) == -1) {
		smtp_end();
		send_message_finalizer(msg, -1);
		return NULL;
	}
	addr = addr->next_addr;
	}

	if (smtp_command("DATA") != 354) {
		display_msg(MSG_WARN, "smtp", "%-.127s", response);
		smtp_end();
		send_message_finalizer(msg, -1);
		return NULL;
	}

	if (smtp_message(msg, smtp_out) == -1) {
		smtp_end();
		send_message_finalizer(msg, -1);
		return NULL;
	}

	if (smtp_command(".") != 250) {
		display_msg(MSG_WARN, "smtp", "%-.127s", response);
		smtp_end();
		send_message_finalizer(msg, -1);
		return NULL;
	}

	smtp_end();
	send_message_finalizer(msg, 0);
	return NULL;
}

int smtp_news_addr(struct _news_addr *addr, char *str, FILE * file)
{
	char buf[255];
	int alen = 0, i = 0;

	if (!file)
		return -1;

	*buf = '\0';

	if (str) {
		snprintf(buf, sizeof(buf), "%s: ", str);
		alen += (strlen(str) + 2);
	}

	while (addr) {
		if (i && (alen + strlen(addr->name) > 78)) {
			strcat(buf, ",");
			if (putline(buf, file) == -1)
				return -1;
			strcpy(buf, " ");
			alen = 1;
		} else if (i) {
			strcat(buf, ",");
			alen += 1;
		}

		strcat(buf, addr->name);
		alen += strlen(addr->name);

		i++;
		addr = addr->next;
	}

	if (alen) {
		if (putline(buf, file) == -1)
			return -1;
	}

	return 0;
}

int smtp_addr(mail_addr * addr, char *str, FILE * file, int charset)
{
	u_int st, st1;
	u_int alen, quote;
	int len;
	char buf[255], acomm[255];
	char *p, *p1, *p2;

	if (!addr)
		return -1;

	if (file == NULL)
		return -1;

	st = st1 = 0;

	if (addr->name && strpbrk(addr->name, ".,;\'\"()<>") &&
	    (*addr->name != '\'') && (*addr->name != '\"'))
		quote = 1;
	else
		quote = 0;

	if (charset >= -1) {
		if ((p = rfc1522_encode(addr->comment, charset, -1)) !=
		    addr->comment) {
			strcpy(acomm, p);
			p = acomm;
		} else
			p = NULL;

		if ((p1 = rfc1522_encode(addr->name, charset, -1)) == addr->name)
			p1 = NULL;
		else
			quote = 0;
	} else {
		p = NULL;
		p1 = NULL;
	}

	if (addr->name && addr->comment)
		snprintf(buf, sizeof(buf), "%s: %s%s%s <%s> (%s)%s", str,
		    quote ? "\"" : "", p1 ? p1 : addr->name,
		    quote ? "\"" : "", addr->addr, p ? p : addr->comment,
		    addr->next_addr ? "," : "");
	else if (!addr->name && !addr->comment)
		snprintf(buf, sizeof(buf), "%s: %s%s", str, addr->addr,
		    addr->next_addr ? "," : "");
	else if (addr->name)
		snprintf(buf, sizeof(buf), "%s: %s%s%s <%s>%s", str,
		    quote ? "\"" : "", p1 ? p1 : addr->name,
		    quote ? "\"" : "", addr->addr,
		    addr->next_addr ? "," : "");
	else
		snprintf(buf, sizeof(buf), "%s: (%s) <%s>%s", str,
		    p ? p : addr->comment, addr->addr,
		    addr->next_addr ? "," : "");

	p = NULL;

	if (putline(buf, file) == -1)
		return -1;

	if (!addr->next_addr)
		return 0;

	st1 += strlen(buf);

	addr = addr->next_addr;

	p2 = buf;

	while (addr) {

		if (addr->name && strpbrk(addr->name, ".,;\'\"()<>") &&
		    (*addr->name != '\'') && (*addr->name != '\"'))
			quote = 1;
		else
			quote = 0;

		if (charset >= -1) {
			if ((p = rfc1522_encode(addr->comment, -1, -1)) !=
			    addr->comment) {
				strcpy(acomm, p);
				p = acomm;
			} else
				p = NULL;

			if ((p1 = rfc1522_encode(addr->name, -1, -1)) == addr->name)
				p1 = NULL;
			else
				quote = 0;
		} else {
			p = NULL;
			p1 = NULL;
		}

		alen = strlen(addr->addr);
		if (addr->name)
			alen += (strlen(p1 ? p1 : addr->name) + 4);

		if (addr->comment)
			alen += (strlen(p ? p : addr->comment) + 4);

		if (quote)
			alen += 2;

		if ((st1 - st + alen) > 80) {
			st = st1;
			if (putline(buf, file) == -1) {
				if (p)
					free(p);
				return -1;
			}
			p2 = buf;
			*p2 = '\t';
			p2++;
			*p2 = '\0';
			st1 += 3;
		} else {
			*p2 = ' ';
			p2++;
			*p2 = '\0';
			st1 += 2;
		}

		if (!addr->name && !addr->comment)
			sprintf(p2, "%s%s", addr->addr, addr->next_addr ? "," : "");
		else if (addr->name && (p ? p : addr->comment))
			sprintf(p2, "%s%s%s <%s> (%s)%s", quote ? "\"" : "",
			    p1 ? p1 : addr->name, quote ? "\"" : "", addr->addr,
			    p ? p : addr->comment, addr->next_addr ? "," : "");
		else if (addr->name)
			sprintf(p2, "%s%s%s <%s>%s", quote ? "\"" : "",
			    p1 ? p1 : addr->name, quote ? "\"" : "", addr->addr,
			    addr->next_addr ? "," : "");
		else
			sprintf(p2, "(%s) <%s>%s", p ? p : addr->comment, addr->addr,
			    addr->next_addr ? "," : "");

		len = strlen(p2);
		st1 += len;
		p2 += len;

		p = NULL;

		addr = addr->next_addr;
	}

	return putline(buf, file);
}

int smtp_header_field(head_field * fld, FILE * file)
{
	char buf[255];
	char *p, *p1, c;
	size_t nlen;

	snprintf(buf, sizeof(buf), "%s: ", fld->f_name);
	p = rfc1522_encode(fld->f_line, -1, -1);
	nlen = FLD_BREAK - (strlen(fld->f_name) + 2);

	while (strlen(p) > nlen) {
		c = p[nlen];
		p[nlen] = '\0';
		if ((p1 = strstr(p, "; ")) ||
		    (p1 = strstr(p, ", ")) || (p1 = strrchr(p, ' '))) {
			p[nlen] = c;
			if (*p1 != ' ')
				p1++;

			nlen = (p1 - p);
			if (nlen >= (sizeof(buf) - strlen(buf)))
				nlen = sizeof(buf) - strlen(buf) - 1;
			if (nlen <= 0)
				nlen = 1;
			if ((nlen < (FLD_BREAK / 8)) ||
			    ((strlen(p) - nlen) < (FLD_BREAK / 8))) {
				strncat(buf, p, nlen);
				p += nlen;
				nlen = FLD_BREAK;
				continue;
			}

			strncat(buf, p, nlen);
			if (putline(buf, file) == -1)
				return -1;

			strcpy(buf, " ");

			p1++;
			p = p1;
			nlen = FLD_BREAK - 1;
		} else {
			p[nlen] = c;
			strncat(buf, p, nlen);
			p += nlen;
			nlen = FLD_BREAK;
		}
	}

	nlen = sizeof(buf) - strlen(buf) - 1;
	if (nlen <= 0)
		return 0;

	if ((strlen(buf) + strlen(p)) >= sizeof(buf)) {
		strncat(buf, p, nlen);
		buf[sizeof(buf) - 1] = '\0';
	} else
		strcat(buf, p);

	return putline(buf, file);
}

int smtp_message(struct _mail_msg *msg, FILE * m_out)
{
	head_field *hf;
	struct _mime_msg *mime;
	char buf[512];
	FILE *mfd;
	int charset, i;

	if (!msg || !m_out)
		return -1;

	if (!Config.getInt("encheader", 1))
		charset = -2;
	else {
		charset = -1;
		if ((mime = get_text_part(msg)) != NULL) {
			i = 0;
			while (supp_charsets[i].charset_code != CHAR_UNKNOWN) {
				if (mime->charset->charset_code ==
				    supp_charsets[i].charset_code) {
					charset = i;
					break;
				}
				i++;
			}
		}
	}

	if (msg->header) {
		hf = msg->header->other_fields;
		while (hf) {
			if (!strip_when_send(hf))
				if (smtp_header_field(hf, m_out) == -1)
					return -1;
			hf = hf->next_head_field;
		}

		smtp_addr(msg->header->Sender, "Sender", m_out, charset);
		smtp_addr(msg->header->From, "From", m_out, charset);
		smtp_addr(msg->header->To, "To", m_out, charset);
		if (msg->header->News)
			smtp_news_addr(msg->header->News, "Newsgroups", m_out);

		if (msg->header->Subject) {
			snprintf(buf, sizeof(buf), "Subject: %s",
			    (charset >= -1) ? rfc1522_encode(msg->header->Subject,
				charset,
				-1) : msg->header->
			    Subject);
			if (putline(buf, m_out) == -1)
				return -1;
		}

		smtp_addr(msg->header->Cc, "Cc", m_out, charset);
		if (msg->header->Bcc) {
		  if (putline("Bcc:", m_out) == -1)
		    return -1;
		}
		  

	}

	if (putline("", m_out) == -1)
		return -1;

	if ((mfd = fopen(msg->get_file(msg), "r")) == NULL) {
		display_msg(MSG_WARN, "smtp", "Can not open %s",
		    msg->get_file(msg));
		return -1;
	}

	if (fseek(mfd, msg->header->header_len, SEEK_SET) == -1) {
		display_msg(MSG_WARN, "smtp", "Can not access message body");
		fclose(mfd);
		return -1;
	}

	*buf = '.';
	while (fgets(buf + 1, sizeof(buf) - 1, mfd)) {
		strip_newline(buf);
		if (*(buf + 1) == '.')
			putline(buf, m_out);
		else
			putline(buf + 1, m_out);
	}

	if (ferror(mfd) && !feof(mfd)) {
		display_msg(MSG_WARN, "smtp", "Error reading mesage body");
		fclose(mfd);
		return -1;
	}

	fclose(mfd);
	return 0;
}

int smtp_auth_dialog( char * client_to_server , char * * pointer_to_response )
{
	int  result ;
	char * pointer = response + 4;
	result = smtp_command("%s",client_to_server);
	*pointer_to_response = pointer;
	return result;
} 

void  get_smtp_username ( char * smtp_username , int maxlen )
{
	char *p;
	*smtp_username  = '\0';
	*(smtp_username + maxlen) = '\0';
	if ( smtp_account ) {
		p = smtp_account->username;
		strncpy(smtp_username, p, maxlen) ;
	}
	return;
}

void  get_smtp_password ( char * smtp_password , int maxlen )
{
	char *p;

	*smtp_password = '\0';
	*(smtp_password + maxlen ) = '\0';
	if ( smtp_account ) {
		p = smtp_account->password;
		if (!p)
			return;
		if(strlen(p) > maxlen)
			return;
		strncpy(smtp_password, p, maxlen);
	}
	return;
}

void  ask_smtp_password ( char * smtp_hostname, char * smtp_username,
			  char * smtp_password , int maxlen ) 
{
	char username[SMTP_MAX_USERNAME_LEN+1];
	char password[SMTP_MAX_PASSWD_LEN+1];
	char * hostname = true_host;

	strncpy(username,smtp_username,SMTP_MAX_USERNAME_LEN);
	*(username + SMTP_MAX_USERNAME_LEN) = '\0';
	strncpy(password,smtp_password,SMTP_MAX_PASSWD_LEN);
	*(password  + SMTP_MAX_PASSWD_LEN) = '\0';

	if ( !strlen(hostname) )
		hostname = smtp_hostname;

	auth_smtp_account(hostname, username, password );

	if ( ! strlen(smtp_username) ) {
		strncpy(smtp_username,username,maxlen);
		*(smtp_username + maxlen) = '\0';
	}

	strncpy(smtp_password,password,maxlen);
	*(smtp_password + maxlen) = '\0';

	return;
}

void get_smtp_host_info (char * smtp_host,
			 struct _smtp_account * * smtp_acct )
{
	int i, len;
	char * name;
	struct _smtp_account * smtp_account = NULL ;
  
	/* first attempt to match smtp_host  to the hostname of an account */
	for (i = 0; i < MAX_SMTP_ACCOUNTS && !smtp_account; i++) {
		if ( smtp_accounts[i].flags & SMTP_DISABLED )
			continue;
		name = smtp_accounts[i].hostname;
		len = strlen(name);
		if ( len && !strncmp(smtp_host,name,len)) 
			smtp_account = &smtp_accounts[i];
	}
	if (smtp_account) {
		*smtp_acct = smtp_account ;
		return;
	}

	/* now attempt to match smtp_host to the name of an account */
	for (i = 0; i < MAX_SMTP_ACCOUNTS && !smtp_account ; i++) {
		if ( smtp_accounts[i].flags & SMTP_DISABLED  )
			continue;
		name = smtp_accounts[i].name;
		len = strlen(name);
		if (len && !strncmp(smtp_host,name,len)) 
			smtp_account = &smtp_accounts[i];
	}  

	if (smtp_account) 
		*smtp_acct = smtp_account ;
  
	return;
}

int get_src_info( char * src_name, char *  username, 
		  char *  password) 
{
	/* get username and password from a source account */
	struct _retrieve_src * source = NULL;
	list<struct _retrieve_src>::iterator p;

	for (p = retrieve_srcs.begin(); p != retrieve_srcs.end(); p++)
		if (!strncmp(p->name, src_name, strlen(p->name))) {
			source = &(*p);
			break;
		}

	if (!source )
		return -1 ;

	if(source->type & RSRC_POP ) {
		struct _pop_src  * pop = (struct _pop_src *) source->spec;

		strncpy(username,pop->username,SMTP_MAX_USERNAME_LEN);
		*(username + SMTP_MAX_USERNAME_LEN ) = '\0';
		strncpy(password,pop->password,SMTP_MAX_PASSWD_LEN);
		*(password + SMTP_MAX_PASSWD_LEN ) = '\0';
		return 0;
	}
	if(source->type & RSRC_IMAP ) {
		struct _imap_src  * imap = (struct _imap_src *) source->spec;
		strncpy(username,imap->username,SMTP_MAX_USERNAME_LEN);
		*(username + SMTP_MAX_USERNAME_LEN ) = '\0';
		strncpy(password,imap->password,SMTP_MAX_PASSWD_LEN);
		*(password + SMTP_MAX_PASSWD_LEN ) = '\0';
		return 0;
	}

	return -1;
}

int load_smtp_acct(struct _smtp_account *smtp , FILE * fd)
{
	char buf[255], *p, *p1;
	char default_smtp_port[] = DEFAULT_SMTP_PORT;
	int len ;

	if(!fgets(buf, 255, fd))
		return -1;
	strip_newline(buf);

	if(sscanf(buf, "%d",&smtp->flags) != 1) 
		return -1;

	if(!fgets(buf, 255, fd))
		return -1;
	strip_newline(buf);

	p1 = buf;
	if((p = get_quoted_str(&p1)) == NULL)
		return -1;
	if(!strlen(p))
		return -1;

	strncpy(smtp->hostname, p,MAX_HOST-1);
	smtp->hostname[MAX_HOST-1] = '\0';
	p = get_quoted_str(&p1);
	len = 0;
	if (p != NULL)
		len = strlen(p);
	if(len >= 16)
		return -1;
	if (len )
		strncpy(smtp->service,p,16);
	else
		strncpy(smtp->service,default_smtp_port,16); 

	/* require that hostname and service  are not null */
	if (!(strlen(smtp->hostname) && strlen(smtp->service)))
		return -1;

	if(!(smtp->flags & SMTP_AUTH )) {
		*smtp->username = '\0';
		*smtp->password = '\0';
		*smtp->src_name = '\0';
		smtp->flags &= ~SMTP_AUTH_SRC;
		smtp->flags &= ~SMTP_STOREPWD;
		return 0;
	}


	if(!fgets(buf, 255, fd))
		return -1;
	strip_newline(buf);

	/* authentication provided by a  source account */

	if(smtp->flags & SMTP_AUTH_SRC) {
		*smtp->username = '\0';
		*smtp->password = '\0';
		smtp->flags &= ~SMTP_STOREPWD;


		p1 = buf;
		if((p = get_quoted_str(&p1)) == NULL)
			return -1;
		len = strlen(p);
	
		if (len && len < 32 )
			strncpy(smtp->src_name, p, 32);
		else
			*smtp->src_name = '\0';
	 
	 
		/* remove SMTP_AUTH_SRC flag if src_name is null */
		if( ! strlen(smtp->src_name) ) 
			smtp->flags  = smtp->flags & ~SMTP_AUTH_SRC ;

		return 0;
	} 

	 
	/* authentication  with supplied username ( + password ) */
   
	*smtp->src_name = '\0';
	p1 = buf;
	if((p = get_quoted_str(&p1)) == NULL)
		return -1;
	strncpy(smtp->username, p, SMTP_MAX_USERNAME_LEN);
	smtp->username[SMTP_MAX_USERNAME_LEN] = '\0';
	*smtp->password = '\0';
   
	len = 0;
	p = get_quoted_str(&p1);
	if (p != NULL)
		len  = strlen(p);
	if(len) {
#ifdef USE_GPASSWD
		if(Config.getInt("use_gpasswd", 0) != 0) {
			int ecode = CE_BASE64;
			char *passwd = NULL;
			/* now encrypted passwords are also base_64 encoded so they are
			   text strings */
			base64_decode(NULL, &ecode);   /* initialize decoder */
			passwd  = base64_decode(p,&ecode);
			if (passwd) {
				//cerr << "Decrypting Pass: " << p << endl;
				p = passwd;
				strncpy(smtp->password, Passwd.decrypt(p).c_str(), SMTP_MAX_PASSWD_LEN);
				//cerr << "Decrypted Pass: " << smtp->password << endl;
			} else 
				*smtp->password = '\0';
		} else {
#endif
			strncpy(smtp->password, p, SMTP_MAX_PASSWD_LEN);
			smtp->password[SMTP_MAX_PASSWD_LEN] = '\0';
	   
#ifdef USE_GPASSWD
		}
#endif
	 
	}
   
	/* remove SMTP_STOREPWD flag if password is null */
	if( ! strlen(smtp->password) ) 
		smtp->flags = smtp->flags & ~SMTP_STOREPWD ;

	return  0;
}

int save_smtp_acct(struct _smtp_account *smtp, FILE * fd)
{
	//  printf(" saving smtp account ");

#ifdef USE_GPASSWD
	char passwd[4 * ((SMTP_MAX_PASSWD_LEN + 2) / 3) + 1];
	int len, len64 ,len1 = 0, len2 = 0 ;
	char *init = NULL, *body = NULL, *end = NULL;
#else
	char passwd[SMTP_MAX_PASSWD_LEN + 1];
#endif

	if(smtp->flags & SMTP_AUTH_SRC ) {
		if(!strlen(smtp->src_name)) 
			smtp->flags &= ~SMTP_AUTH_SRC ;
	}
	
	if(smtp->flags & SMTP_STOREPWD) {
		if(!strlen(smtp->password)) 
			smtp->flags &= ~SMTP_STOREPWD ;
		else {
	
#ifdef USE_GPASSWD
			if(Config.getInt("use_gpasswd", 0) != 0) {
				// cerr << "Encrypting Pass: " << smtp->password << endl;
				strncpy(passwd, Passwd.encrypt(smtp->password).c_str(), SMTP_MAX_PASSWD_LEN);
				/* md5 encryption to a text string */
				len = strlen(passwd);
				len64 = 4 * ((len + 2) / 3) ;
				init = base64_encode(NULL, len64 + 12);
				if (init) 
					body = base64_encode(passwd, len);
				*passwd = '\0';
				if(body) {
					len1 = strlen(body);
					end = base64_encode(NULL, len);	/* terminate encoding */
				}
				if(end) {
					len2 = strlen(end);
					if(len1 + len2 < sizeof(passwd)) {
						strncpy(passwd, body, len1);
						strncpy(passwd + len1, end, len2);
						*(passwd + len1 + len2) = '\0';
					} 
				} 
				// cerr << "Encrypted Pass: " << passwd << endl;
			} else {
#endif	 
				strncpy(passwd, smtp->password, SMTP_MAX_PASSWD_LEN);
	  
#ifdef USE_GPASSWD
			}
#endif
	
			if(!strlen(passwd)) 
				smtp->flags &= ~SMTP_STOREPWD ;
	
		}
	}

	fprintf(fd,"%d\n",smtp->flags);
	fprintf(fd, "%s %s\n", smtp->hostname, smtp->service);
	if(!(smtp->flags & SMTP_AUTH)) 
		return 0;

	if(smtp->flags & SMTP_AUTH_SRC ) {
		if(strchr(smtp->src_name, ' '))
			fprintf(fd, "\"%s\"\n", smtp->src_name);
		else
			fprintf(fd, "%s\n", smtp->src_name);
		return 0;
	}
	
	if(strlen(smtp->username)) {
		if(strchr(smtp->username, ' '))
			fprintf(fd, "\"%s\"", smtp->username);
		else
			fprintf(fd, "%s", smtp->username);
	}
	else
		fprintf(fd,"\"\"");

	if(  smtp->flags & SMTP_STOREPWD) 
		fprintf(fd, " %s\n", passwd);
	else 
		fprintf(fd, " \n");

	return 0;
}

void init_smtp_acct(struct _smtp_account *smtp)
{

	strcpy(smtp->hostname, "127.0.0.1");
	strcpy(smtp->service, DEFAULT_SMTP_PORT);
	strcpy(smtp->username, user_n);
	*smtp->password = '\0';
	*smtp->src_name = '\0';
	smtp->flags = SMTP_DISABLED;

	return;
}
