/***************************************************************************

  libsmtp_comm.c

  (c) 2000-2012 Benoît Minisini <gambas@users.sourceforge.net>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2, 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 General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  MA 02110-1301, USA.

***************************************************************************/

/*
	libsmtp is a library to send mail via SMTP
		This is the communication part

Copyright  2001 Kevin Read <obsidian@berlios.de>

This software is available under the GNU Lesser Public License as described
in the COPYING file.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or any later version.

This library 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
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
	MA 02110-1301, USA

Kevin Read <obsidian@berlios.de>
Thu Aug 16 2001 */

/* #ifndef __G_LIB_H__ */
	#include <glib.h>
/* #endif */

//#include "../config.h"

#include "gb_common.h"

#include <errno.h>
#include <sys/socket.h>
#include <time.h>
#include <locale.h>

#include "libsmtp.h"
#include "libsmtp_mime.h"
#include "main.h"

//#define LIBSMTP_DEBUG

/* Check if a string has only ASCII characters */

static bool is_ascii_string(char *str)
{
	unsigned char c;
	
	while ((c = *str++))
	{
		if (c & 0x80)
			return FALSE;
	}
	
	return TRUE;
}

/* internal communication functions */

/* Type is one of:
	0 normal body mesg
	1 normal header mesg
	2 normal dialogue mesg

	This function won't return correct libsmtp_gstring_read for dialogue mesgs */

int libsmtp_int_read (GString *libsmtp_gstring_read, struct libsmtp_session_struct *libsmtp_session, int type)
{
	int libsmtp_int_bytes;
	char *libsmtp_int_temp_buffer;
	char libsmtp_int_rec_buffer[4096];

	bzero (libsmtp_int_rec_buffer, sizeof(libsmtp_int_rec_buffer));

	if (libsmtp_session->stream)
	{
		//int block = GB.Stream.Block(libsmtp_session->stream, TRUE);
		//libsmtp_int_bytes = GB.Stream.Read(libsmtp_session->stream, libsmtp_int_rec_buffer, 1);
		//fprintf(stderr, "GB.Stream.Read: %d\n", libsmtp_int_bytes);
		//GB.Stream.Block(libsmtp_session->stream, block);
		libsmtp_int_bytes = GB.Stream.Read(libsmtp_session->stream, libsmtp_int_rec_buffer, (int)(- sizeof(libsmtp_int_rec_buffer)));
		//fprintf(stderr, "GB.Stream.Read: %d\n", libsmtp_int_bytes);
	}
	else
		libsmtp_int_bytes = read(libsmtp_session->socket, libsmtp_int_rec_buffer, sizeof(libsmtp_int_rec_buffer));
	
	if (libsmtp_int_bytes<=0)
	{
		libsmtp_close(libsmtp_session);
		libsmtp_session->ErrorCode=LIBSMTP_ERRORREADFATAL;
		libsmtp_session->Stage=type;
		return LIBSMTP_ERRORREAD;
	}

	#ifdef LIBSMTP_DEBUG
		printf("DEBUG in read: %.*s\n", libsmtp_int_bytes, libsmtp_int_rec_buffer);
	#endif
	
	if (libsmtp_session->debug && type > 0)
		fprintf(stderr, "<- %.*s\n", libsmtp_int_bytes, libsmtp_int_rec_buffer);

	/* Update statistics */
	switch (type)
	{
		case (0):
			libsmtp_session->BodyBytes+=libsmtp_int_bytes;
			break;

		case (1):
			libsmtp_session->HeaderBytes+=libsmtp_int_bytes;
			libsmtp_session->HeadersSent++;
			break;

		case (2):
			libsmtp_session->DialogueBytes+=libsmtp_int_bytes;
			libsmtp_session->DialogueSent++;

			g_string_assign (libsmtp_gstring_read, libsmtp_int_rec_buffer);

			/* Ok, take the first part of the response ... */
			libsmtp_int_temp_buffer = strtok ((char *)libsmtp_int_rec_buffer, " ");

			/* and extract the response code */
			libsmtp_session->LastResponseCode = atoi(libsmtp_int_temp_buffer);

			/* Then fetch the rest of the string and save it */
			libsmtp_int_temp_buffer = strtok (NULL, "\0");
			g_string_assign(libsmtp_session->LastResponse, libsmtp_int_temp_buffer);
			break;
	}
	return LIBSMTP_NOERR;
}

