Commit bee00121 bee001217ceaed8c188f1048e20dcffbcea31cf2 by Alain Magloire

attribute.c auth.c body.c header.c io.c mailbox.c mbx_pop.c

 	mbx_unix.c mbx_unixscan.c message.c mime.c tcp.c transcode.c
 	include/private/attribute0.h include/private/io0.h
 	include/private/mailbox0.h include/private/tcp.h
 	include/public/attribute.h include/public/auth.h
 	include/public/io.h include/public/mailbox.h
 	include/public/message.h
added the first basic support for pop.
 	include/private/auth0.h

move the definition of auth_t struct here.
 	net.c include/private/net0.h include/public/net.h

Overhaul change of the net_t by D. I.
1 parent 4ccdee87
......@@ -23,26 +23,24 @@
#include <errno.h>
int
attribute_create (attribute_t *pattr, void *owner)
attribute_create (attribute_t *pattr)
{
attribute_t attr;
if (pattr == NULL || owner == NULL)
if (pattr == NULL)
return EINVAL;
attr = calloc (1, sizeof(*attr));
if (attr == NULL)
return ENOMEM;
attr->owner = owner;
*pattr = attr;
return 0;
}
void
attribute_destroy (attribute_t *pattr, void *owner)
attribute_destroy (attribute_t *pattr)
{
if (pattr && *pattr)
{
attribute_t attr = *pattr;
if (attr->owner == owner)
free (attr);
/* loose the link */
*pattr = NULL;
......@@ -254,12 +252,12 @@ attribute_copy (attribute_t dest, attribute_t src)
}
int
string_to_attribute (const char *buffer, attribute_t *pattr, void *owner)
string_to_attribute (const char *buffer, attribute_t *pattr)
{
char *sep;
const char *sep;
int status;
status = attribute_create (pattr, owner);
status = attribute_create (pattr);
if (status != 0)
return status;
......@@ -268,6 +266,10 @@ string_to_attribute (const char *buffer, attribute_t *pattr, void *owner)
{
sep = strchr(buffer, ':'); /* pass the ':' */
sep++;
}
else
sep = buffer;
while (*sep == ' ') sep++; /* glob spaces */
if (strchr (sep, 'R') != NULL || strchr (sep, 'r') != NULL)
attribute_set_read (*pattr);
......@@ -277,7 +279,6 @@ string_to_attribute (const char *buffer, attribute_t *pattr, void *owner)
attribute_set_answered (*pattr);
if (strchr (sep, 'F') != NULL || strchr (sep, 'f') != NULL)
attribute_set_flagged (*pattr);
}
return 0;
}
......
......@@ -15,7 +15,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <auth.h>
#include <auth0.h>
#include <cpystr.h>
#include <errno.h>
......@@ -23,14 +23,6 @@
#include <string.h>
#include <stdlib.h>
struct _auth
{
void *owner;
int (*_prologue) (auth_t);
int (*_authenticate) (auth_t);
int (*_epilogue) (auth_t);
};
int
auth_create (auth_t *pauth, void *owner)
{
......@@ -58,7 +50,8 @@ auth_destroy (auth_t *pauth, void *owner)
}
int
auth_set_authenticate (auth_t auth, int (*_authenticate)(auth_t),
auth_set_authenticate (auth_t auth,
int (*_authenticate)(auth_t, char **, char **),
void *owner)
{
if (auth == NULL)
......@@ -70,11 +63,11 @@ auth_set_authenticate (auth_t auth, int (*_authenticate)(auth_t),
}
int
auth_authenticate (auth_t auth)
auth_authenticate (auth_t auth, char **user, char **passwd)
{
if (auth == NULL || auth->_authenticate == NULL)
return EINVAL;
return auth->_authenticate (auth);
return auth->_authenticate (auth, user, passwd);
}
int
......@@ -91,7 +84,7 @@ auth_set_epilogue (auth_t auth, int (*_epilogue)(auth_t), void *owner)
int
auth_epilogue (auth_t auth)
{
if (auth == NULL && auth->_epilogue == NULL)
if (auth == NULL || auth->_epilogue == NULL)
return EINVAL;
return auth->_epilogue (auth);
}
......@@ -110,7 +103,7 @@ auth_set_prologue (auth_t auth, int (*_prologue)(auth_t), void *owner)
int
auth_prologue (auth_t auth)
{
if (auth == NULL && auth->_prologue == NULL)
if (auth == NULL || auth->_prologue == NULL)
return EINVAL;
return auth->_prologue (auth);
}
......
......@@ -82,7 +82,7 @@ body_get_stream (body_t body, stream_t *pstream)
/* lazy floating body it is created when
* doing the first body_write call
*/
status = stream_create (&stream, 0, body);
status = stream_create (&stream, MU_STREAM_RDWR, body);
if (status != 0)
return status;
stream_set_read (stream, body_read, body);
......
......@@ -68,7 +68,7 @@ header_create (header_t *ph, const char *blurb, size_t len, void *owner)
header_parse (h, (char *)blurb, len);
status = stream_create (&(h->stream), 0, h);
status = stream_create (&(h->stream), MU_STREAM_READ|MU_STREAM_WRITE, h);
if (status != 0)
return status;
......
......@@ -35,7 +35,6 @@ extern "C" {
struct _attribute
{
size_t flag;
void *owner;
};
#define MU_ATTRIBUTE_SEEN ((int)1)
......
......@@ -2,30 +2,25 @@
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
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 General Public License for more details.
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 _NET_H
#define _NET_H
#ifndef _AUTH0_H
#define _AUTH0_H
#include <auth.h>
#include <sys/types.h>
#include <io.h>
#ifdef _cplusplus
extern "C" {
#endif
#ifndef __P
#ifdef __STDC__
#define __P(args) args
......@@ -34,24 +29,21 @@ extern "C" {
#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 *));
#ifdef _cplusplus
extern "C" {
#endif
struct _netinstance;
typedef struct _netinstance *netinstance_t;
struct _auth
{
void *owner;
int (*_prologue) (auth_t);
int (*_authenticate) (auth_t, char **user, char **passwd);
int (*_epilogue) (auth_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 */
#endif /* _AUTH0_H */
......
......@@ -36,7 +36,9 @@ struct _stream
{
void *owner;
int flags;
void (*_destroy) __P ((void *));
void (*_destroy) __P ((stream_t));
int (*_open) __P ((stream_t, const char *, int port, int flags));
int (*_close) __P ((stream_t));
int (*_get_fd) __P ((stream_t, int *));
int (*_read) __P ((stream_t, char *, size_t, off_t, size_t *));
int (*_write) __P ((stream_t, const char *, size_t, off_t, size_t *));
......
......@@ -42,7 +42,7 @@ struct _mailbox
char *name;
auth_t auth;
locker_t locker;
netinstance_t netinstance;
stream_t stream;
url_t url;
/* register events */
......
/* 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 */
......@@ -15,25 +15,16 @@
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;
};
......
......@@ -35,8 +35,8 @@ extern "C" {
struct _attribute;
typedef struct _attribute * attribute_t;
extern int attribute_create __P ((attribute_t *, void *owner));
extern void attribute_destroy __P ((attribute_t *, void *owner));
extern int attribute_create __P ((attribute_t *));
extern void attribute_destroy __P ((attribute_t *));
extern int attribute_is_seen __P ((attribute_t));
extern int attribute_is_answered __P ((attribute_t));
......@@ -68,10 +68,10 @@ extern int attribute_copy __P ((attribute_t dst,
attribute_t src));
extern int string_to_attribute __P ((const char *buf,
attribute_t *pattr, void *owner));
attribute_t *pattr));
extern int attribute_to_string __P ((attribute_t attr, char *buf,
size_t len, size_t *));
extern int attribute_get_owner __P ((attribute_t attr, void **owner));
#ifdef __cplusplus
}
#endif
......
......@@ -44,9 +44,10 @@ extern int auth_set_prologue __P ((auth_t auth,
int (*_prologue) __P ((auth_t)),
void *owner));
extern int auth_authenticate __P ((auth_t));
extern int auth_authenticate __P ((auth_t, char **, char **));
extern int auth_set_authenticate __P ((auth_t auth,
int (*_authenticate) __P ((auth_t)),
int (*_authenticate)
__P ((auth_t, char **, char **)),
void *owner));
extern int auth_epilogue __P ((auth_t));
......
......@@ -36,32 +36,58 @@ struct _stream;
typedef struct _stream *stream_t;
/* stream will be destroy on stream_destroy */
#define MU_STREAM_NO_CHECK 1
#define MU_STREAM_READ 0x00000001
#define MU_STREAM_WRITE 0x00000002
#define MU_STREAM_RDWR 0x00000004
#define MU_STREAM_APPEND 0x00000008
#define MU_STREAM_CREAT 0x00000010
#define MU_STREAM_NONBLOCK 0x00000020
#define MU_STREAM_NO_CHECK 0x00000040
extern int stream_create __P ((stream_t *, int flags, void *owner));
extern void stream_destroy __P ((stream_t *, void *owner));
extern int stream_set_destroy __P ((stream_t, void (*_destroy) __P ((stream_t)),
void *owner));
extern int stream_open __P ((stream_t, const char *, int, int));
extern int stream_set_open __P ((stream_t,
int (*_open) __P ((stream_t, const char *,
int, int)),
void *owner));
extern int stream_set_destroy __P ((stream_t,
void (*_destroy) __P ((void *)),
extern int stream_close __P ((stream_t));
extern int stream_set_close __P ((stream_t, int (*_close) __P ((stream_t)),
void *owner));
extern int stream_get_fd __P ((stream_t , int *));
extern int stream_set_fd __P ((stream_t,
int (*_get_fd)(stream_t, int *),
void *owner));
extern int stream_read __P ((stream_t, char *, size_t, off_t, size_t *));
extern int stream_set_read __P ((stream_t,
int (*_read) __P ((stream_t, char *,
size_t, off_t, size_t *)),
void *owner));
extern int stream_write __P ((stream_t, const char *, size_t, off_t, size_t *));
extern int stream_set_write __P ((stream_t,
int (*_write) __P ((stream_t, const char *,
size_t, off_t,
size_t *)),
void *owner));
extern int stream_get_fd __P ((stream_t , int *));
extern int stream_read __P ((stream_t, char *, size_t, off_t, size_t *));
extern int stream_write __P ((stream_t, const char *, size_t,
off_t, size_t *));
extern int stream_get_flags __P ((stream_t , int *flags));
/* misc */
extern int file_stream_create __P ((stream_t *stream, const char *filename,
int flags));
extern int encoder_stream_create __P ((stream_t *stream, stream_t iostream,
const char *encoding));
extern int decoder_stream_create __P ((stream_t *stream, stream_t iostream,
const char *encoding));
extern int tcp_stream_create __P ((stream_t *stream));
#ifdef __cplusplus
}
......
......@@ -23,7 +23,7 @@
#include <attribute.h>
#include <auth.h>
#include <locker.h>
#include <net.h>
#include <io.h>
#include <sys/types.h>
......@@ -48,12 +48,12 @@ extern int mailbox_create __P ((mailbox_t *, const char *, int id));
extern void mailbox_destroy __P ((mailbox_t *));
/* flags for mailbox_open () */
#define MU_MAILBOX_RDONLY ((int)1)
#define MU_MAILBOX_WRONLY (MU_MAILBOX_RDONLY << 1)
#define MU_MAILBOX_RDWR (MU_MAILBOX_WRONLY << 1)
#define MU_MAILBOX_APPEND (MU_MAILBOX_RDWR << 1)
#define MU_MAILBOX_CREAT (MU_MAILBOX_APPEND << 1)
#define MU_MAILBOX_NONBLOCK (MU_MAILBOX_CREAT << 1)
#define MU_MAILBOX_RDONLY MU_STREAM_READ
#define MU_MAILBOX_WRONLY MU_STREAM_WRITE
#define MU_MAILBOX_RDWR MU_STREAM_RDWR
#define MU_MAILBOX_APPEND MU_STREAM_APPEND
#define MU_MAILBOX_CREAT MU_STREAM_CREAT
#define MU_MAILBOX_NONBLOCK MU_STREAM_NONBLOCK
extern int mailbox_open __P ((mailbox_t, int flag));
extern int mailbox_close __P ((mailbox_t));
......@@ -64,9 +64,9 @@ extern int mailbox_append_message __P ((mailbox_t, message_t msg));
extern int mailbox_messages_count __P ((mailbox_t, size_t *num));
extern int mailbox_expunge __P ((mailbox_t));
/* netinstance settings */
extern int mailbox_get_netinstance __P ((mailbox_t, netinstance_t *net));
extern int mailbox_set_netinstance __P ((mailbox_t, netinstance_t net));
/* stream settings */
extern int mailbox_get_stream __P ((mailbox_t, stream_t *pstream));
extern int mailbox_set_stream __P ((mailbox_t, stream_t stream));
/* Lock settings */
extern int mailbox_get_locker __P ((mailbox_t, locker_t *locker));
......
......@@ -80,14 +80,25 @@ extern int message_set_received __P ((message_t,
extern int message_get_attribute __P ((message_t, attribute_t *));
extern int message_set_attribute __P ((message_t, attribute_t, void *owner));
//extern int message_clone __P ((message_t));
/* events */
#define MU_EVT_MSG_DESTROY 32
extern int message_register __P ((message_t msg, size_t type,
int (*action) (size_t typ, void *arg),
void *arg));
extern int message_deregister __P ((message_t msg, void *action));
/* misc functions */
extern int message_create_attachment __P ((const char *content_type,
const char *encoding,
const char *filename,
message_t *newmsg));
extern int message_save_attachment __P ((message_t msg,
const char *filename, void **data));
extern int message_encapsulate __P ((message_t msg, message_t *newmsg,
void **data));
extern int message_unencapsulate __P ((message_t msg, message_t *newmsg,
void **data));
#ifdef _cplusplus
}
#endif
......
......@@ -42,18 +42,17 @@ stream_destroy (stream_t *pstream, void *owner)
if (pstream && *pstream)
{
stream_t stream = *pstream;
if (!(stream->flags & MU_STREAM_NO_CHECK) && stream->owner != owner)
return;
if (stream->_destroy)
stream->_destroy (owner);
if ((stream->flags & MU_STREAM_NO_CHECK) || stream->owner == owner)
stream->_destroy (stream);
free (stream);
*pstream = NULL;
}
}
int
stream_set_destroy (stream_t stream, void (*_destroy) (void *),
void *owner)
stream_set_destroy (stream_t stream, void (*_destroy) (stream_t), void *owner)
{
if (stream == NULL)
return EINVAL;
......@@ -66,6 +65,53 @@ stream_set_destroy (stream_t stream, void (*_destroy) (void *),
}
int
stream_open (stream_t stream, const char *name, int port, int flags)
{
if (stream == NULL)
return EINVAL;
if (stream->_open)
return stream->_open (stream, name, port, flags);
return 0;
}
int
stream_set_open (stream_t stream,
int (*_open) (stream_t, const char *, int, int), void *owner)
{
if (stream == NULL)
return EINVAL;
if (owner == stream->owner)
{
stream->_open = _open;
return 0;
}
return EACCES;
}
int
stream_close (stream_t stream)
{
if (stream == NULL)
return EINVAL;
if (stream->_close)
return stream->_close (stream);
return 0;
}
int
stream_set_close (stream_t stream, int (*_close) (stream_t), void *owner)
{
if (stream == NULL)
return EINVAL;
if (owner == stream->owner)
{
stream->_close = _close;
return 0;
}
return EACCES;
}
int
stream_set_fd (stream_t stream, int (*_get_fd) (stream_t, int *), void *owner)
{
if (stream == NULL)
......@@ -85,7 +131,9 @@ stream_set_read (stream_t stream, int (*_read)
{
if (stream == NULL)
return EINVAL;
if (owner == stream->owner)
if (owner == stream->owner &&
((stream->flags & MU_STREAM_READ) ||
(stream->flags & MU_STREAM_RDWR)))
{
stream->_read = _read;
return 0;
......@@ -100,7 +148,10 @@ stream_set_write (stream_t stream, int (*_write)
{
if (stream == NULL)
return EINVAL;
if (stream->owner == owner)
if (stream->owner == owner &&
((stream->flags & MU_STREAM_WRITE) ||
(stream->flags & MU_STREAM_RDWR) ||
(stream->flags & MU_STREAM_APPEND)))
{
stream->_write = _write;
return 0;
......@@ -133,3 +184,12 @@ stream_get_fd (stream_t stream, int *pfd)
return EINVAL;
return stream->_get_fd (stream, pfd);
}
int
stream_get_flags (stream_t stream, int *pfl)
{
if (stream == NULL && pfl == NULL )
return EINVAL;
*pfl = stream->flags;
return 0;
}
......
......@@ -23,7 +23,6 @@
#include <message0.h>
#include <registrar.h>
#include <locker.h>
#include <net.h>
#include <stdlib.h>
#include <string.h>
......@@ -163,11 +162,12 @@ mailbox_set_locker (mailbox_t mbox, locker_t locker)
}
int
mailbox_get_locker (mailbox_t mbox, locker_t *locker)
mailbox_get_locker (mailbox_t mbox, locker_t *plocker)
{
if (mbox == NULL || locker == NULL)
if (mbox == NULL || plocker == NULL)
return EINVAL;
*locker = mbox->locker;
if (plocker)
*plocker = mbox->locker;
return 0;
}
......@@ -185,25 +185,27 @@ mailbox_get_auth (mailbox_t mbox, auth_t *pauth)
{
if (mbox == NULL || pauth == NULL)
return EINVAL;
if (pauth)
*pauth = mbox->auth;
return 0;
}
int
mailbox_set_netinstance (mailbox_t mbox, netinstance_t netinstance)
mailbox_set_stream (mailbox_t mbox, stream_t stream)
{
if (mbox == NULL)
return EINVAL;
mbox->netinstance = netinstance;
mbox->stream = stream;
return 0;
}
int
mailbox_get_netinstance (mailbox_t mbox, netinstance_t *pnetinstance)
mailbox_get_stream (mailbox_t mbox, stream_t *pstream)
{
if (mbox == NULL || pnetinstance == NULL)
if (mbox == NULL || pstream == NULL)
return EINVAL;
*pnetinstance = mbox->netinstance;
if (pstream)
*pstream = mbox->stream;
return 0;
}
......
......@@ -16,9 +16,21 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <mailbox0.h>
#include <io0.h>
#include <body0.h>
#include <message0.h>
#include <registrar0.h>
#include <auth0.h>
#include <attribute.h>
#include <termios.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
static int mailbox_pop_create (mailbox_t *mbox, const char *name);
static void mailbox_pop_destroy (mailbox_t *mbox);
......@@ -29,6 +41,194 @@ struct mailbox_registrar _mailbox_pop_registrar =
mailbox_pop_create, mailbox_pop_destroy
};
static int mailbox_pop_open (mailbox_t, int flags);
static int mailbox_pop_close (mailbox_t);
static int mailbox_pop_get_message (mailbox_t, size_t msgno, message_t *msg);
static int mailbox_pop_messages_count (mailbox_t, size_t *num);
static int mailbox_pop_expunge (mailbox_t);
static int mailbox_pop_num_deleted (mailbox_t, size_t *);
/* update and scanning*/
static int mailbox_pop_is_updated (mailbox_t);
static int mailbox_pop_scan (mailbox_t mbox, size_t msgno, size_t *pcount);
/* mailbox size ? */
static int mailbox_pop_size (mailbox_t, off_t *size);
static int mailbox_pop_readstream (stream_t is, char *buffer, size_t buflen,
off_t offset, size_t *pnread);
static int mailbox_pop_getfd (stream_t, int *pfd);
static int mailbox_pop_body_size (body_t, size_t *psize);
/* According to the rfc:
* RFC 2449 POP3 Extension Mechanism November 1998
* 4. Parameter and Response Lengths
* This specification increases the length restrictions on commands and
* parameters imposed by RFC 1939.
* The maximum length of a command is increased from 47 characters (4
* character command, single space, 40 character argument, CRLF) to 255
* octets, including the terminating CRLF.
* Servers which support the CAPA command MUST support commands up to
* 255 octets. Servers MUST also support the largest maximum command
* length specified by any supported capability.
* The maximum length of the first line of a command response (including
* the initial greeting) is unchanged at 512 octets (including the
* terminating CRLF).
*/
/* buffered IO */
struct _bio {
#define POP_BUFSIZ 512
int fd;
size_t maxlen;
size_t len;
char *current;
char *buffer;
char *ptr;
char *nl;
};
typedef struct _bio *bio_t;
static int bio_create (bio_t *, int);
static void bio_destroy (bio_t *);
static int bio_readline (bio_t);
static int bio_read (bio_t);
static int bio_write (bio_t);
struct _mailbox_pop_data;
struct _mailbox_pop_message;
typedef struct _mailbox_pop_data * mailbox_pop_data_t;
typedef struct _mailbox_pop_message * mailbox_pop_message_t;
struct _mailbox_pop_message
{
bio_t bio;
int started, inbody;
size_t num;
off_t body_size;
message_t message;
mailbox_pop_data_t mpd;
};
struct _mailbox_pop_data
{
void *func;
void *id;
int state;
mailbox_pop_message_t *pmessages;
size_t pmessages_count;
size_t messages_count;
size_t size;
#ifdef HAVE_PTHREAD_H
pthread_mutex_t mutex;
#endif
int flags;
int fd;
bio_t bio;
int is_updated;
char *user;
char *passwd;
mailbox_pop_message_t mpm;
} ;
/* Parse the url, allocate mailbox_t etc .. */
static int
mailbox_pop_create (mailbox_t *pmbox, const char *name)
{
mailbox_t mbox;
mailbox_pop_data_t mpd;
size_t name_len;
int status;
/* sanity check */
if (pmbox == NULL || name == NULL || *name == '\0')
return EINVAL;
name_len = strlen (name);
#define POP_SCHEME "pop://"
#define POP_SCHEME_LEN 6
#define SEPARATOR '/'
/* skip the url scheme */
if (name_len > POP_SCHEME_LEN &&
(name[0] == 'p' || name[0] == 'P') &&
(name[1] == 'o' || name[1] == 'O') &&
(name[2] == 'p' || name[2] == 'P') &&
(name[3] == ':' && name[4] == '/' && name[5] == '/'))
{
name += POP_SCHEME_LEN;
name_len -= POP_SCHEME_LEN;
}
/* allocate memory for mbox */
mbox = calloc (1, sizeof (*mbox));
if (mbox == NULL)
return ENOMEM;
/* allocate specific pop box data */
mpd = mbox->data = calloc (1, sizeof (*mpd));
if (mbox->data == NULL)
{
mailbox_pop_destroy (&mbox);
return ENOMEM;
}
/* allocate the struct for buffered I/O */
status = bio_create (&(mpd->bio), -1);
if (status != 0)
{
mailbox_pop_destroy (&mbox);
return status;
}
/* copy the name */
mbox->name = calloc (name_len + 1, sizeof (char));
if (mbox->name == NULL)
{
mailbox_pop_destroy (&mbox);
return ENOMEM;
}
memcpy (mbox->name, name, name_len);
#ifdef HAVE_PHTREAD_H
/* mutex when accessing the structure fields */
/* FIXME: should we use rdwr locks instead ?? */
pthread_mutex_init (&(mud->mutex), NULL);
#endif
/* initialize the structure */
mbox->_create = mailbox_pop_create;
mbox->_destroy = mailbox_pop_destroy;
mbox->_open = mailbox_pop_open;
mbox->_close = mailbox_pop_close;
/* messages */
mbox->_get_message = mailbox_pop_get_message;
mbox->_messages_count = mailbox_pop_messages_count;
mbox->_expunge = mailbox_pop_expunge;
mbox->_num_deleted = mailbox_pop_num_deleted;
mbox->_scan = mailbox_pop_scan;
mbox->_is_updated = mailbox_pop_is_updated;
mbox->_size = mailbox_pop_size;
(*pmbox) = mbox;
return 0; /* okdoke */
}
static void
mailbox_pop_destroy (mailbox_t *mbox)
{
......@@ -36,9 +236,1017 @@ mailbox_pop_destroy (mailbox_t *mbox)
return;
}
static struct termios stored_settings;
static void
echo_off(void)
{
struct termios new_settings;
tcgetattr (0, &stored_settings);
new_settings = stored_settings;
new_settings.c_lflag &= (~ECHO);
tcsetattr (0, TCSANOW, &new_settings);
}
static void
echo_on(void)
{
tcsetattr (0, TCSANOW, &stored_settings);
}
static int
pop_authenticate (auth_t auth, char **user, char **passwd)
{
/* FIXME: this incorrect and goes against GNU style: having a limitation
* on the user/passwd length, it should be fix
*/
char u[128];
char p[128];
mailbox_t mbox = auth->owner;
int status;
*u = '\0';
*p = '\0';
/* prompt for the user/login name */
status = url_get_user (mbox->url, u, sizeof (u), NULL);
if (status != 0 || *u == '\0')
{
printf ("Pop User: "); fflush (stdout);
fgets (u, sizeof (u), stdin);
u [strlen (u) - 1] = '\0'; /* nuke the trailing NL */
}
/* prompt for the passwd */
/* FIXME: should turn off echo .... */
status = url_get_passwd (mbox->url, p, sizeof (p), NULL);
if (status != 0 || *p == '\0' || *p == '*')
{
printf ("Pop Passwd: ");
fflush (stdout);
echo_off ();
fgets (p, sizeof(p), stdin);
echo_on ();
p [strlen (p) - 1] = '\0';
}
*user = strdup (u);
*passwd = strdup (p);
return 0;
}
static int
mailbox_pop_open (mailbox_t mbox, int flags)
{
mailbox_pop_data_t mpd;
int status;
bio_t bio;
void *func = mailbox_pop_open;
int fd;
char host[256] ;
long port;
/* sanity checks */
if (mbox == NULL || mbox->url == NULL || (mpd = mbox->data) == NULL)
return EINVAL;
/* create the networking stack */
if (!mbox->stream)
{
if ((status = url_get_host (mbox->url, host, sizeof(host), NULL)) != 0 ||
(status = url_get_port (mbox->url, &port)) != 0 ||
(status = tcp_stream_create (&(mbox->stream))) != 0)
{
mpd->func = NULL;
mpd->state = 0;
return status;
}
}
/* flag busy */
if (mpd->func && mpd->func != func)
return EBUSY;
mpd->func = func;
bio = mpd->bio;
/* spawn the prologue */
if (mbox->auth)
auth_prologue (mbox->auth);
/* enter the state machine */
switch (mpd->state)
{
/* establish the connection */
case 0:
status = stream_open (mbox->stream, host, port, flags);
if (status != 0)
{
if (status != EAGAIN && status != EINPROGRESS && status != EINTR)
{
mpd->func = NULL;
mpd->state = 0;
}
return status;
}
/* get the fd */
stream_get_fd (mbox->stream, &fd);
mpd->bio->fd = mpd->fd = fd;
mpd->state = 1;
/* glob the Greetings */
case 1:
status = bio_readline (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = NULL;
mpd->state = 0;
}
return status;
}
if (strncasecmp (bio->buffer, "+OK", 3) != 0)
{
mpd->func = NULL;
mpd->state = 0;
close (mpd->fd);
mpd->bio->fd = -1;
return EACCES;
}
/* Dealing whith Authentication */
/* so far only normal user/pass supported */
if (mbox->auth)
auth_authenticate (mbox->auth, &mpd->user, &mpd->passwd);
else
{
status = auth_create (&(mbox->auth), mbox);
if (status != 0)
{
mpd->func = NULL;
mpd->state = 0;
return status;
}
auth_set_authenticate (mbox->auth, pop_authenticate, mbox);
}
auth_authenticate (mbox->auth, &mpd->user, &mpd->passwd);
/* FIXME use snprintf */
//mpd->len = sprintf (pop->buffer, POP_BUFSIZ, "USER %s\r\n", user);
bio->len = sprintf (bio->buffer, "USER %s\r\n", mpd->user);
bio->ptr = bio->buffer;
free (mpd->user); mpd->user = NULL;
mpd->state = 2;
/* send username */
case 2:
status = bio_write (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = NULL;
mpd->state = 0;
}
return status;
}
mpd->state = 3;
/* get the ack */
case 3:
status = bio_readline (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = NULL;
mpd->state = 0;
}
return status;
}
if (strncasecmp (bio->buffer, "+OK", 3) != 0)
return EACCES;
/* FIXME use snprintf */
//mpd->len = snprintf (mpd->buffer, POP_BUFSIZ, "PASS %s\r\n", passwd);
bio->len = sprintf (bio->buffer, "PASS %s\r\n", mpd->passwd);
bio->ptr = bio->buffer;
free (mpd->passwd); mpd->passwd = NULL;
mpd->state = 4;
/* send Passwd */
case 4:
status = bio_write (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = NULL;
mpd->state = 0;
}
return status;
}
mpd->state = 5;
/* get the ack from passwd */
case 5:
status = bio_readline (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = NULL;
mpd->state = 0;
}
return status;
}
if (strncasecmp (bio->buffer, "+OK", 3) != 0)
return EACCES;
}/* swith state */
/* spawn cleanup functions */
if (mbox->auth)
auth_epilogue (mbox->auth);
/* clear any state */
mpd->func = NULL;
mpd->state = 0;
return 0;
}
static int
mailbox_pop_close (mailbox_t mbox)
{
mailbox_pop_data_t mpd;
//mailbox_pop_message_t mpm;
if (mbox == NULL || (mpd = mbox->data) == NULL)
return EINVAL;
if (mpd->fd != -1)
close (mpd->fd);
mpd->fd = -1;
return 0;
}
static int
mailbox_pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
{
mailbox_pop_data_t mpd;
bio_t bio;
int status;
size_t i;
void *func = mailbox_pop_get_message;
/* sanity */
if (mbox == NULL || pmsg == NULL || (mpd = mbox->data) == NULL)
return EINVAL;
/* see if we already have this message */
for (i = 0; i < mpd->pmessages_count; i++)
{
if (mpd->pmessages[i])
{
if (mpd->pmessages[i]->num == msgno)
{
*pmsg = mpd->pmessages[i]->message;
return 0;
}
}
}
/* are we busy in another function ? */
if (mpd->func && mpd->func != func)
return EBUSY;
/* In the function, but are we busy with an other message/request ? */
if (mpd->id && mpd->id != *pmsg)
return EBUSY;
mpd->func = func;
bio = mpd->bio;
/* Ok men, we're going in */
switch (mpd->state)
{
/* the message */
case 0:
{
message_t msg;
mailbox_pop_message_t mpm ;
mpm = calloc (1, sizeof (*mpm));
if (mpm == NULL)
return ENOMEM;
/* we'll use the bio to store headers */
mpm->bio = calloc (1, sizeof (*(mpm->bio)));
if (mpm->bio == NULL)
{
free (mpm);
mpd->func = NULL;
return ENOMEM;
}
/* create the message */
status = message_create (&msg, mpm);
if (status != 0)
{
free (mpm->bio);
free (mpm);
mpd->func = NULL;
return status;
}
/* the message */
mpm->message = msg;
mpm->num = msgno;
mpd->mpm = mpm;
/* back pointer */
mpm->mpd = mpd;
/* set the busy request state */
mpd->id = (void *)msg;
/*
* Get the header.
* FIXME: TOP is an optionnal command, if we want to
* be compliant we can not count on it to exists.
* So we should be prepare when it fails and fall to
* a second scheme
*/
/*bio->len = snprintf (bio->buffer, POP_BUFSIZ, "TOP %d 0\r\n", msgno);*/
bio->len = sprintf (bio->buffer, "TOP %d 0\r\n", msgno);
bio->ptr = bio->buffer;
mpd->state = 1;
}
/* send the TOP */
case 1:
{
status = bio_write (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
message_destroy (&(mpd->mpm->message), mpd->mpm);
bio_destroy (&(mpd->mpm->bio));
free (mpd->mpm);
mpd->mpm = NULL;
}
return status;
}
mpd->state = 2;
}
/* ack from TOP */
case 2:
{
status = bio_readline (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
message_destroy (&(mpd->mpm->message), mpd->mpm);
bio_destroy (&(mpd->mpm->bio));
free (mpd->mpm);
mpd->mpm = NULL;
}
return status;
}
if (strncasecmp (bio->buffer, "+OK", 3) != 0)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
message_destroy (&(mpd->mpm->message), mpd->mpm);
bio_destroy (&(mpd->mpm->bio));
free (mpd->mpm);
mpd->mpm = NULL;
return ERANGE;
}
mpd->state = 5;
}
/* get the header */
case 5:
{
char *tbuf;
int nread;
while (1)
{
status = bio_readline (bio);
if (status != 0)
{
/* recoverable */
if (status != EAGAIN && status != EINTR)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
message_destroy (&(mpd->mpm->message), mpd->mpm);
bio_destroy (&(mpd->mpm->bio));
free (mpd->mpm);
mpd->mpm = NULL;
}
return status;
}
/* our ticket out */
if (bio->buffer[0] == '\0')
{
mpd->mpm->bio->buffer[mpd->mpm->bio->maxlen + 1] = '\0';
break;
}
nread = (bio->nl) ? bio->nl - bio->buffer :
bio->ptr - bio->buffer + 1;
tbuf = realloc (mpd->mpm->bio->buffer,
mpd->mpm->bio->maxlen + nread + 1);
if (tbuf == NULL)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
message_destroy (&(mpd->mpm->message), mpd->mpm);
bio_destroy (&(mpd->mpm->bio));
free (mpd->mpm);
mpd->mpm = NULL;
return ENOMEM;
}
else
mpd->mpm->bio->buffer = (void *)tbuf;
memcpy (mpd->mpm->bio->buffer + mpd->mpm->bio->maxlen,
bio->buffer, nread);
mpd->mpm->bio->maxlen += nread;
} /* while () */
} /* case 5: */
break;
default:
/* error here unknow case */
fprintf (stderr, "Pop unknown state(get_message)\n");
} /* switch (state) */
/* no need to carry a state anymore */
mpd->func = mpd->id = NULL;
mpd->state = 0;
/* create the header */
{
header_t header;
status = header_create (&header, mpd->mpm->bio->buffer,
mpd->mpm->bio->maxlen, mpd->mpm);
bio_destroy (&(mpd->mpm->bio));
if (status != 0)
{
message_destroy (&(mpd->mpm->message), mpd->mpm);
free (mpd->mpm);
mpd->mpm = NULL;
return status;
}
message_set_header ((mpd->mpm->message), header, mpd->mpm);
}
/* reallocate the working buffer */
bio_create (&(mpd->mpm->bio), mpd->fd);
/* create the attribute */
{
attribute_t attribute;
char hdr_status[64];
header_t header = NULL;
hdr_status[0] = '\0';
message_get_header (mpd->mpm->message, &header);
header_get_value (header, "Status", hdr_status, sizeof (hdr_status), NULL);
/* create the attribute */
status = string_to_attribute (hdr_status, &attribute);
if (status != 0)
{
message_destroy (&(mpd->mpm->message), mpd->mpm);
bio_destroy (&(mpd->mpm->bio));
free (mpd->mpm);
mpd->mpm = NULL;
return status;
}
message_set_attribute (mpd->mpm->message, attribute, mpd->mpm);
}
/* create the body */
{
stream_t stream;
body_t body;
status = body_create (&body, mpd->mpm);
if (status != 0)
{
message_destroy (&(mpd->mpm->message), mpd->mpm);
bio_destroy (&(mpd->mpm->bio));
free (mpd->mpm);
mpd->mpm = NULL;
return status;
}
message_set_body (mpd->mpm->message, body, mpd->mpm);
status = stream_create (&stream, MU_STREAM_READ, mpd->mpm);
if (status != 0)
{
message_destroy (&(mpd->mpm->message), mpd->mpm);
bio_destroy (&(mpd->mpm->bio));
free (mpd->mpm);
mpd->mpm = NULL;
return status;
}
stream_set_read (stream, mailbox_pop_readstream, mpd->mpm);
stream_set_fd (stream, mailbox_pop_getfd, mpd->mpm);
body_set_size (body, mailbox_pop_body_size, mpd->mpm);
//body_set_lines (body, mailbox_pop_body_lines, mpd->mpm);
body_set_stream (body, stream, mpd->mpm);
}
/* add it to the list */
{
mailbox_pop_message_t *m ;
m = realloc (mpd->pmessages, (mpd->pmessages_count + 1)*sizeof (*m));
if (m == NULL)
{
message_destroy (&(mpd->mpm->message), mpd->mpm);
free (mpd->mpm);
mpd->mpm = NULL;
return ENOMEM;
}
mpd->pmessages = m;
mpd->pmessages[mpd->pmessages_count] = mpd->mpm;
mpd->pmessages_count++;
}
*pmsg = mpd->mpm->message;
return 0;
}
static int
mailbox_pop_messages_count (mailbox_t mbox, size_t *pcount)
{
mailbox_pop_data_t mpd;
int status;
void *func = mailbox_pop_messages_count;
bio_t bio;
if (mbox == NULL || (mpd = (mailbox_pop_data_t)mbox->data) == NULL)
return EINVAL;
if (mailbox_pop_is_updated (mbox))
{
if (pcount)
*pcount = mpd->messages_count;
return 0;
}
if (mpd->func && mpd->func != func)
return EBUSY;
mpd->func = func;
bio = mpd->bio;
switch (mpd->state)
{
case 0:
bio->len = sprintf (bio->buffer, "STAT\r\n");
bio->ptr = bio->buffer;
mpd->state = 1;
/* Send the STAT */
case 1:
status = bio_write (bio);
if (status != 0)
return status;
mpd->state = 2;
/* get the ACK */
case 2:
status = bio_readline (bio);
if (status != 0)
return status;
break;
default:
fprintf (stderr, "unknow state(messages_count)\n");
}
mpd->id = mpd->func = NULL;
mpd->state = 0;
status = sscanf (bio->buffer, "+OK %d %d", &(mpd->messages_count),
&(mpd->size));
mpd->is_updated = 1;
if (pcount)
*pcount = mpd->messages_count;
if (status == EOF || status != 2)
return EIO;
return 0;
}
/* update and scanning*/
static int
mailbox_pop_create (mailbox_t *mbox, const char *name)
mailbox_pop_is_updated (mailbox_t mbox)
{
(void)mbox; (void)name;
return ENOSYS;
mailbox_pop_data_t mpd;
if ((mpd = (mailbox_pop_data_t)mbox->data) == NULL)
return 0;
return mpd->is_updated;
}
static int
mailbox_pop_num_deleted (mailbox_t mbox, size_t *pnum)
{
mailbox_pop_data_t mpd;
size_t i, total;
attribute_t attr;
if (mbox == NULL ||
(mpd = (mailbox_pop_data_t) mbox->data) == NULL)
return EINVAL;
for (i = total = 0; i < mpd->messages_count; i++)
{
if (message_get_attribute (mpd->pmessages[i]->message, &attr) != 0)
{
if (attribute_is_deleted (attr))
total++;
}
}
if (pnum)
*pnum = total;
return 0;
}
/* We just simulated */
static int
mailbox_pop_scan (mailbox_t mbox, size_t msgno, size_t *pcount)
{
int status;
size_t i;
status = mailbox_pop_messages_count (mbox, pcount);
if (status != 0)
return status;
for (i = msgno; i < *pcount; i++)
if (mailbox_notification (mbox, MU_EVT_MBX_MSG_ADD) != 0)
break;
return 0;
}
/* This were we actually sending the DELE command */
static int
mailbox_pop_expunge (mailbox_t mbox)
{
mailbox_pop_data_t mpd;
size_t i;
attribute_t attr;
if (mbox == NULL ||
(mpd = (mailbox_pop_data_t) mbox->data) == NULL)
return EINVAL;
for (i = 0; i < mpd->messages_count; i++)
{
if (message_get_attribute (mpd->pmessages[i]->message, &attr) != 0)
{
if (attribute_is_deleted (attr))
{
}
}
}
return 0;
}
/* mailbox size ? */
static int
mailbox_pop_size (mailbox_t mbox, off_t *psize)
{
mailbox_pop_data_t mpd;
size_t count;
int status;
if (mbox == NULL || (mpd = (mailbox_pop_data_t)mbox->data) == NULL)
return EINVAL;
if (mailbox_pop_is_updated (mbox))
{
if (psize)
*psize = mpd->size;
return 0;
}
status = mailbox_pop_messages_count (mbox, &count);
if (psize)
*psize = mpd->size;
return status;
}
static int
mailbox_pop_body_size (body_t body, size_t *psize)
{
mailbox_pop_message_t mpm;
if (body == NULL || (mpm = body->owner) == NULL)
return EINVAL;
if (psize)
*psize = mpm->body_size;
return 0;
}
static int
mailbox_pop_getfd (stream_t stream, int *pfd)
{
mailbox_pop_message_t mpm;
if (stream == NULL || (mpm = stream->owner) == NULL)
return EINVAL;
if (pfd)
*pfd = mpm->bio->fd;
return 0;
}
static int
mailbox_pop_readstream (stream_t is, char *buffer, size_t buflen,
off_t offset, size_t *pnread)
{
mailbox_pop_message_t mpm;
mailbox_pop_data_t mpd;
size_t nread = 0;
bio_t bio;
int status = 0;
void *func = mailbox_pop_readstream;
(void)offset;
if (is == NULL || (mpm = is->owner) == NULL)
return EINVAL;
if (buffer == NULL || buflen == 0)
{
if (pnread)
*pnread = nread;
return 0;
}
bio = mpm->bio;
mpd = mpm->mpd;
/* busy ? */
if (mpd->func && mpd->func != func)
return EBUSY;
/* which request */
if (mpd->id && mpd->id != mpm)
return EBUSY;
mpd->func = func;
mpd->id = mpm;
switch (mpd->state)
{
/* send the RETR command */
case 0:
bio->len = sprintf (bio->buffer, "RETR %d\r\n", mpm->num);
mpd->state = 1;
case 1:
status = bio_write (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
}
return status;
}
mpd->state = 2;
/* RETR ACK */
case 2:
status = bio_readline (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
}
return status;
}
if (strncasecmp (bio->buffer, "+OK", 3) != 0)
return EINVAL;
mpd->state = 3;
/* skip the header */
case 3:
while (!mpm->inbody)
{
status = bio_readline (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
}
return status;
}
if (bio->buffer[0] == '\n')
{
mpm->inbody = 1;
break;
}
}
/* skip the newline */
bio_readline (bio);
/* start taking the header */
mpd->state = 4;
bio->current = bio->buffer;
case 4:
{
int nleft, n;
/* do we need to fill up */
if (bio->current >= bio->nl)
{
bio->current = bio->buffer;
status = bio_readline (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
}
}
}
n = bio->nl - bio->current;
nleft = buflen - n;
/* we got more then requested */
if (nleft <= 0)
{
memcpy (buffer, bio->current, buflen);
bio->current += buflen;
nread = buflen;
}
else
{
/* drain the buffer */
memcpy (buffer, bio->current, n);
bio->current += n;
nread = n;
}
}
} /* switch state */
if (nread == 0)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
}
if (pnread)
*pnread = nread;
return 0;
}
static int
bio_create (bio_t *pbio, int fd)
{
bio_t bio;
bio = calloc (1, sizeof (*bio));
if (bio == NULL)
return ENOMEM;
bio->maxlen = POP_BUFSIZ + 1;
bio->current = bio->ptr = bio->buffer = calloc (1, POP_BUFSIZ + 1);
if (bio->buffer == NULL)
{
free (bio);
return ENOMEM;
}
bio->fd = fd;
*pbio = bio;
return 0;
}
static void
bio_destroy (bio_t *pbio)
{
if (pbio && *pbio)
{
bio_t bio = *pbio;
free (bio->buffer);
free (bio);
*pbio = NULL;
}
}
static int
bio_write (bio_t bio)
{
int nwritten;
while (bio->len > 0)
{
nwritten = write (bio->fd, bio->ptr, bio->len);
if (nwritten < 0)
return errno;
bio->len -= nwritten;
bio->ptr += nwritten;
}
bio->ptr = bio->buffer;
return 0;
}
static int
bio_read (bio_t bio)
{
int nread, len;
len = bio->maxlen - (bio->ptr - bio->buffer) - 1;
nread = read (bio->fd, bio->ptr, len);
if (nread < 0)
return errno;
else if (nread == 0)
{ /* EOF ???? We got a situation here ??? */
bio->buffer[0] = '.';
bio->buffer[1] = '\r';
bio->buffer[2] = '\n';
nread = 3;
}
bio->ptr[nread] = '\0';
bio->ptr += nread;
return 0;
}
/*
* Responses to certain commands are multi-line. In these cases, which
* are clearly indicated below, after sending the first line of the
* response and a CRLF, any additional lines are sent, each terminated
* by a CRLF pair. When all lines of the response have been sent, a
* final line is sent, consisting of a termination octet (decimal code
* 046, ".") and a CRLF pair.
*/
static int
bio_readline (bio_t bio)
{
size_t len;
int status;
/* Still unread lines in the buffer ? */
if (bio->nl && bio->nl < bio->ptr)
{
memmove (bio->buffer, bio->nl + 1, bio->ptr - bio->nl);
bio->ptr = bio->buffer + (bio->ptr - bio->nl) - 1;
bio->nl = memchr (bio->buffer, '\n', bio->ptr - bio->buffer + 1);
//if (bio->nl == NULL)
//bio->nl = bio->buffer;
}
else
bio->nl = bio->ptr = bio->buffer;
if (bio->nl == NULL || bio->nl == bio->ptr)
{
for (;;)
{
status = bio_read (bio);
if (status < 0)
return status;
len = bio->ptr - bio->buffer;
/* a newline */
bio->nl = memchr (bio->buffer, '\n', len);
if (bio->nl == NULL)
{
if (len >= bio->maxlen)
{
char *tbuf = realloc (bio->buffer,
(2*(bio->maxlen) + 1)*(sizeof(char)));
if (tbuf == NULL)
return ENOMEM;
bio->buffer = tbuf;
bio->maxlen *= 2;
}
bio->ptr = bio->buffer + len;
}
else
break;
}
}
/*
* When examining a multi-line response, the client checks
* to see if the line begins with the termination octet "."(DOT).
* If so and if octets other than CRLF follow, the first octet
* of the line (the termination octet) is stripped away.
*/
if (bio->buffer[0] == '.')
{
if (bio->buffer[1] != '\r' && bio->buffer[2] != '\n')
{
memmove (bio->buffer, bio->buffer + 1, bio->ptr - bio->buffer);
bio->ptr--;
bio->nl--;
}
/* If so and if CRLF immediately
* follows the termination character, then the response from the POP
* server is ended and the line containing ".CRLF" is not considered
* part of the multi-line response.
*/
else if (bio->buffer[1] == '\r' && bio->buffer[2] == '\n')
{
bio->buffer[0] = '\0';
bio->nl = bio->ptr = bio->buffer;
return 0;
}
}
/* \r\n --> \n\0 */
if (bio->nl > bio->buffer)
{
*(bio->nl - 1) = '\n';
*(bio->nl) = '\0';
}
return 0;
}
......
......@@ -313,8 +313,8 @@ mailbox_unix_destroy (mailbox_t *pmbox)
continue;
/* Destroy the attach messages */
message_destroy (&(mum->message), mum);
attribute_destroy (&(mum->old_attr), mbox);
attribute_destroy (&(mum->new_attr), mbox);
attribute_destroy (&(mum->old_attr));
attribute_destroy (&(mum->new_attr));
free (mum);
}
free (mud->umessages);
......@@ -399,7 +399,11 @@ mailbox_unix_open (mailbox_t mbox, int flags)
/* Authentication */
if (mbox->auth)
{
int status = auth_authenticate (mbox->auth);
char *user = NULL;
char *passwd = NULL;
int status = auth_authenticate (mbox->auth, &user, &passwd);
free (user);
free (passwd);
if (status != 0)
return status;
}
......@@ -516,7 +520,7 @@ mailbox_unix_is_updated (mailbox_t mbox)
}
static int
mailbox_unix_num_deleted (mailbox_t mbox, size_t *num)
mailbox_unix_num_deleted (mailbox_t mbox, size_t *pnum)
{
mailbox_unix_data_t mud;
mailbox_unix_message_t mum;
......@@ -531,8 +535,8 @@ mailbox_unix_num_deleted (mailbox_t mbox, size_t *num)
total++;
}
if (num)
*num = total;
if (pnum)
*pnum = total;
return 0;
}
......@@ -894,7 +898,7 @@ mailbox_unix_getfd (stream_t is, int *pfd)
{
mailbox_unix_message_t mum;
if (is == NULL || (mum = (mailbox_unix_message_t)is->owner) == NULL)
if (is == NULL || (mum = is->owner) == NULL)
return EINVAL;
if (pfd)
*pfd = fileno (mum->file);
......@@ -908,7 +912,7 @@ mailbox_unix_readstream (stream_t is, char *buffer, size_t buflen,
mailbox_unix_message_t mum;
size_t nread = 0;
if (is == NULL || (mum = is->owner) == NULL)
if (is == NULL || (mum = (mailbox_unix_message_t)is->owner) == NULL)
return EINVAL;
if (buffer == NULL || buflen == 0)
......@@ -1169,7 +1173,7 @@ mailbox_unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
}
message_set_body (msg, body, mum);
status = stream_create (&stream, 0, mum);
status = stream_create (&stream, MU_STREAM_READ, mum);
if (status != 0)
{
message_destroy (&msg, mum);
......
......@@ -254,7 +254,7 @@ do \
} while (0)
/* skip a function call, ?? do we gain that much */
#define ATTRIBUTE_CREATE(attr,own) \
#define ATTRIBUTE_CREATE(attr,mbox) \
do \
{ \
attr = calloc (1, sizeof(*(attr))); \
......@@ -265,7 +265,6 @@ do \
mailbox_unix_unlock (mbox); \
return ENOMEM; \
} \
(attr)->owner = own; \
} while (0)
/* allocate slots for the new messages */
......
......@@ -47,7 +47,7 @@ message_create (message_t *pmsg, void *owner)
msg = calloc (1, sizeof (*msg));
if (msg == NULL)
return ENOMEM;
status = stream_create (&stream, 0, msg);
status = stream_create (&stream, MU_STREAM_RDWR, msg);
if (status != 0)
{
free (msg);
......@@ -92,7 +92,7 @@ message_destroy (message_t *pmsg, void *owner)
/* header */
header_destroy (&header, owner);
/* attribute */
attribute_destroy (&attribute, owner);
attribute_destroy (&attribute);
/* stream */
stream_destroy (&stream, owner);
......@@ -188,7 +188,7 @@ message_get_stream (message_t msg, stream_t *pstream)
{
stream_t stream;
int status;
status = stream_create (&stream, 0, msg);
status = stream_create (&stream, MU_STREAM_RDWR, msg);
if (status != 0)
return status;
stream_set_read (stream, message_read, msg);
......@@ -350,7 +350,7 @@ message_get_attribute (message_t msg, attribute_t *pattribute)
if (msg->attribute == NULL && msg->owner == NULL)
{
attribute_t attribute;
int status = attribute_create (&attribute, msg);
int status = attribute_create (&attribute);
if (status != 0)
return status;
msg->attribute = attribute;
......@@ -366,7 +366,7 @@ message_set_attribute (message_t msg, attribute_t attribute, void *owner)
return EINVAL;
if (msg->owner != owner)
return EACCES;
attribute_destroy (&(msg->attribute), msg);
attribute_destroy (&(msg->attribute));
msg->attribute = attribute;
return 0;
}
......
......@@ -83,17 +83,6 @@ static int _mime_append_part(mime_t mime, message_t msg, int body_offset, int bo
return 0;
}
static struct _mime_part *_mime_get_owner(mime_t mime, message_t msg)
{
int i;
for ( i = 0; i < mime->nmtp_parts; i++ ) {
if ( mime->mtp_parts[i] == msg->owner )
return mime->mtp_parts[i];
}
return NULL;
}
static char *_strltrim(char *str)
{
char *p;
......@@ -119,7 +108,7 @@ char *_strtrim(char *str);
#define _ISSPECIAL(c) ( \
((c) == '(') || ((c) == ')') || ((c) == '<') || ((c) == '>') \
|| ((c) == '@') || ((c) == ',') || ((c) == ';') || ((c) == ':') \
|| ((c) == '\\') || ((c) == '"') || ((c) == '.') || ((c) == '[') \
|| ((c) == '\\') || ((c) == '.') || ((c) == '[') \
|| ((c) == ']') )
static void _mime_munge_content_header(char *field_body )
......@@ -129,8 +118,10 @@ static void _mime_munge_content_header(char *field_body )
_strtrim(field_body);
if ( ( e = p = strchr(str, ';') ) == NULL )
if ( ( e = strchr(str, ';') ) == NULL )
return;
while( *e == ';' ) {
p = e;
e++;
while ( *e && isspace(*e) ) /* remove space upto param */
e++;
......@@ -140,13 +131,14 @@ static void _mime_munge_content_header(char *field_body )
while ( *e && *e != '=' ) /* find end of value */
e++;
e = p = e+1;
while ( *e && (quoted || !_ISSPECIAL(*e) || !isspace(*e) ) ) {
while ( *e && (quoted || ( !_ISSPECIAL(*e) && !isspace(*e) ) ) ) {
if ( *e == '\\' ) { /* escaped */
memmove(e, e+1, strlen(e)+2);
} else if ( *e == '\"' )
quoted = ~quoted;
e++;
}
}
}
static char *_mime_get_param(char *field_body, const char *param, int *len)
......@@ -164,7 +156,7 @@ static char *_mime_get_param(char *field_body, const char *param, int *len)
break;
*len = 0;
v = e = v + 1;
while ( *e && (quoted || !_ISSPECIAL(*e) || !isspace(*e) ) ) { /* skip pass value and calc len */
while ( *e && (quoted || ( !_ISSPECIAL(*e) && !isspace(*e) ) ) ) { /* skip pass value and calc len */
if ( *e == '\"' )
quoted = ~quoted, was_quoted = 1;
else
......@@ -256,6 +248,8 @@ static int _mime_parse_mpart_message(mime_t mime)
_mime_append_part(mime, NULL, body_offset, body_length, FALSE );
if ( ( cp2 + blength + 2 < cp && !strncasecmp(cp2+2+blength, "--",2) ) ||
!strncasecmp(cp2+blength, "--",2) ) { /* very last boundary */
mime->parser_state = MIME_STATE_BEGIN_LINE;
mime->header_length = 0;
break;
}
mime->line_ndx = -1; /* headers parsing requires empty line */
......@@ -293,6 +287,8 @@ static int _mime_parse_mpart_message(mime_t mime)
mime->body_length = body_length;
mime->body_offset = body_offset;
if ( ret != EAGAIN ) { /* finished cleanup */
if ( mime->header_length ) /* this skips the preamble */
_mime_append_part(mime, NULL, body_offset, body_length, FALSE );
mime->flags &= ~MIME_PARSER_ACTIVE;
mime->body_offset = mime->body_length = mime->header_length = 0;
}
......@@ -365,7 +361,7 @@ int mime_create(mime_t *pmime, message_t msg, int flags)
}
}
else {
if ( ( ret = message_create( &msg, mime ) ) == 0 ) {
if ( ( ret = message_create( &(mime->msg), mime ) ) == 0 ) {
mime->flags |= MIME_NEW_MESSAGE;
}
}
......@@ -449,7 +445,7 @@ int mime_get_part(mime_t mime, int part, message_t *msg)
message_set_header(mime_part->msg, mime_part->hdr, mime_part);
header_size(mime_part->hdr, &hsize);
if ( ( ret = body_create(&body, mime_part) ) == 0 ) {
if ( ( ret = stream_create(&stream, 0, mime_part) ) == 0 ) {
if ( ( ret = stream_create(&stream, MU_STREAM_READ, mime_part) ) == 0 ) {
body_set_size (body, _mime_body_size, mime_part);
stream_set_read(stream, _mime_message_read, mime_part);
body_set_stream(body, stream, mime_part);
......@@ -464,82 +460,6 @@ int mime_get_part(mime_t mime, int part, message_t *msg)
return ret;
}
int mime_unencapsulate(mime_t mime, message_t msg, message_t *newmsg)
{
size_t size, nbytes;
int ret, body_offset = 0, body_length = 0, done = 0;
char *content_type, *cp;
header_t hdr;
stream_t stream;
body_t body;
struct _mime_part *mime_part;
if ( mime == NULL || msg == NULL || newmsg == NULL || mime->flags & MIME_NEW_MESSAGE )
return EINVAL;
if ( mime->msg != msg && ( mime_part = _mime_get_owner( mime, msg ) ) == NULL ) /* I don't know about or own this message */
return EPERM;
if ( ( ret = message_get_header(msg, &hdr) ) == 0 ) {
if ( ( ret = header_get_value(hdr, "Content-Type", NULL, 0, &size) ) == 0 && size ) {
if ( ( content_type = malloc(size+1) ) == NULL )
ret = ENOMEM;
else if ( ( ret = header_get_value(hdr, "Content-Type", content_type, size+1, 0) ) == 0 ) {
_mime_munge_content_header(content_type);
if ( strncasecmp(content_type, "message/rfc822", strlen(content_type)) != 0 )
ret = EINVAL;
else {
if ( mime_part ) {
body_offset = mime_part->body_offset;
body_length = mime_part->body_len;
}
if ( ( ret = _mime_setup_buffers(mime) ) == 0 ) {
mime->line_ndx = 0;
mime->cur_offset = body_offset;
while ( !done && ( ret = stream_read(mime->stream, mime->cur_buf, mime->buf_size, mime->cur_offset, &nbytes) ) == 0 && nbytes ) {
cp = mime->cur_buf;
while ( nbytes ) {
mime->cur_line[mime->line_ndx] = *cp;
mime->line_ndx++;
if ( *cp == '\n' ) {
_mime_append_header_line(mime);
if ( mime->line_ndx == 1 ) {
done = 1;
break;
}
mime->line_ndx = 0;
}
mime->cur_offset++;
nbytes--;
cp++;
}
}
body_length -= mime->cur_offset - body_offset;
body_offset = mime->cur_offset + 1;
if ( ( ret = _mime_append_part( mime, NULL, body_offset, body_length, TRUE ) ) == 0 ) {
mime_part = mime->cap_msgs[mime->ncap_msgs - 1];
if ( ( ret = message_create(&(mime_part->msg), mime_part) ) == 0) {
message_set_header(mime_part->msg, mime_part->hdr, mime_part);
if ( ( ret = body_create(&body, mime_part) ) == 0 ) {
if ( ( ret = stream_create(&stream, 0, mime_part) ) == 0 ) {
stream_set_read(stream, _mime_message_read, mime_part);
body_set_size (body, _mime_body_size, mime_part);
body_set_stream( body, stream, mime_part);
*newmsg = mime_part->msg;
return 0;
}
message_destroy(&mime_part->msg, mime_part);
}
}
}
}
}
}
}
}
return ret;
}
int mime_get_num_parts(mime_t mime, int *nmtp_parts)
{
int ret = 0;
......
/* 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 <string.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;
}
......@@ -26,30 +26,46 @@
#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_close(stream_t stream)
{
struct _tcp_instance *tcp = stream->owner;
static int _tcp_doconnect(struct _tcp_instance *tcp)
if ( tcp->fd != -1 )
close(tcp->fd);
tcp->fd = -1;
tcp->state = TCP_STATE_INIT;
return 0;
}
static int _tcp_open(stream_t stream, const char *host, int port, int flags)
{
struct _tcp_instance *tcp = stream->owner;
int flgs, ret;
size_t namelen;
struct sockaddr_in peer_addr;
struct hostent *phe;
struct sockaddr_in soc_addr;
if ( tcp->state == TCP_STATE_INIT ) {
tcp->port = port;
if ( ( tcp->host = strdup(host) ) == NULL )
return ENOMEM;
}
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 ) {
if ( flags & MU_STREAM_NONBLOCK ) {
flgs = fcntl(tcp->fd, F_GETFL);
flgs |= O_NONBLOCK;
fcntl(tcp->fd, F_SETFL, flgs);
stream->flags |= MU_STREAM_NONBLOCK;
}
tcp->state = TCP_STATE_RESOLVING;
case TCP_STATE_RESOLVING:
......@@ -59,7 +75,7 @@ static int _tcp_doconnect(struct _tcp_instance *tcp)
if (tcp->address == INADDR_NONE) {
phe = gethostbyname(tcp->host);
if ( !phe ) {
_tcp_close(tcp);
_tcp_close(stream);
return EINVAL;
}
tcp->address = *(((unsigned long **)phe->h_addr_list)[0]);
......@@ -77,7 +93,7 @@ static int _tcp_doconnect(struct _tcp_instance *tcp)
tcp->state = TCP_STATE_CONNECTING;
ret = EAGAIN;
} else
_tcp_close(tcp);
_tcp_close(stream);
return ret;
}
tcp->state = TCP_STATE_CONNECTING;
......@@ -87,7 +103,7 @@ static int _tcp_doconnect(struct _tcp_instance *tcp)
tcp->state = TCP_STATE_CONNECTED;
else {
ret = errno;
_tcp_close(tcp);
_tcp_close(stream);
return ret;
}
break;
......@@ -95,17 +111,14 @@ static int _tcp_doconnect(struct _tcp_instance *tcp)
return 0;
}
static int _tcp_get_fd(stream_t stream, int *fd)
{
struct _tcp_instance *tcp = stream->owner;
if ( fd == NULL )
if ( fd == NULL || tcp->fd == EINVAL )
return EINVAL;
if ( tcp->fd == -1 ) {
if ( ( tcp->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
return errno;
}
*fd = tcp->fd;
return 0;
}
......@@ -113,152 +126,67 @@ static int _tcp_get_fd(stream_t stream, int *fd)
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;
int bytes;
offset;
offset = offset;
if ( br == NULL )
return EINVAL;
*br = 0;
if ( ( *br = recv(tcp->fd, buf, buf_size, 0) ) == -1 ) {
if ( ( bytes = recv(tcp->fd, buf, buf_size, 0) ) == -1 ) {
*br = 0;
return errno;
}
*br = bytes;
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;
int bytes;
offset;
offset = offset;
if ( bw == NULL )
return EINVAL;
*bw = 0;
if ( ( *bw = send(tcp->fd, buf, buf_size, 0) ) == -1 ) {
if ( ( bytes = send(tcp->fd, buf, buf_size, 0) ) == -1 ) {
*bw = 0;
return errno;
}
*bw = bytes;
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, 0, 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)
static void _tcp_destroy(stream_t stream)
{
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;
struct _tcp_instance *tcp = stream->owner;
if ( tcp->host )
free(tcp->host);
if ( tcp->fd != -1 )
close(tcp->fd);
free(*data);
*data = NULL;
return 0;
free(tcp);
}
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)
int tcp_stream_create(stream_t *stream)
{
struct _tcp_options *options;
struct _tcp_instance *tcp;
int ret;
if ( ( options = malloc(sizeof(*options)) ) == NULL )
if ( ( tcp = malloc(sizeof(*tcp)) ) == 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;
tcp->fd = -1;
tcp->host = NULL;
tcp->port = -1;
tcp->state = TCP_STATE_INIT;
if ( ( ret = stream_create(stream, MU_STREAM_NO_CHECK|MU_STREAM_RDWR, tcp) ) != 0 )
return ret;
stream_set_open(*stream, _tcp_open, tcp);
stream_set_close(*stream, _tcp_close, tcp);
stream_set_read(*stream, _tcp_read, tcp);
stream_set_write(*stream, _tcp_write, tcp);
stream_set_fd(*stream, _tcp_get_fd, tcp);
stream_set_destroy(*stream, _tcp_destroy, tcp);
return 0;
}
......