[En-Nut-Discussion] Re: smtp over ethernut

Mikael Adolfsson ma at stendahls.net
Fri Sep 12 21:20:06 CEST 2003


On Fri, 12 Sep 2003, Brett Abbott wrote:
> Mikael
> 
> Im very much interested in your prototype smtp code.  I was about to 
> launch into writing a similar module.  If you have a chance, I'd love a 
> copy of the source as it is to date.
> Are you expecting to publish it to nut/os?

Hi,

here is a working prototype. It's quite uggly written, but it fulfills my 
current needs. I'll probably rewrite it completely in a later date. 
Currently the whole message body needs to be in ram. I'd rather like it 
being a stream.

/ Mikael
-------------- next part --------------
/* SMTP module for ECBlite, based on Nut/OS */

#include <stdio.h>
#include <string.h>
#include <ctype.h>

#include <arpa/inet.h>
#include <sys/heap.h>
#include <sys/socket.h>
#include <sys/confnet.h>
#include <sys/version.h>

#include <pro/smtp.h>

static FILE *debugStream;
static u_char debugEnabled = 0;
/*
 * Waits for a message, and stores it into buff (mostly to save RAM)
 */
static int SMTPWaitMessage (FILE *stream, char *buff, int size) {
  int n;

  fgets (buff, size, stream);
  if (debugEnabled)
    fprintf_P (debugStream, PSTR("SMTP: %s"), buff);

  /* SMTP messages are allways 3 digits */
  if (strlen(buff) < 4 || !isdigit(buff[0]) || !isdigit(buff[1]) || 
      !isdigit(buff[2]) || buff[3] != ' ') {
    if (debugEnabled) {
      buff[4] = 0;
      fprintf_P(debugStream, PSTR("Illegal return code: '%s'\r\n"), 
		strlen(buff));
    }	
    return -1;
  }
  n = (buff[0]-'0')*100 + (buff[1]-'0')*10 + (buff[2]-'0');
  return n;
}

/*
 * \todo 
 * Make it possible to write email addresses in the format
 * 'name <address>'. 
 * Encode message body - hande specail case with sing dots.
 * React on 8-bit subjects.
 * Maybe add support for 7-bit mails with mime-encoding
 */

static int SMTPTransport (FILE *stream, char *buf,
			  int size, const char *from,
			  const char *to, const char *subject, 
			  const char *msg) {

  /* Wait for '220 servername ESMTP */
  if ( SMTPWaitMessage (stream, buf, size) != 220 )
    return SMTP_ERR_GREETING;

  /* Send greeting 'HELO [ip.addr.]' */
  fprintf_P (stream, PSTR("HELO [%s]\r\n"), inet_ntoa(confnet.cdn_ip_addr));
  fflush (stream);
  
  /* Wait for '250 servername' */
  if ( SMTPWaitMessage (stream, buf, size) != 250 )
    return SMTP_ERR_HELO;

  /* Send mail request: 'MAIL FROM:<from at email.addr>' */
  fprintf_P (stream, PSTR("MAIL FROM:<%s>\r\n"), from);
  fflush (stream);
  
  /* Wait for '250 ok' */
  if ( SMTPWaitMessage (stream, buf, size) != 250 )
    return SMTP_ERR_MAILFROM;

  /* Specify recipients: 'RCPT TO:<to at mail.addr>' */
  fprintf_P(stream, PSTR("RCPT TO:<%s>\r\n"), to);
  fflush (stream);

  /* Wait for '250 ok' */
  if ( SMTPWaitMessage (stream, buf, size) != 250 )
    return SMTP_ERR_RCPTTO;

  /* Send data request: 'DATA' */
  fputs_P (PSTR("DATA\r\n"), stream);
  fflush (stream);
  
  /* Wait for '354 go ahead' */
  if ( SMTPWaitMessage (stream, buf, size) != 354 ) 
    return SMTP_ERR_DATA;

  /* Send the encoded message */
  fprintf_P (stream, PSTR("From: %s\r\n"), from);
  fprintf_P (stream, PSTR("To: %s\r\n"), to);
  fputs_P (PSTR("Content-Type: text/plain; charset=ISO-8859-1\r\n"
		"Content-Transfer-Encoding: 8BIT\r\n"
		"MIME-Version: 1.0\r\n"), stream);
  fprintf_P (stream, PSTR("User-Agent: ECBlite based on Nut/OS %s\r\n"), 
	     NutVersionString());
  fprintf_P (stream, PSTR("Subject: %s\r\n\r\n"), subject);

  /* Fix encoding here!!! */
  fputs (msg, stream);
  fputs_P (PSTR("\r\n.\r\n"), stream);
  fflush (stream);

  /* Wait for '250 ok' */
  if ( SMTPWaitMessage (stream, buf, size) != 250 )
    return SMTP_ERR_BODY;

  /* Exit session */
  fputs_P (PSTR("QUIT\r\n"), stream);
  fflush (stream);

  // Wait for '221 ok'
  if ( SMTPWaitMessage (stream, buf, size) != 221 ) 
    return SMTP_ERR_EXIT;
  return 0;
}

void SMTPSetDebugStream (FILE *stream) {
  debugStream = stream;
  debugEnabled = 1;
}
void SMTPDisableDebugStream (void) {
  debugStream = NULL;
  debugEnabled = 0;
}

int SMTPSendMail (u_long host, int port, const char *from,
		  const char *to, const char *subject, 
		  const char *msg) {
  TCPSOCKET *sock;
  FILE *stream;
  int n;
  char *buf;
  const int size = 256;

  buf = (char *) NutHeapAlloc (size);
  if (!buf) 
    return SMTP_ERR_OUTOFMEMORY;

  if ( (sock = NutTcpCreateSocket()) == 0 ) {
    NutHeapFree (buf);
    return SMTP_ERR_SOCKETCREATE;
  }
  if (!port)
    port = 25;
  if ( NutTcpConnect (sock, host, port) ) {
    NutHeapFree (buf);
    return SMTP_ERR_CONNECT;
  }
  if ( !(stream = _fdopen((int)sock, "r+b")) ) {
    NutTcpCloseSocket (sock);
    NutHeapFree (buf);
    return SMTP_ERR_STREAMCREATE;
  }

  /* Keep the error code - we'll have to do the rest anyway */
  n = SMTPTransport (stream, buf, size, from, to, subject, msg);

  fclose(stream);
  NutTcpCloseSocket (sock);
  NutHeapFree (buf);

  return n;
}

-------------- next part --------------
/* SMTP module for ECBlite, based on Nus/OS */

#ifndef __MOD_SMTP_H
#define __MOD_SMTP_H

#include <stdio.h>

#define SMTP_ERR_SOCKETCREATE	-1
#define SMTP_ERR_CONNECT	-2
#define SMTP_ERR_STREAMCREATE	-3
#define SMTP_ERR_OUTOFMEMORY	-4
#define SMTP_ERR_GREETING	-5
#define SMTP_ERR_HELO		-6
#define SMTP_ERR_MAILFROM	-7
#define SMTP_ERR_RCPTTO		-8
#define SMTP_ERR_DATA		-9
#define SMTP_ERR_BODY		-10
#define SMTP_ERR_EXIT		-11

extern int SMTPSendMail (u_long host, int port, const char *from,
			 const char *to, const char *subject, 
			 const char *msg);
extern void SMTPSetDebugStream (FILE *stream);
extern void SMTPDisableDebugStream (void);

#endif



More information about the En-Nut-Discussion mailing list