/* Type is one of:
	0 normal body mesg
	1 normal header mesg
	2 normal dialogue mesg */

int libsmtp_int_send (GString *libsmtp_send_gstring, struct libsmtp_session_struct *libsmtp_session, int type)
{
	int libsmtp_int_bytes;

	#ifdef LIBSMTP_DEBUG
		printf ("DEBUG in send: %s", libsmtp_send_gstring->str);
	#endif

	if (libsmtp_session->debug && type > 0)
		fprintf(stderr, "-> %.*s\n", (int)libsmtp_send_gstring->len, libsmtp_send_gstring->str);

	if (libsmtp_session->stream)
	{
		libsmtp_int_bytes = GB.Stream.Write(libsmtp_session->stream, libsmtp_send_gstring->str, libsmtp_send_gstring->len);
		//fprintf(stderr, "GB.Stream.Write: %d\n", libsmtp_int_bytes);
	}
	else
		libsmtp_int_bytes = write(libsmtp_session->socket, libsmtp_send_gstring->str, libsmtp_send_gstring->len);
	
	if (libsmtp_int_bytes != libsmtp_send_gstring->len)
	{
		libsmtp_close(libsmtp_session);
		libsmtp_session->ErrorCode=LIBSMTP_ERRORSENDFATAL;
		libsmtp_session->Stage=type;
		return LIBSMTP_ERRORSEND;
	}
	/* Update statistics */
	switch (type)
	{
		case (0):
			libsmtp_session->BodyBytes+=libsmtp_int_bytes;
			break;
		case (1):
			libsmtp_session->HeaderBytes+=libsmtp_int_bytes;
			libsmtp_session->HeadersSent++;
			break;
		case (2):
			libsmtp_session->DialogueBytes+=libsmtp_int_bytes;
			libsmtp_session->DialogueSent++;
			break;
	}

	return LIBSMTP_NOERR;
}

int libsmtp_int_send_body(char *libsmtp_send_string, unsigned int libsmtp_int_length, struct libsmtp_session_struct *libsmtp_session)
{
	int libsmtp_int_bytes;

	#ifdef LIBSMTP_DEBUG
		printf ("DEBUG in body send : %s\n", libsmtp_send_string);
	#endif

	if (libsmtp_session->debug && libsmtp_session->Stage < LIBSMTP_DATA_STAGE)
		fprintf(stderr, "-> %.*s\n", libsmtp_int_length, libsmtp_send_string);

	if (libsmtp_session->stream)
	{
		libsmtp_int_bytes = GB.Stream.Write(libsmtp_session->stream, libsmtp_send_string, libsmtp_int_length);
		//fprintf(stderr, "GB.Stream.Write: %d\n", libsmtp_int_bytes);
	}
	else
		libsmtp_int_bytes = write(libsmtp_session->socket, libsmtp_send_string, libsmtp_int_length);

	if (libsmtp_int_bytes<0)
	{
		libsmtp_close(libsmtp_session);
		libsmtp_session->ErrorCode=LIBSMTP_ERRORSENDFATAL;
		return LIBSMTP_ERRORSEND;
	}
	/* Update statistics */
	libsmtp_session->BodyBytes+=libsmtp_int_bytes;

	return LIBSMTP_NOERR;
}

/* Use this function to make libsmtp run the SMTP dialogue */

