Commit 91905487 9190548774e3ae77363f993d5f603a394c8815b1 by Alain Magloire

body.c mailer.c mbx_unixscan.c net.c tcp.c transcode.c

 	include/private/attribute0.h include/private/body0.h
 	include/private/mailer0.h include/private/net0.h
 	include/private/tcp.h include/public/body.h
 	include/public/mailer.h include/public/net.h

parsing and little of networking code, making a path for Pop and IMAP.
1 parent d9a9b601
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Library 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 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <body0.h>
#include <io0.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
static int body_read (stream_t is, char *buf, size_t buflen,
off_t off, size_t *pnread );
static int body_write (stream_t os, const char *buf, size_t buflen,
off_t off, size_t *pnwrite);
static FILE *lazy_create (void);
static int body_get_fd (stream_t stream, int *pfd);
int
body_create (body_t *pbody, void *owner)
{
body_t body;
if (pbody == NULL || owner == NULL)
return EINVAL;
body = calloc (1, sizeof (*body));
if (body == NULL)
return ENOMEM;
body->owner = owner;
*pbody = body;
return 0;
}
void
body_destroy (body_t *pbody, void *owner)
{
if (pbody && *pbody)
{
body_t body = *pbody;
if (body->owner == owner)
{
if (body->file)
{
fclose (body->file);
body->file = NULL;
}
free (body->filename); body->filename = NULL;
stream_destroy (&(body->stream), body);
}
*pbody = NULL;
}
}
int
body_get_stream (body_t body, stream_t *pstream)
{
if (body == NULL || pstream == NULL)
return EINVAL;
if (body->stream == NULL)
{
stream_t stream;
int status;
/* lazy floating body it is created when
* doing the first body_write call
*/
status = stream_create (&stream, body);
if (status != 0)
return status;
stream_set_read (stream, body_read, body);
stream_set_write (stream, body_write, body);
stream_set_fd (stream, body_get_fd, body);
body->stream = stream;
}
*pstream = body->stream;
return 0;
}
int
body_set_stream (body_t body, stream_t stream, void *owner)
{
if (body == NULL)
return EINVAL;
if (body->owner != owner)
return EACCES;
/* make sure we destroy the old one if it is own by the body */
stream_destroy (&(body->stream), body);
if (body->file)
{
fclose (body->file);
body->file = NULL;
}
body->stream = stream;
return 0;
}
int
body_set_lines (body_t body, int (*_lines)(body_t, size_t *), void *owner)
{
if (body == NULL)
return EINVAL;
if (body->owner == owner)
return EACCES;
body->_lines = _lines;
return 0;
}
int
body_lines (body_t body, size_t *plines)
{
if (body == NULL)
return EINVAL;
if (body->_lines)
return body->_lines (body, plines);
if (plines)
*plines = 0;
return 0;
}
int
body_size (body_t body, size_t *psize)
{
if (body == NULL)
return EINVAL;
/* Check to see if they want to doit themselves,
* it was probably not a floating message */
if (body->_size)
return body->_size (body, psize);
/* ok we should handle this */
if (body->file)
{
struct stat st;
if (fstat (fileno (body->file), &st) == -1)
return errno;
if (psize)
*psize = st.st_size;
}
else if (body->filename)
{
struct stat st;
if (stat (body->filename, &st) == -1)
return errno;
if (psize)
*psize = st.st_size;
}
else if (psize)
*psize = 0;
return 0;
}
int
body_set_size (body_t body, int (*_size)(body_t, size_t*) , void *owner)
{
if (body == NULL)
return EINVAL;
if (body->owner != owner)
return EACCES;
body->_size = _size;
return 0;
}
static int
body_read (stream_t is, char *buf, size_t buflen,
off_t off, size_t *pnread )
{
body_t body;
size_t nread = 0;
if (is == NULL || (body = is->owner) == NULL)
return EINVAL;
/* check if they want to read from a file */
if (body->file == NULL && body->filename)
{
/* try read only, we don't want to
* handle nasty security issues here.
*/
body->file = fopen (body->filename, "r");
if (body->file == NULL)
{
if (pnread)
*pnread = 0;
return errno;
}
}
if (body->file)
{
/* should we check the error of fseek for some handlers
* like socket where fseek () will fail.
* FIXME: Alternative is to check fseeck and errno == EBADF
* if not a seekable stream.
*/
if (fseek (body->file, off, SEEK_SET) == -1)
return errno;
nread = fread (buf, sizeof (char), buflen, body->file);
if (nread == 0)
{
if (ferror (body->file))
return errno;
/* clear the error for feof() */
clearerr (body->file);
}
}
if (pnread)
*pnread = nread;
return 0;
}
static int
body_write (stream_t os, const char *buf, size_t buflen,
off_t off, size_t *pnwrite)
{
body_t body;
size_t nwrite = 0;
if (os == NULL || (body = os->owner) == NULL)
return EINVAL;
/* FIXME: security issues, Refuse to write to an unknow file */
if (body->file == NULL && body->filename)
return EINVAL;
/* Probably being lazy, then create a body for the stream */
if (body->file == NULL)
{
body->file = lazy_create ();
if (body->file == NULL)
return errno;
}
/* should we check the error of fseek for some handlers
* like socket where it does not make sense.
* FIXME: Alternative is to check fseeck and errno == EBADF
* if not a seekable stream.
*/
if (fseek (body->file, off, SEEK_SET) == -1)
return errno;
nwrite = fwrite (buf, sizeof (char), buflen, body->file);
if (nwrite == 0)
{
if (ferror (body->file))
return errno;
/* clear the error for feof() */
clearerr (body->file);
}
if (pnwrite)
*pnwrite = nwrite;
return 0;
}
static int
body_get_fd (stream_t stream, int *pfd)
{
body_t body;
if (stream == NULL || (body = stream->owner) == NULL)
return EINVAL;
/* Probably being lazy, then create a body for the stream */
if (body->file == NULL)
{
body->file = lazy_create ();
if (body->file == 0)
return errno;
}
if (pfd)
*pfd = fileno (body->file);
return 0;
}
static FILE *
lazy_create ()
{
FILE *file;
#ifdef HAVE_MKSTEMP
char tmpbuf[L_tmpnam + 1];
int fd;
if (tmpnam (tmpbuf) == NULL ||
(fd = mkstemp (tmpbuf)) == -1 ||
(file = fdopen(fd, "w+")) == NULL)
return NULL;
(void)remove(tmpbuf);
#else
file = tmpfile ();
/* make sure the mode is right */
if (file)
fchmod (fileno (file), 0600);
#endif
return file;
}
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Library 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 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _ATTRIBUTE0_H
# define _ATTRIBUTE0_H
#include <attribute.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __P
# ifdef __STDC__
# define __P(args) args
# else
# define __P(args) ()
# endif
#endif /*__P */
struct _attribute
{
size_t flag;
void *owner;
};
#define MU_ATTRIBUTE_SEEN ((int)1)
#define MU_ATTRIBUTE_ANSWERED (MU_ATTRIBUTE_SEEN << 1)
#define MU_ATTRIBUTE_FLAGGED (MU_ATTRIBUTE_ANSWERED << 1)
#define MU_ATTRIBUTE_DELETED (MU_ATTRIBUTE_FLAGGED << 1)
#define MU_ATTRIBUTE_DRAFT (MU_ATTRIBUTE_DELETED << 1)
#define MU_ATTRIBUTE_RECENT (MU_ATTRIBUTE_DRAFT << 1)
#define MU_ATTRIBUTE_READ (MU_ATTRIBUTE_RECENT << 1)
#ifdef __cplusplus
}
#endif
#endif /* _ATTRIBUTE0_H */
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Library 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 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _BODY0_H
#define _BODY0_H
#include <io.h>
#include <body.h>
#include <stdio.h>
#include <sys/types.h>
#ifndef __P
# ifdef __STDC__
# define __P(args) args
# else
# define __P(args) ()
# endif
#endif /* __P */
#ifdef _cplusplus
extern "C" {
#endif
struct _body
{
void *owner;
/* it's better and more portable to use stdio */
FILE *file;
char *filename;
stream_t stream;
int (*_size) (body_t, size_t*);
int (*_lines) (body_t, size_t*);
};
#ifdef _cplusplus
}
#endif
#endif /* _BODY0_H */
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
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, 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 Library General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _MAILER0_H
#define _MAILER0_H
#include <sys/types.h>
#include <mailer.h>
#ifdef _cplusplus
extern "C" {
#endif
#ifndef __P
# ifdef __STDC__
# define __P(args) args
# else
# define __P(args) ()
# endif
#endif /*__P */
// mailer states
#define MAILER_STATE_HDR 1
#define MAILER_STATE_MSG 2
#define MAILER_STATE_COMPLETE 3
// mailer messages
#define MAILER_HELO 1
#define MAILER_MAIL 2
#define MAILER_RCPT 3
#define MAILER_DATA 4
#define MAILER_RSET 5
#define MAILER_QUIT 6
#define MAILER_LINE_BUF_SIZE 1000
struct _mailer
{
int socket;
char *hostname;
char line_buf[MAILER_LINE_BUF_SIZE];
int offset;
int state;
int add_dot;
stream_t stream;
char last_char;
};
#ifdef _cplusplus
}
#endif
#endif /* MAILER0_H */
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
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, 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 Library General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _NET0_H
#define _NET0_H
#include <sys/types.h>
#include <io.h>
#include <net.h>
#ifdef _cplusplus
extern "C" {
#endif
#ifndef __P
#ifdef __STDC__
#define __P(args) args
#else
#define __P(args) ()
#endif
#endif /*__P */
struct _net_api {
int (*new)(void *netdata, net_t parent, void **data);
int (*connect)(void *data, const char *host, int port);
int (*get_stream)(void *data, stream_t *iostr);
int (*close)(void *data);
int (*free)(void **data);
};
struct _netregistrar {
const char *type;
int (*create)(void **netdata, struct _net_api **api);
int (*set_option)(void *netdata, const char *name, const char *value);
int (*destroy)(void **netdata);
};
struct _net {
struct _net_api *api;
void *data;
struct _net *parent;
struct _netregistrar *net_reg;
};
struct _netinstance {
struct _net_api *api;
void *data;
};
int _tcp_create(void **data, struct _net_api **api);
int _tcp_set_option(void *data, const char *name, const char *value);
int _tcp_destroy(void **data);
#ifdef _cplusplus
}
#endif
#endif /* NET0_H */
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
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, 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 Library General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <net0.h>
#define TCP_STATE_INIT 1
#define TCP_STATE_RESOLVE 2
#define TCP_STATE_RESOLVING 3
#define TCP_STATE_CONNECTING 4
#define TCP_STATE_CONNECTED 5
struct _tcp_options {
int non_block;
int net_timeout;
};
struct _tcp_instance {
struct _tcp_options *options;
int fd;
char *host;
int port;
int state;
stream_t stream;
unsigned long address;
};
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Library 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 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _BODY_H
#define _BODY_H
#include <sys/types.h>
#include <io.h>
#ifndef __P
# ifdef __STDC__
# define __P(args) args
# else
# define __P(args) ()
# endif
#endif /* __P */
#ifdef _cplusplus
extern "C" {
#endif
/* forward declaration */
struct _body;
typedef struct _body *body_t;
extern int body_create __P ((body_t *, void *owner));
extern void body_destroy __P ((body_t *, void *owner));
extern int body_get_stream __P ((body_t, stream_t *));
extern int body_set_stream __P ((body_t, stream_t, void *owner));
extern int body_get_filename __P ((body_t, char *, size_t, size_t *));
extern int body_set_filename __P ((body_t, const char*));
extern int body_size __P ((body_t, size_t*));
extern int body_set_size __P ((body_t,
int (*_size) __P ((body_t, size_t*)),
void *owner));
extern int body_lines __P ((body_t, size_t *));
extern int body_set_lines __P ((body_t,
int (*_lines) __P ((body_t, size_t*)),
void *owner));
#ifdef _cplusplus
}
#endif
#endif /* _BODY_H */
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
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, 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 Library General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _MAILER_H
#define _MAILER_H
#include "message.h"
#include <sys/types.h>
#ifndef __P
# ifdef __STDC__
# define __P(args) args
# else
# define __P(args) ()
# endif
#endif /* __P */
#ifdef _cplusplus
extern "C" {
#endif
/* forward declaration */
struct _mailer;
typedef struct _mailer *mailer_t;
extern int mailer_create __P ((mailer_t *, message_t));
extern int mailer_connect __P ((mailer_t, char *host));
extern int mailer_disconnect __P ((mailer_t));
extern int mailer_send_header __P ((mailer_t, message_t));
extern int mailer_send_message __P ((mailer_t, message_t));
#ifdef _cplusplus
}
#endif
#endif /* _MAILER_H */
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
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, 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 Library General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _NET_H
#define _NET_H
#include <sys/types.h>
#include <io.h>
#ifdef _cplusplus
extern "C" {
#endif
#ifndef __P
#ifdef __STDC__
#define __P(args) args
#else
#define __P(args) ()
#endif
#endif /*__P */
struct _net;
typedef struct _net *net_t;
extern int net_api_create __P((net_t *, net_t, const char *type));
extern int net_api_set_option __P((net_t net, const char *name, const char *value));
extern int net_api_destroy __P((net_t *));
struct _netinstance;
typedef struct _netinstance *netinstance_t;
extern int net_new __P((net_t, netinstance_t *));
extern int net_connect __P((netinstance_t, const char *host, int port));
extern int net_get_stream __P((netinstance_t, stream_t *iostr));
extern int net_close __P((netinstance_t));
extern int net_free __P((netinstance_t *));
#ifdef _cplusplus
}
#endif
#endif /* NET_H */
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Library 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 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <errno.h>
#include <stdlib.h>
#include <stdarg.h>
#include <fcntl.h>
#include <ctype.h>
#include <mailer0.h>
int _mailer_sock_connect(char *host, int port);
char *_mailer_find_mailbox(char *addr);
int _mailer_send_command(mailer_t ml, message_t msg, int cmd);
char *nb_fgets(char *buf, int size, int s);
char *nb_fprintf(int s, char *format, ...);
#define nb_read read
#define nb_write write
#define BUFFSIZE 4096
int
mailer_create(mailer_t *pml, message_t msg)
{
mailer_t ml;
(void)msg;
if (!pml)
return EINVAL;
ml = calloc (1, sizeof (*ml));
if (ml == NULL)
return (ENOMEM);
*pml = ml;
return (0);
}
int
mailer_destroy(mailer_t *pml)
{
mailer_t ml;
if (!pml)
return (EINVAL);
ml = *pml;
if (ml->hostname)
free(ml->hostname);
mailer_disconnect(ml);
free(ml);
*pml = NULL;
return (0);
}
int
mailer_connect(mailer_t ml, char *host)
{
if (!ml || !host)
return (EINVAL);
if ((ml->socket = _mailer_sock_connect(host, 25)) < 0)
return (-1);
do
{
nb_fgets(ml->line_buf, MAILER_LINE_BUF_SIZE, ml->socket); /* read header line */
} while ( strlen(ml->line_buf) > 4 && *(ml->line_buf+3) == '-');
return (0);
}
int
mailer_disconnect(mailer_t ml)
{
if (!ml || (ml->socket != -1))
return (EINVAL);
close(ml->socket);
return (0);
}
int
mailer_send_header(mailer_t ml, message_t msg)
{
header_t hdr;
char buf[64];
if (!ml || !msg || (ml->socket == -1))
return (EINVAL);
if (!ml->hostname)
{
if (gethostname(buf, 64) < 0)
return (-1);
ml->hostname = strdup(buf);
}
if (_mailer_send_command(ml, msg, MAILER_HELO) != 0)
return (-1);
if (_mailer_send_command(ml, msg, MAILER_MAIL) != 0)
return (-1);
if (_mailer_send_command(ml, msg, MAILER_RCPT) != 0)
return (-1);
if (_mailer_send_command(ml, msg, MAILER_DATA) != 0)
return (-1);
message_get_header(msg, &hdr);
header_get_stream(hdr, &(ml->stream));
ml->state = MAILER_STATE_HDR;
return (0);
}
int
mailer_send_message(mailer_t ml, message_t msg)
{
int status, len = 0, data_len = 0, consumed = 0;
char *data, *p, *q;
if (!ml || !msg || (ml->socket == -1))
return (EINVAL);
// alloca
if (!(data = alloca(MAILER_LINE_BUF_SIZE)))
return (ENOMEM);
memset(data, 0, 1000);
if ((status = stream_read(ml->stream, data, MAILER_LINE_BUF_SIZE, ml->offset, &len)) != 0)
return (-1);
if ((len == 0) && (ml->state == MAILER_STATE_HDR))
{
ml->state = MAILER_STATE_MSG;
ml->offset = 0;
message_get_stream(msg, &(ml->stream));
return (1);
}
else if (len == 0)
{
strcpy(ml->line_buf, "\r\n.\r\n");
consumed = strlen(data);
}
else
{
p = data;
q = ml->line_buf;
memset(ml->line_buf, 0, MAILER_LINE_BUF_SIZE);
while (consumed < len)
{
// RFC821: if the first character on a line is a '.' you must add an
// extra '.' to the line which will get stipped off at the other end
if ((*p == '.') && (ml->last_char == '\n'))
ml->add_dot = 1;
ml->last_char = *p;
*q++ = *p++; // store the character
data_len++; // increase the length by 1
consumed++;
if (((MAILER_LINE_BUF_SIZE - data_len) > 1) && (ml->add_dot == 1))
{
*q++ = '.';
data_len++;
ml->add_dot = 0;
}
}
}
ml->offset += consumed;
nb_fprintf(ml->socket, "%s\r\n", ml->line_buf);
if (len == 0)
{
ml->state = MAILER_STATE_COMPLETE;
return (0);
}
return (consumed);
}
int
_mailer_sock_connect(char *host, int port)
{
struct sockaddr_in saddr;
struct hostent *hp;
int s;
memset(&saddr, 0, sizeof(struct sockaddr_in));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);
if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
return (-1);
if ((hp = gethostbyname(host)) == 0)
return (-1);
memcpy(&saddr.sin_addr, hp->h_addr, hp->h_length);
if (connect(s, (struct sockaddr *)&saddr, sizeof(saddr)) == 0)
return (s);
close(s);
return (-1);
}
char *
_mailer_find_mailbox(char *addr)
{
char *p, *c;
p = addr;
if ( (c = strchr( p, '<')) != 0)
{
p = c+1;
if ( c = strchr( p, '>'))
*c = '\0';
}
else if ( (c = strchr( p, '(' )) != 0 )
{
--c;
while ( c > p && *c && isspace( *c ) ) {
*c = '\0';
--c;
}
}
return p;
}
int
_mailer_rctp(mailer_t ml, char *str)
{
char *p, *c = NULL, *q = NULL;
for (q = p = str; q && *p; p = q+1)
{
if ( q = strchr( p, ','))
*q = '\0';
while ( p && *p && isspace( *p ) )
p++;
c = strdup(p);
p = _mailer_find_mailbox(c);
nb_fprintf(ml->socket, "RCPT TO:<%s>\r\n", p);
free(c);
nb_fgets(ml->line_buf, sizeof(ml->line_buf), ml->socket);
if (strncmp(ml->line_buf, "250", 3))
return (-strtol(ml->line_buf, 0, 10));
}
return (0);
}
int
_mailer_send_command(mailer_t ml, message_t msg, int cmd)
{
header_t hdr;
char *p, *c = NULL, *q = NULL;
char str[128];
size_t str_len;
char *success = "250";
switch (cmd)
{
case MAILER_HELO:
nb_fprintf(ml->socket, "HELO %s\r\n", ml->hostname);
break;
case MAILER_MAIL:
message_get_header(msg, &hdr);
header_get_value(hdr, MU_HEADER_FROM, str, 128, &str_len);
str[str_len] = '\0';
p = _mailer_find_mailbox(str);
nb_fprintf(ml->socket, "MAIL From: %s\r\n", p);
break;
case MAILER_RCPT:
message_get_header(msg, &hdr);
header_get_value(hdr, MU_HEADER_TO, str, 128, &str_len);
str[str_len] = '\0';
if (_mailer_rctp(ml, str) == -1)
return (-1);
header_get_value(hdr, MU_HEADER_CC, str, 128, &str_len);
str[str_len] = '\0';
if (_mailer_rctp(ml, str) == -1)
return (-1);
return (0);
break;
case MAILER_DATA:
nb_fprintf(ml->socket, "DATA\r\n");
success = "354";
break;
case MAILER_RSET:
nb_fprintf(ml->socket, "RSET\r\n");
break;
case MAILER_QUIT:
nb_fprintf(ml->socket, "QUIT\r\n");
success = "221";
break;
}
nb_fgets(ml->line_buf, sizeof(ml->line_buf), ml->socket);
if (strncmp(ml->line_buf, success, 3) == 0)
return (0);
else
return (-strtol(ml->line_buf, 0, 10));
}
char *
nb_fgets( char *buf, int size, int s )
{
static char *buffer[25];
char *p, *b, *d;
int bytes, i;
int flags;
if ( !buffer[s] && !( buffer[s] = calloc( BUFFSIZE+1, 1 ) ) )
return 0;
bytes = i = strlen( p = b = buffer[s] );
*( d = buf ) = '\0';
for ( ; i-- > 0; p++ )
{
if ( *p == '\n' )
{
char c = *( p+1 );
*( p+1 ) = '\0';
strcat( d, b );
*( p+1 ) = c;
memmove( b, p+1, i+1 );
return buf;
}
}
flags = fcntl( s, F_GETFL );
fcntl( s, F_SETFL, O_NONBLOCK );
while ( bytes <= size )
{
fd_set fds;
FD_ZERO( &fds );
FD_SET( s, &fds );
select( s+1, &fds, 0, 0, 0 ); /* we really don't care what it returns */
if ( ( i = nb_read( s, p, BUFFSIZE - bytes ) ) == -1 )
{
*b = '\0';
return 0;
}
else if ( i == 0 )
{
*( p+1 ) = '\0';
strcat( d, b );
*b = '\0';
fcntl( s, F_SETFL, flags );
return strlen( buf ) ? buf : 0;
}
*( p+i ) = '\0';
bytes += i;
for ( ; i-- > 0; p++ )
{
if ( *p == '\n' )
{
char c = *( p+1 );
*( p+1 ) = '\0';
strcat( d, b );
*( p+1 ) = c;
memmove( b, p+1, i+1 );
fcntl( s, F_SETFL, flags );
return buf;
}
}
if ( bytes == BUFFSIZE )
{
memcpy( d, b, BUFFSIZE );
d += BUFFSIZE;
size -= BUFFSIZE;
bytes = 0;
*( p = b ) = '\0';
}
}
memcpy( d, b, size );
memmove( b, b+size, strlen( b+size )+1 );
fcntl( s, F_SETFL, flags );
return buf;
}
char *
nb_fprintf( int s, char *format, ... )
{
char buf[MAILER_LINE_BUF_SIZE];
va_list vl;
int i;
va_start( vl, format );
vsprintf( buf, format, vl );
va_end( vl );
i = strlen( buf );
if ( nb_write( s, buf, i ) != i )
return 0;
return format;
}
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
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, 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 Library General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdlib.h>
#include <errno.h>
#include <net0.h>
static struct _netregistrar _netreg[1] = { "tcp", _tcp_create, _tcp_set_option, _tcp_destroy };
int net_api_create(net_t *net, net_t parent, const char *type)
{
net_t n;
int i, napis, ret = 0;
if ( net == NULL || type == NULL )
return EINVAL;
*net = NULL;
if ( ( n = calloc(1, sizeof(*n)) ) == NULL )
return ENOMEM;
napis = sizeof(_netreg) / sizeof(_netreg[0]);
for( i = 0; i < napis; i++ ) {
if ( strcasecmp(_netreg[i].type, type) == 0 )
break;
}
if ( i == napis )
return ENOTSUP;
if ( ret = ( _netreg[i].create(&(n->data), &(n->api)) ) != 0 )
free(n);
n->parent = parent;
n->net_reg = &_netreg[i];
*net = n;
return 0;
}
int net_api_set_option(net_t net, const char *name, const char *value)
{
if ( net && name && value )
return net->net_reg->set_option(net->data, name, value);
return EINVAL;
}
int net_api_destroy(net_t *net)
{
net_t n;
if ( net == NULL || *net == NULL )
return EINVAL;
n = *net;
n->net_reg->destroy(&n->data);
free(n);
*net = NULL;
return 0;
}
int net_new(net_t net, netinstance_t *inst)
{
netinstance_t netinst;
int ret = 0;
if ( net == NULL || inst == NULL )
return EINVAL;
*inst = NULL;
if ( ( netinst = calloc(1, sizeof(*netinst)) ) == NULL )
return ENOMEM;
netinst->api = net->api;
if ( ( ret = net->api->new(net->data, net->parent, &(netinst->data)) ) != 0 ) {
free(netinst);
return ret;
}
*inst = netinst;
return 0;
}
int net_connect(netinstance_t inst, const char *host, int port)
{
if ( inst == NULL || host == NULL )
return EINVAL;
return inst->api->connect(inst->data, host, port);
}
int net_get_stream(netinstance_t inst, stream_t *iostr)
{
if ( inst == NULL || iostr == NULL )
return EINVAL;
return inst->api->get_stream(inst->data, iostr);
}
int net_close(netinstance_t inst)
{
if ( inst == NULL )
return EINVAL;
return inst->api->close(inst->data);
}
int net_free(netinstance_t *pinst)
{
int ret;
netinstance_t inst;
if ( pinst == NULL || *pinst == NULL )
return EINVAL;
inst = *pinst;
ret = inst->api->free(&(inst->data));
free(inst);
*pinst = NULL;
return ret;
}
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
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, 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 Library General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <netdb.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net0.h>
#include <io0.h>
#include <tcp.h>
static int _tcp_close(void *data);
static int _tcp_doconnect(struct _tcp_instance *tcp)
{
int flgs, ret;
size_t namelen;
struct sockaddr_in peer_addr;
struct hostent *phe;
struct sockaddr_in soc_addr;
switch( tcp->state ) {
case TCP_STATE_INIT:
if ( tcp->fd == -1 ) {
if ( ( tcp->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
return errno;
}
if ( tcp->options->non_block ) {
flgs = fcntl(tcp->fd, F_GETFL);
flgs |= O_NONBLOCK;
fcntl(tcp->fd, F_SETFL, flgs);
}
tcp->state = TCP_STATE_RESOLVING;
case TCP_STATE_RESOLVING:
if ( tcp->host == NULL || tcp->port == -1 )
return EINVAL;
tcp->address = inet_addr(tcp->host);
if (tcp->address == INADDR_NONE) {
phe = gethostbyname(tcp->host);
if ( !phe ) {
_tcp_close(tcp);
return EINVAL;
}
tcp->address = *(((unsigned long **)phe->h_addr_list)[0]);
}
tcp->state = TCP_STATE_RESOLVE;
case TCP_STATE_RESOLVE:
memset (&soc_addr, 0, sizeof (soc_addr));
soc_addr.sin_family = AF_INET;
soc_addr.sin_port = htons(tcp->port);
soc_addr.sin_addr.s_addr = tcp->address;
if ( ( connect(tcp->fd, (struct sockaddr *) &soc_addr, sizeof(soc_addr)) ) == -1 ) {
ret = errno;
if ( ret == EINPROGRESS || ret == EAGAIN ) {
tcp->state = TCP_STATE_CONNECTING;
ret = EAGAIN;
} else
_tcp_close(tcp);
return ret;
}
tcp->state = TCP_STATE_CONNECTING;
case TCP_STATE_CONNECTING:
namelen = sizeof (peer_addr);
if ( getpeername (tcp->fd, (struct sockaddr *)&peer_addr, &namelen) == 0 )
tcp->state = TCP_STATE_CONNECTED;
else {
ret = errno;
_tcp_close(tcp);
return ret;
}
break;
}
return 0;
}
static int _tcp_get_fd(stream_t stream, int *fd)
{
struct _tcp_instance *tcp = stream->owner;
if ( fd == NULL )
return EINVAL;
if ( tcp->fd == -1 ) {
if ( ( tcp->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
return errno;
}
*fd = tcp->fd;
return 0;
}
static int _tcp_read(stream_t stream, char *buf, size_t buf_size, off_t offset, size_t *br)
{
struct _tcp_instance *tcp = stream->owner;
offset;
if ( br == NULL )
return EINVAL;
*br = 0;
if ( ( *br = recv(tcp->fd, buf, buf_size, 0) ) == -1 ) {
*br = 0;
return errno;
}
return 0;
}
static int _tcp_write(stream_t stream, const char *buf, size_t buf_size, off_t offset, size_t *bw)
{
struct _tcp_instance *tcp = stream->owner;
offset;
if ( bw == NULL )
return EINVAL;
*bw = 0;
if ( ( *bw = send(tcp->fd, buf, buf_size, 0) ) == -1 ) {
*bw = 0;
return errno;
}
return 0;
}
static int _tcp_new(void *netdata, net_t parent, void **data)
{
struct _tcp_instance *tcp;
if ( parent ) /* tcp must be top level api */
return EINVAL;
if ( ( tcp = malloc(sizeof(*tcp)) ) == NULL )
return ENOMEM;
tcp->options = (struct _tcp_options *)netdata;
tcp->fd = -1;
tcp->host = NULL;
tcp->port = -1;
tcp->state = TCP_STATE_INIT;
stream_create(&tcp->stream, tcp);
stream_set_read(tcp->stream, _tcp_read, tcp);
stream_set_write(tcp->stream, _tcp_write, tcp);
stream_set_fd(tcp->stream, _tcp_get_fd, tcp);
*data = tcp;
return 0;
}
static int _tcp_connect(void *data, const char *host, int port)
{
struct _tcp_instance *tcp = data;
if ( tcp->state == TCP_STATE_INIT ) {
tcp->port = port;
if ( ( tcp->host = strdup(host) ) == NULL )
return ENOMEM;
}
if ( tcp->state < TCP_STATE_CONNECTED )
return _tcp_doconnect(tcp);
return 0;
}
static int _tcp_get_stream(void *data, stream_t *stream)
{
struct _tcp_instance *tcp = data;
*stream = tcp->stream;
return 0;
}
static int _tcp_close(void *data)
{
struct _tcp_instance *tcp = data;
if ( tcp->fd != -1 )
close(tcp->fd);
tcp->fd = -1;
tcp->state = TCP_STATE_INIT;
return 0;
}
static int _tcp_free(void **data)
{
struct _tcp_instance *tcp;
if ( data == NULL || *data == NULL )
return EINVAL;
tcp = *data;
if ( tcp->host )
free(tcp->host);
if ( tcp->fd != -1 )
close(tcp->fd);
free(*data);
*data = NULL;
return 0;
}
static struct _net_api _tcp_net_api = {
_tcp_new,
_tcp_connect,
_tcp_get_stream,
_tcp_close,
_tcp_free
};
int _tcp_create(void **netdata, struct _net_api **netapi)
{
struct _tcp_options *options;
if ( ( options = malloc(sizeof(*options)) ) == NULL )
return ENOMEM;
options->non_block = 0;
options->net_timeout = -1; /* system default */
*netdata = options;
*netapi = &_tcp_net_api;
return 0;
}
int _tcp_set_option(void *netdata, const char *name, const char *value)
{
struct _tcp_options *options = netdata;
if ( strcasecmp(name, "tcp_non_block") == 0 ) {
if ( value[0] == 't' || value[0] == 'T' || value[0] == '1' || value[0] == 'y' || value[0] == 'Y')
options->non_block = 1;
else
options->non_block = 0;
}
else if ( strcasecmp(name, "tcp_timeout") == 0 )
options->net_timeout = atoi(value);
else
return EINVAL;
return 0;
}
int _tcp_destroy(void **netdata)
{
struct _tcp_options *options = *netdata;
free(options);
*netdata = NULL;
return 0;
}