[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