int libsmtp_dialogue (struct libsmtp_session_struct *libsmtp_session)
{
	int libsmtp_temp;
	GString *libsmtp_temp_gstring;
	GList *libsmtp_temp_glist;

	libsmtp_temp_gstring = g_string_new(NULL);

	/* This can only be used if the hello stage is finished, but we haven't
		entered data stage yet */
	if ((libsmtp_session->Stage < LIBSMTP_HELLO_STAGE) ||
			(libsmtp_session->Stage >= LIBSMTP_DATA_STAGE))
	{
		libsmtp_session->ErrorCode = LIBSMTP_BADSTAGE;
		return LIBSMTP_BADSTAGE;
	}

	/* First we check if sender, subject and at least one recipient has
		been set */

	#ifdef LIBSMTP_DEBUG
		printf ("DEBUG:List length: %d!\n", g_list_length (libsmtp_session->To));
	#endif

	if (libsmtp_session->From->len < 1 || g_list_length(libsmtp_session->To) < 1)
	{
		libsmtp_session->ErrorCode = LIBSMTP_BADARGS;
		return LIBSMTP_BADARGS;
	}

	/* We enter the sender stage now */
	libsmtp_session->Stage = LIBSMTP_SENDER_STAGE;

	/* Ok, now lets give him the sender address */

	g_string_sprintf (libsmtp_temp_gstring, "mail from: %s\r\n", \
											libsmtp_session->From->str);

	if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 2))
	{
		libsmtp_session->ErrorCode = LIBSMTP_ERRORSENDFATAL;
		return LIBSMTP_ERRORSENDFATAL;
	}

	/* Now we have to see if he likes it */

	if (libsmtp_int_read (libsmtp_temp_gstring, libsmtp_session, 2))
	{
		libsmtp_session->ErrorCode = LIBSMTP_ERRORREADFATAL;
		return LIBSMTP_ERRORREADFATAL;
	}

	if (libsmtp_session->LastResponseCode > 299)
	{
		libsmtp_close(libsmtp_session);
		libsmtp_session->ErrorCode = LIBSMTP_WONTACCEPTSENDER;
		return LIBSMTP_WONTACCEPTSENDER;
	}

	/* We enter the recipient stage now */
	libsmtp_session->Stage = LIBSMTP_RECIPIENT_STAGE;

	/* Now we go through all recipients, To: first */

	for (libsmtp_temp=0; libsmtp_temp < g_list_length(libsmtp_session->To);\
				libsmtp_temp++)
	{
		libsmtp_temp_glist=g_list_nth (libsmtp_session->To, libsmtp_temp);
		#ifdef LIBSMTP_DEBUG
			printf ("To: %s\n", (char *)libsmtp_temp_glist->data);
		#endif
		g_string_sprintf (libsmtp_temp_gstring, "rcpt to: %s\r\n", \
				(char *)libsmtp_temp_glist->data);


		/* Every recipient gets sent to the server */

		if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 2))
		{
			libsmtp_session->ErrorCode = LIBSMTP_ERRORSENDFATAL;
			return LIBSMTP_ERRORSENDFATAL;
		}

		/* We have to read the servers response of course */
		if (libsmtp_int_read (libsmtp_temp_gstring, libsmtp_session, 2))
		{
			libsmtp_session->ErrorCode = LIBSMTP_ERRORREADFATAL;
			return LIBSMTP_ERRORREADFATAL;
		}

		/* We write the response code into the response linked
			list so that denial reasons can be seen later */

		libsmtp_session->ToResponse = g_list_append (libsmtp_session->ToResponse,\
			(char *)strdup (libsmtp_temp_gstring->str));

		/* Did he like this one? */
		if (libsmtp_session->LastResponseCode > 299)
		{
			libsmtp_session->ErrorCode = LIBSMTP_WONTACCEPTREC;

			/* No, he didn't. */

			libsmtp_session->NumFailedTo++;
		}
	}

	/* Now we go through all CC recipients */

	for (libsmtp_temp=0; libsmtp_temp < g_list_length(libsmtp_session->CC);\
				libsmtp_temp++)
	{
		libsmtp_temp_glist=g_list_nth (libsmtp_session->CC, libsmtp_temp);
		g_string_sprintf (libsmtp_temp_gstring, "rcpt to: %s\r\n", \
				(char *)libsmtp_temp_glist->data);


		/* Every recipient gets sent to the server */

		if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 2))
		{
			libsmtp_session->ErrorCode = LIBSMTP_ERRORSENDFATAL;
			return LIBSMTP_ERRORSENDFATAL;
		}

		/* We have to read the servers response of course */
		if (libsmtp_int_read (libsmtp_temp_gstring, libsmtp_session, 2))
		{
			libsmtp_session->ErrorCode = LIBSMTP_ERRORREADFATAL;
			return LIBSMTP_ERRORREADFATAL;
		}

		/* We write the response code into the response linked */

		libsmtp_session->CCResponse = g_list_append (libsmtp_session->CCResponse,\
			(char *)strdup (libsmtp_temp_gstring->str));

		/* Did he like this one? */
		if (libsmtp_session->LastResponseCode > 299)
		{
			libsmtp_session->ErrorCode = LIBSMTP_WONTACCEPTREC;

			/* No, he didn't. Increase the counter. */

			libsmtp_session->NumFailedCC++;
		}
	}

	/* Now we go through all BCC recipients */

	for (libsmtp_temp=0; libsmtp_temp < g_list_length(libsmtp_session->BCC);\
				libsmtp_temp++)
	{
		libsmtp_temp_glist=g_list_nth (libsmtp_session->BCC, libsmtp_temp);
		g_string_sprintf (libsmtp_temp_gstring, "rcpt to: %s\r\n", \
				(char *)libsmtp_temp_glist->data);


		/* Every recipient gets sent to the server */

		if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 2))
		{
			libsmtp_session->ErrorCode = LIBSMTP_ERRORSENDFATAL;
			return LIBSMTP_ERRORSENDFATAL;
		}

		/* We have to read the servers response of course */
		if (libsmtp_int_read (libsmtp_temp_gstring, libsmtp_session, 2))
		{
			libsmtp_session->ErrorCode = LIBSMTP_ERRORREADFATAL;
			return LIBSMTP_ERRORREADFATAL;
		}

		/* No, he didn't. We write the response code into the response linked
				list */

			libsmtp_session->BCCResponse = g_list_append (libsmtp_session->BCCResponse,\
				(char *)strdup (libsmtp_temp_gstring->str));

		/* Did he like this one? */
		if (libsmtp_session->LastResponseCode > 299)
		{
			libsmtp_session->ErrorCode = LIBSMTP_WONTACCEPTREC;

			libsmtp_session->NumFailedBCC++;
		}
	}
	
	#if 0
	g_string_sprintf (libsmtp_temp_gstring, "rcpt to:\r\n");

	if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 2))
	{
		libsmtp_session->ErrorCode = LIBSMTP_ERRORSENDFATAL;
		return LIBSMTP_ERRORSENDFATAL;
	}

	/* We have to read the servers response of course */
	if (libsmtp_int_read (libsmtp_temp_gstring, libsmtp_session, 2))
	{
		libsmtp_session->ErrorCode = LIBSMTP_ERRORREADFATAL;
		return LIBSMTP_ERRORREADFATAL;
	}
	#endif
	
	return LIBSMTP_NOERR;
}

/* With this function you can send SMTP dialogue strings yourself */

int libsmtp_dialogue_send (char *libsmtp_dialogue_string, \
				struct libsmtp_session_struct *libsmtp_session)
{
	GString *libsmtp_temp_gstring;

	libsmtp_temp_gstring = g_string_new(libsmtp_dialogue_string);

	/* This can only be used if the hello stage is finished, but we haven't
		entered data stage yet */
	if ((libsmtp_session->Stage < LIBSMTP_HELLO_STAGE) ||
			(libsmtp_session->Stage >= LIBSMTP_DATA_STAGE))
	{
		libsmtp_session->ErrorCode = LIBSMTP_BADSTAGE;
		return LIBSMTP_BADSTAGE;
	}

	if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 2))
	{
		libsmtp_session->ErrorCode = LIBSMTP_ERRORSENDFATAL;
		return LIBSMTP_ERRORSENDFATAL;
	}

	/* We have to read the servers response of course */
	if (libsmtp_int_read (libsmtp_temp_gstring, libsmtp_session, 2))
	{
		libsmtp_session->ErrorCode = LIBSMTP_ERRORREADFATAL;
		return LIBSMTP_ERRORREADFATAL;
	}

	/* We don't look at the response code here - the app will have to do that */

	return LIBSMTP_NOERR;
}


static const char *get_current_time()
{
	static char date[32];
	time_t now;
	struct tm *tm;

	if (time(&now) == ((time_t)-1))
		return NULL;
	
	tm = localtime(&now);
	if (!tm)
		return NULL;
	
	setlocale (LC_TIME, "C");
	strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z" , tm);
	setlocale (LC_TIME, "");
	
	return date;
}

/* This function starts the DATA part. No more dialogue stuff can be sent
	from this time on. */

int libsmtp_headers (struct libsmtp_session_struct *libsmtp_session)
{
	const char *date;
	int libsmtp_temp;
	GString *libsmtp_temp_gstring = NULL;
	GList *libsmtp_temp_glist;

	/* Are we at the end of the dialogue stage, but haven't sent the
		body yet? */
	if ((libsmtp_session->Stage < LIBSMTP_RECIPIENT_STAGE) || \
			(libsmtp_session->Stage > LIBSMTP_DATA_STAGE))
	{
		libsmtp_session->ErrorCode = LIBSMTP_BADSTAGE;
		return LIBSMTP_BADSTAGE;
	}

	/* Maybe we are already in DATA mode so... */
	if (libsmtp_session->Stage < LIBSMTP_DATA_STAGE)
	{
		/* Great finality. After this no more dialogue can go on */
		libsmtp_temp_gstring = g_string_new ("datA\r\n");

		if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 2))
			return LIBSMTP_ERRORSENDFATAL;

		/* What has he say to a little bit of DATA? */

		if (libsmtp_int_read (libsmtp_temp_gstring, libsmtp_session, 2))
		{
			libsmtp_session->ErrorCode = LIBSMTP_ERRORREADFATAL;
			return LIBSMTP_ERRORREADFATAL;
		}

		if (libsmtp_session->LastResponseCode != 354)
		{
			libsmtp_close(libsmtp_session);
			libsmtp_session->ErrorCode = LIBSMTP_WONTACCEPTDATA;
			return LIBSMTP_WONTACCEPTDATA;
		}

		/* We enter the data stage now */
		libsmtp_session->Stage = LIBSMTP_HEADERS_STAGE;
	}

	/* Now we send through all the headers. No more responses will come from
		the mailserver until we end the DATA part. */

	// BM: Put the Date field
	// For example: Date: Sat, 18 Jul 2009 12:47:43 +0100
	
	date = get_current_time();
	if (date)
	{
		g_string_sprintf (libsmtp_temp_gstring, "Date: %s\r\n", date);

		if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 1))
			return LIBSMTP_ERRORSENDFATAL;
	}

	/* First the From: header */

	g_string_sprintf (libsmtp_temp_gstring, "From: %s\r\n", \
											libsmtp_session->From->str);

	if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 1))
		return LIBSMTP_ERRORSENDFATAL;

	/* Then the Subject: header */

	// BM: if the subject is not ASCII, then it is UTF-8

	if (is_ascii_string(libsmtp_session->Subject->str))
	{
		g_string_sprintf (libsmtp_temp_gstring, "Subject: %s\r\n", \
												libsmtp_session->Subject->str);
	
		if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 1))
			return LIBSMTP_ERRORSENDFATAL;
	}
	else
	{
		/*g_string_assign(libsmtp_temp_gstring, "Subject: =?utf-8?q?");
		if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 1))
			return LIBSMTP_ERRORSENDFATAL;*/
		
		if (libsmtp_int_send_quoted_header("Subject:", libsmtp_session->Subject->str, libsmtp_session->Subject->len, libsmtp_session))
			return LIBSMTP_ERRORSENDFATAL;
	
		//g_string_assign(libsmtp_temp_gstring, "?=\r\n");
		//if (libsmtp_int_send(libsmtp_temp_gstring, libsmtp_session, 1))
		//	return LIBSMTP_ERRORSENDFATAL;
	}

	/* Then we send all the To: addresses */

	g_string_assign (libsmtp_temp_gstring, "To: ");

	for (libsmtp_temp=0; libsmtp_temp < g_list_length(libsmtp_session->To);\
			libsmtp_temp++)
	{
		/* Select the respective node of the linked list */
		libsmtp_temp_glist=g_list_nth (libsmtp_session->To, libsmtp_temp);

		/* If this is the last entry of the list, don't append a comma */
		if (libsmtp_temp==(g_list_length (libsmtp_session->To)-1))
		{
			g_string_append (libsmtp_temp_gstring, libsmtp_temp_glist->data);
			g_string_append (libsmtp_temp_gstring, "\r\n");
		}
		else
		{
			g_string_append (libsmtp_temp_gstring, libsmtp_temp_glist->data);
			g_string_append (libsmtp_temp_gstring, ", ");
		}
	}
	/* Send the line to the server */

	if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 1))
		return LIBSMTP_ERRORSENDFATAL;

	/* Then we iterate through all CC recipients */

	if (g_list_length (libsmtp_session->CC))
	{
		g_string_assign (libsmtp_temp_gstring, "CC: ");

		for (libsmtp_temp=0; libsmtp_temp < g_list_length(libsmtp_session->CC);\
				libsmtp_temp++)
		{
			/* Select the respective node of the linked list */
			libsmtp_temp_glist=g_list_nth (libsmtp_session->CC, libsmtp_temp);

			/* If this is the last entry of the list, don't append a comma */
			if (libsmtp_temp==(g_list_length (libsmtp_session->CC)-1))
			{
				g_string_append (libsmtp_temp_gstring, libsmtp_temp_glist->data);
				g_string_append (libsmtp_temp_gstring, "\r\n");
			}
			else
			{
				g_string_append (libsmtp_temp_gstring, libsmtp_temp_glist->data);
				g_string_append (libsmtp_temp_gstring, ", ");
			}
		}
		/* Send the line to the server */

		if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 1))
			return LIBSMTP_ERRORSENDFATAL;
	}

	return LIBSMTP_NOERR;
}


/* With this function you can send custom headers. */

int libsmtp_header_send (char *libsmtp_header_string, \
			struct libsmtp_session_struct *libsmtp_session)
{
	GString *libsmtp_temp_gstring;

	/* Are we at the end of the dialogue stage, but haven't sent the
		DATA yet? */
	if ((libsmtp_session->Stage < LIBSMTP_RECIPIENT_STAGE) || \
			(libsmtp_session->Stage > LIBSMTP_HEADERS_STAGE))
	{
		libsmtp_session->ErrorCode = LIBSMTP_BADSTAGE;
		return LIBSMTP_BADSTAGE;
	}

	/* Maybe we are already in DATA mode so... */
	if (libsmtp_session->Stage < LIBSMTP_DATA_STAGE)
	{
		/* Great finality. After this no more dialogue can go on */
		libsmtp_temp_gstring = g_string_new ("daTa\r\n");

		if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 2))
			return LIBSMTP_ERRORSENDFATAL;

		/* What has he to say to a little bit of DATA? */

		if (libsmtp_int_read (libsmtp_temp_gstring, libsmtp_session, 2))
		{
			libsmtp_session->ErrorCode = LIBSMTP_ERRORREADFATAL;
			return LIBSMTP_ERRORREADFATAL;
		}

		if (libsmtp_session->LastResponseCode != 354)
		{
			libsmtp_close(libsmtp_session);
			libsmtp_session->ErrorCode = LIBSMTP_WONTACCEPTDATA;
			return LIBSMTP_WONTACCEPTDATA;
		}

		/* We enter the data stage now */
		libsmtp_session->Stage = LIBSMTP_DATA_STAGE;
	}

	/* Ok. Lets send these custom headers. */
	libsmtp_temp_gstring = g_string_new (libsmtp_header_string);

	if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 1))
		return LIBSMTP_ERRORSENDFATAL;

	return LIBSMTP_NOERR;
}



/* This function sends raw body data. It can only be used in the appropriate
	stage. The data to be sent has to be formatted according to RFC822 and
	the MIME standards. */

int libsmtp_body_send_raw (char *libsmtp_body_data, unsigned int libsmtp_int_length, \
						struct libsmtp_session_struct *libsmtp_session)
{

	/* Headers should have been sent before body data goes out, but we
		must still be in the body stage at most */
	if ((libsmtp_session->Stage < LIBSMTP_HEADERS_STAGE) ||
			(libsmtp_session->Stage > LIBSMTP_BODY_STAGE))
	{
		libsmtp_session->ErrorCode = LIBSMTP_BADSTAGE;
		return LIBSMTP_BADSTAGE;
	}

	/* If we just came from the headers stage, we have to send a blank line
		first */

	/* Headers should have been sent before body data goes out */
	if (libsmtp_session->Stage == LIBSMTP_HEADERS_STAGE)
	{
		/* Now let there be a blank line */
		GString *libsmtp_temp_gstring = g_string_new ("\r\n");

		if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 1))
			return LIBSMTP_ERRORSENDFATAL;
			
		g_string_free(libsmtp_temp_gstring, TRUE);
	}

	/* We now enter the body stage */
	libsmtp_session->Stage = LIBSMTP_BODY_STAGE;

	if (libsmtp_int_send_body (libsmtp_body_data, libsmtp_int_length, libsmtp_session))
		return LIBSMTP_ERRORSENDFATAL;

	return LIBSMTP_NOERR;
}



/* This function ends the body part. It can only be used in certain stages */

int libsmtp_body_end (struct libsmtp_session_struct *libsmtp_session)
{
	GString *libsmtp_temp_gstring;

	libsmtp_temp_gstring = g_string_new (NULL);

	/* We need to be in body stage to leave it :) */
	if (libsmtp_session->Stage < LIBSMTP_BODY_STAGE)
	{
		libsmtp_session->ErrorCode = LIBSMTP_BADSTAGE;
		return LIBSMTP_BADSTAGE;
	}

	/* We now enter the finished stage */
	libsmtp_session->Stage = LIBSMTP_FINISHED_STAGE;

	/* Now let there be a line with only a dot on it */

	if (libsmtp_int_send_body ("\r\n", 2, libsmtp_session))
		return LIBSMTP_ERRORSENDFATAL;

	if (libsmtp_int_send_body (".\r\n", 3, libsmtp_session))
		return LIBSMTP_ERRORSENDFATAL;

	/* Did you like that body, connisseur? */

	sleep (2);
	if (libsmtp_int_read (libsmtp_temp_gstring, libsmtp_session, 2))
		return LIBSMTP_ERRORREADFATAL;

	#ifdef LIBSMTP_DEBUG
		printf ("DEBUG: %s\n", libsmtp_session->LastResponse->str);
	#endif

	if (libsmtp_session->LastResponseCode > 299)
	{
		/* Aaaw no, he didn't. Don't ask me how that can happen... */
		libsmtp_close(libsmtp_session);
		libsmtp_session->ErrorCode = LIBSMTP_REJECTBODY;
		return LIBSMTP_REJECTBODY;
	}

	return LIBSMTP_NOERR;
}


/* This function ends the SMTP session. It can only be used in certain stages,
	notably in all dialogue modes. */

int libsmtp_quit (struct libsmtp_session_struct *libsmtp_session)
{
	GString *libsmtp_temp_gstring;

	/* We need to be in body stage to leave it :) */
	if ((libsmtp_session->Stage == LIBSMTP_FINISHED_STAGE) || \
			(libsmtp_session->Stage < LIBSMTP_DATA_STAGE))
	{

		/* We now enter the quit stage */
		libsmtp_session->Stage = LIBSMTP_QUIT_STAGE;

		/* Lets tell him we are quitting. */
		libsmtp_temp_gstring = g_string_new ("quit\r\n");

		if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 1))
			return LIBSMTP_ERRORSENDFATAL;

		/* I hope thats okay with him :) */

		if (libsmtp_int_read (libsmtp_temp_gstring, libsmtp_session, 2))
			return LIBSMTP_ERRORREADFATAL;

		if (libsmtp_session->LastResponseCode > 299)
		{
			/* He says it isn't, but who cares... */

			libsmtp_close(libsmtp_session);
			libsmtp_session->ErrorCode = LIBSMTP_REJECTQUIT;
			libsmtp_session->Stage=LIBSMTP_NOCONNECT_STAGE;
			return LIBSMTP_REJECTQUIT;
		}
		else
		{
			/* Babe, I'm gonne leave you... */

			libsmtp_close(libsmtp_session);
			libsmtp_session->ErrorCode = LIBSMTP_NOERR;
			libsmtp_session->Stage=LIBSMTP_NOCONNECT_STAGE;
			return LIBSMTP_NOERR;
		}
	}

	/* Wrong stage, dude ! */
	libsmtp_session->ErrorCode = LIBSMTP_BADSTAGE;
	return LIBSMTP_BADSTAGE;
}

