Commit f30fe5bf f30fe5bfa76d2631c1480ac31e487f23a03868a5 by Alain Magloire

Introduction of the notion of filter_t object takes a stream and

	perform some filtering on it.  All the decoding streams will move
	to this i.e. quoted-printable, base64 etc .. This scheme will also
	permit users to add to the list new filters.  Still work in progress.

	* mailbox/Makefile.am : Add filter.c filter_rfc822.c.
	* mailbox/body.c ( : When creating a floating body i.e creating
	a temporary file, the stream was not "own" by the body_t.
	(_body_get_fd): Likewised.
	(_body_read):_ Likewised.
	(_body_readline): Likewised.
	(_body_write): Likewised.
	(_body_truncate): Likewised.
	(_body_size): Likewised.
	(_body_flush): Likewised.

	* mailbox/folder_imap.c (imap_literal_string): Check if the
	callback.buffer is NULL.
	(imap_body): Do no set the callback.type if "FIELDS" is part of the
	string.

	* mailbox/header.c: Remove the support for RFC822 it will be part
	of the filter_t object.
	* mailbox/mbx_mbox.c: Likewised.
	* mailbox/mailbox.c (mailbox_size): Rename to mailbox_get_size().

	* mailbox/stream.c (stream_is_seekable): New function.
	(stream_set_property): New function.
	(stream_get_property): New function.

	* mailbox/trans_stream.c: Beautify.
1 parent 360bc51c
......@@ -20,6 +20,8 @@ body.c \
debug.c \
envelope.c \
file_stream.c \
filter.c \
filter_rfc822.c \
folder.c \
folder_imap.c \
folder_mbox.c \
......
......@@ -32,6 +32,13 @@
#include <body0.h>
static int lazy_create __P ((body_t));
static int _body_flush __P ((stream_t));
static int _body_get_fd __P ((stream_t, int *));
static int _body_read __P ((stream_t, char *, size_t, off_t, size_t *));
static int _body_readline __P ((stream_t, char *, size_t, off_t, size_t *));
static int _body_write __P ((stream_t, const char *, size_t, off_t, size_t *));
static int _body_truncate __P ((stream_t, off_t));
static int _body_size __P ((stream_t, off_t *));
int
body_create (body_t *pbody, void *owner)
......@@ -60,10 +67,23 @@ body_destroy (body_t *pbody, void *owner)
{
if (body->filename)
{
/* FIXME: should we do this? */
remove (body->filename);
free (body->filename);
}
stream_destroy (&(body->stream), body);
if (body->stream)
stream_destroy (&(body->stream), body);
if (body->fstream)
{
stream_close (body->fstream);
stream_destroy (&(body->fstream), NULL);
}
if (body->property)
property_destroy (&(body->property), body);
free (body);
}
*pbody = NULL;
......@@ -93,6 +113,33 @@ body_clear_modified (body_t body)
}
int
body_set_property (body_t body, property_t property, void *owner)
{
if (body == NULL)
return EINVAL;
if (body->owner != owner)
return EACCES;
property_destroy (&(body->property), body);
body->property = property;
return 0;
}
int
body_get_property (body_t body, property_t *pproperty)
{
if (body == NULL || pproperty == NULL)
return EINVAL;
if (body->property == NULL)
{
int status = property_create (&(body->property), body);
if (status != 0)
return status;
}
*pproperty = body->property;
return 0;
}
int
body_get_filename (body_t body, char *filename, size_t len, size_t *pn)
{
int n = 0;
......@@ -120,19 +167,27 @@ body_get_stream (body_t body, stream_t *pstream)
if (body->stream == NULL)
{
stream_t stream;
int fd;
int status = file_stream_create (&stream);
int status = stream_create (&(body->stream), MU_STREAM_RDWR, body);
if (status != 0)
return status;
status = file_stream_create (&(body->fstream));
if (status != 0)
return status;
fd = lazy_create (body);
if (fd == -1)
return errno;
status = stream_open (stream, body->filename, 0, MU_STREAM_RDWR);
status = stream_open (body->fstream, body->filename, 0, MU_STREAM_RDWR);
close (fd);
if (status != 0)
return status;
body->stream = stream;
stream_set_fd (body->stream, _body_get_fd, body);
stream_set_read (body->stream, _body_read, body);
stream_set_readline (body->stream, _body_readline, body);
stream_set_write (body->stream, _body_write, body);
stream_set_truncate (body->stream, _body_truncate, body);
stream_set_size (body->stream, _body_size, body);
stream_set_flush (body->stream, _body_flush, body);
}
*pstream = body->stream;
return 0;
......@@ -223,6 +278,55 @@ body_set_size (body_t body, int (*_size)(body_t, size_t*) , void *owner)
return 0;
}
static int
_body_get_fd (stream_t stream, int *fd)
{
body_t body = stream_get_owner (stream);
return stream_get_fd (body->fstream, fd);
}
static int
_body_read (stream_t stream, char *buffer, size_t n, off_t off, size_t *pn)
{
body_t body = stream_get_owner (stream);
return stream_read (body->fstream, buffer, n, off, pn);
}
static int
_body_readline (stream_t stream, char *buffer, size_t n, off_t off, size_t *pn)
{
body_t body = stream_get_owner (stream);
return stream_readline (body->fstream, buffer, n, off, pn);
}
static int
_body_write (stream_t stream, const char *buf, size_t n, off_t off, size_t *pn)
{
body_t body = stream_get_owner (stream);
return stream_write (body->fstream, buf, n, off, pn);
}
static int
_body_truncate (stream_t stream, off_t n)
{
body_t body = stream_get_owner (stream);
return stream_truncate (body->fstream, n);
}
static int
_body_size (stream_t stream, off_t *size)
{
body_t body = stream_get_owner (stream);
return stream_size (body->fstream, size);
}
static int
_body_flush (stream_t stream)
{
body_t body = stream_get_owner (stream);
return stream_flush (body->fstream);
}
#ifndef P_tmpdir
# define P_tmpdir "/tmp"
#endif
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 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. */
/* First draft by Alain Magloire */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <errno.h>
#ifdef HAVE_PTHREAD_H
# define _XOPEN_SOURCE 500
# include <pthread.h>
#endif
#include <mailutils/filter.h>
#include <mailutils/property.h>
static int rfc822_property __P ((property_t, const char *, const char *));
static int rfc822_init __P ((filter_t));
static void rfc822_destroy __P ((filter_t));
static int rfc822_read __P ((filter_t, char *, size_t, off_t, size_t *));
static int rfc822_readline __P ((filter_t, char *, size_t, off_t, size_t *));
static int rfc822_read0 __P ((filter_t, char *, size_t, off_t, size_t *, int));
struct rfc822
{
off_t r_offset; /* rfc822 offset. */
off_t s_offset; /* stream offset. */
size_t lines;
int residue;
};
static struct _filter _rfc822_filter =
{
"RFC822",
rfc822_init,
rfc822_read,
rfc822_readline,
NULL,
rfc822_destroy,
NULL,
NULL,
NULL,
0,
NULL
};
/* Exported. */
filter_t rfc822_filter = &_rfc822_filter;
static int
rfc822_property (property_t property, const char *key, const char *value)
{
filter_t filter = property_get_owner (property);
struct rfc822 *rfc822 = filter->data;
(void)key;
rfc822->lines = strtoul (value, NULL, 10);
return 0;
}
static int
rfc822_init (filter_t filter)
{
property_t property;
int status;
filter->data = calloc (1, sizeof (struct rfc822));
if (filter->data == NULL)
return ENOMEM;
/* We are interested in this property. */
if ((status = stream_get_property (filter->filter_stream, &property) != 0)
|| (status = property_add_defaults (property, "LINES", "0",
rfc822_property, NULL, filter)) != 0)
{
free (filter->data);
filter->data = NULL;
return status;
}
return 0;
}
static void
rfc822_destroy (filter_t filter)
{
if (filter->data)
free (filter->data);
}
static int
rfc822_read (filter_t filter, char *buffer, size_t buflen,
off_t off, size_t *pnread)
{
return rfc822_read0 (filter, buffer, buflen, off, pnread, 0);
}
static int
rfc822_readline (filter_t filter, char *buffer, size_t buflen,
off_t off, size_t *pnread)
{
return rfc822_read0 (filter, buffer, buflen, off, pnread, 1);
}
/* RFC 822 converter "\n" --> "\r\n"
We maintain to offset, the rfc822 offset (r_offset) and the offset of
the stream (s_offset). If they do not match we go back as for as possible
and start to read by 1 'till we reach the current offset. */
static int
rfc822_read0 (filter_t filter, char *buffer, size_t buflen,
off_t off, size_t *pnread, int isreadline)
{
size_t total = 0;
int status = 0;
struct rfc822 *rfc822 = filter->data;
/* Catch up i.e bring us to the current offset. */
if (rfc822->r_offset != off)
{
rfc822->r_offset = off - rfc822->lines;
rfc822->residue = 0;
if (rfc822->r_offset < 0)
rfc822->r_offset = 0;
rfc822->s_offset = rfc822->r_offset;
while (rfc822->r_offset < off)
{
char c;
size_t n = 0;
status = stream_read (filter->stream, &c, 1, rfc822->s_offset, &n);
if (status != 0)
return status;
if (n == 0)
break;
if (c == '\n')
{
rfc822->r_offset++;
if (rfc822->r_offset == off)
{
rfc822->residue = 1;
break;
}
}
rfc822->r_offset++;
rfc822->s_offset++;
}
}
do
{
size_t nread = 0;
status = stream_readline (filter->stream, buffer, buflen,
rfc822->s_offset, &nread);
if (status != 0)
return status;
if (nread == 0)
break;
rfc822->r_offset += nread;
rfc822->s_offset += nread;
total += nread;
buflen -= nread;
if (buffer[nread - 1] == '\n')
{
if (!rfc822->residue)
{
buffer[nread - 1] = '\r';
if (buflen == 0)
{
rfc822->residue = 1;
break;
}
buffer[nread] = '\n';
buflen--;
nread++;
total++;
rfc822->r_offset++;
}
else
rfc822->residue = 0;
}
buffer += nread;
} while (buflen > 0 || !isreadline);
if (isreadline)
*buffer = '\0';
if (pnread)
*pnread = total;
return status;
}
......@@ -756,11 +756,11 @@ imap_literal_string (f_imap_t f_imap, char **ptr)
f_imap->ptr = f_imap->buffer;
/* How much ? */
len0= len = f_imap->nl - f_imap->buffer;
len0 = len = f_imap->nl - f_imap->buffer;
/* Check if the last read did not finish on a line, if yes do not copy in
callback buffer the terminating sequence ")\r\n". We are doing this
by checking if the amount(total) we got so far + the len of the line
+1 (taking to account the strip '\r'). */
+1 (taking to account the strip '\r') goes behond the request. */
if ((total + len + 1) > f_imap->callback.nleft)
{
len0 = len = f_imap->callback.nleft - total;
......@@ -777,8 +777,9 @@ imap_literal_string (f_imap_t f_imap, char **ptr)
/* Check how much we can fill the callback buffer. */
int x = (f_imap->callback.buflen - f_imap->callback.total) - len0;
x = (x >= 0) ? len0 : (x + len0);
memcpy (f_imap->callback.buffer + f_imap->callback.total,
f_imap->buffer, x);
if (f_imap->callback.buffer)
memcpy (f_imap->callback.buffer + f_imap->callback.total,
f_imap->buffer, x);
f_imap->callback.total += x;
/* Depending on the type of request we incremente the xxxx_lines
......@@ -838,7 +839,8 @@ imap_quoted_string (f_imap_t f_imap, char **ptr)
f_imap->callback.total = *ptr - bquote;
/* Fill the call back buffer. The if is redundant there should always
be enough room since the request is base on the buffer size. */
if (f_imap->callback.total <= f_imap->callback.buflen)
if (f_imap->callback.total <= f_imap->callback.buflen
&& f_imap->callback.buffer)
memcpy (f_imap->callback.buffer, bquote, f_imap->callback.total);
if (**ptr == '"')
(*ptr)++;
......@@ -1238,6 +1240,7 @@ imap_body (f_imap_t f_imap, char **ptr)
if (**ptr == '[')
{
char *sep = strchr (*ptr, ']');
(*ptr)++; /* Move pass the '[' */
if (sep)
{
size_t len = sep - *ptr;
......@@ -1250,20 +1253,22 @@ imap_body (f_imap_t f_imap, char **ptr)
if (isalpha((unsigned)*p))
*p = toupper ((unsigned)*p);
/* Check to see the callback type to update the line count. */
if (strstr (section, "MIME")
|| (strstr (section, "HEADER") && ! strstr (section, "FIELD")))
if (!strstr (section, "FIELD"))
{
f_imap->callback.type = IMAP_HEADER;
}
else if (strstr (section, "TEXT"))
{
f_imap->callback.type = IMAP_BODY;
}
else if (len == 1) /* body[] */
{
f_imap->callback.type = IMAP_MESSAGE;
if (strstr (section, "MIME") || (strstr (section, "HEADER")))
{
f_imap->callback.type = IMAP_HEADER;
}
else if (strstr (section, "TEXT") || len > 0)
{
f_imap->callback.type = IMAP_BODY;
}
else if (len == 0) /* body[] */
{
f_imap->callback.type = IMAP_MESSAGE;
}
}
sep++;
sep++; /* Move pass the ']' */
*ptr = sep;
}
}
......@@ -1586,15 +1591,12 @@ imap_readline (f_imap_t f_imap)
while (f_imap->nl == NULL);
/* Conversion \r\n --> \n\0 */
/**/
if (f_imap->selected == NULL
|| f_imap->selected->mailbox->properties[PROP_RFC822].value == 0)
if (f_imap->nl > f_imap->buffer)
{
*(f_imap->nl - 1) = '\n';
*(f_imap->nl) = '\0';
f_imap->ptr = f_imap->nl;
}
if (f_imap->nl > f_imap->buffer)
{
*(f_imap->nl - 1) = '\n';
*(f_imap->nl) = '\0';
f_imap->ptr = f_imap->nl;
}
return 0;
}
......
......@@ -413,7 +413,6 @@ header_get_value (header_t header, const char *name, char *buffer,
size_t name_len;
size_t total = 0, fn_len = 0, fv_len = 0;
size_t threshold;
int rfc822 = 0;
int err = 0;
if (header == NULL || name == NULL)
......@@ -456,10 +455,6 @@ header_get_value (header_t header, const char *name, char *buffer,
return err;
}
/* Do they want rfc822 format */
if (header->property)
rfc822 = property_is_set (header->property, "RFC822");
/* We set the threshold to be 1 less for the null. */
threshold = --buflen;
......@@ -481,25 +476,7 @@ header_get_value (header_t header, const char *name, char *buffer,
if (buffer && threshold > 0)
{
buflen = (fv_len < threshold) ? fv_len : threshold;
if (rfc822)
{
/* Convert to \r\n */
char *s = header->hdr[i].fv;
size_t j;
for (j = 0; j < buflen; s++, j++)
{
if (*s == '\n')
{
buffer[j] = '\r';
/* Side effect. */
if (++j >= buflen)
break;
}
buffer[j] = *s;
}
}
else
memcpy (buffer, header->hdr[i].fv, buflen);
memcpy (buffer, header->hdr[i].fv, buflen);
buffer += buflen;
threshold -= buflen;
}
......@@ -679,15 +656,7 @@ header_size (header_t header, size_t *psize)
}
if (psize)
{
*psize = header->blurb_len;
if (property_is_set (header->property, "RFC822"))
{
size_t lines = 0;
header_lines (header, &lines);
*psize += lines;
}
}
*psize = header->blurb_len;
return 0;
}
......@@ -708,6 +677,12 @@ header_get_property (header_t header, property_t *pp)
{
if (header == NULL || pp == NULL)
return EINVAL;
if (header->property == NULL)
{
int status = property_create (&(header->property), header);
if (status != 0)
return status;
}
*pp = header->property;
return 0;
}
......@@ -874,7 +849,6 @@ header_read (stream_t is, char *buf, size_t buflen, off_t off, size_t *pnread)
{
int len;
header_t header = stream_get_owner (is);
int rfc822 = 0;
if (is == NULL || header == NULL)
return EINVAL;
......@@ -894,53 +868,14 @@ header_read (stream_t is, char *buf, size_t buflen, off_t off, size_t *pnread)
return err;
}
if (header->property)
rfc822 = property_is_set (header->property, "RFC822");
if (rfc822)
len = header->blurb_len - off;
if (len > 0)
{
size_t j;
int residue = 0;
char *s = header->blurb;
char *e = header->blurb + header->blurb_len;
/* Get to the offset. */
for (j = 0; j < (size_t)off && s < e; j++, s++)
{
if (*s == '\n')
{
if (++j >= (size_t)off)
{
residue = 1;
break;
}
}
}
if (residue)
buf[0] = '\r';
/* Copy. */
for (j = residue ; j < buflen && s < e; j++, s++)
{
if (*s == '\n')
{
buf[j] = '\r';
if (++j >= buflen)
break;
}
buf[j] = *s;
}
len = j;
len = (buflen < (size_t)len) ? buflen : len;
memcpy (buf, header->blurb + off, len);
}
else
{
len = header->blurb_len - off;
if (len > 0)
{
len = (buflen < (size_t)len) ? buflen : len;
memcpy (buf, header->blurb + off, len);
}
else
len = 0;
}
len = 0;
if (pnread)
*pnread = len;
......@@ -952,7 +887,6 @@ header_readline (stream_t is, char *buf, size_t buflen, off_t off, size_t *pn)
{
int len;
header_t header = stream_get_owner (is);
int rfc822 = 0;
if (is == NULL || header == NULL)
return EINVAL;
......@@ -972,54 +906,19 @@ header_readline (stream_t is, char *buf, size_t buflen, off_t off, size_t *pn)
return err;
}
if (header->property)
rfc822 = property_is_set (header->property, "RFC822");
buflen--; /* Space for the null. */
if (rfc822)
len = header->blurb_len - off;
if (len > 0)
{
size_t j;
char *s = header->blurb;
char *e = header->blurb + header->blurb_len;
char *nl;
/* Get to the offset. */
for (j = 0; j < (size_t)off && s <= e; j++, s++)
{
if (*s == '\n')
{
if (++j >= (size_t)off)
break;
}
}
/* Copy. */
e = (nl = memchr (s, '\n', e - s)) ? nl : e;
for (j = 0 ; j < buflen && s <= e; j++, s++)
{
if (*s == '\n')
{
buf[j] = '\r';
if (++j >= buflen)
break;
}
buf[j] = *s;
}
len = j;
char *nl = memchr (header->blurb + off, '\n', len);
if (nl)
len = nl - (header->blurb + off) + 1;
len = (buflen < (size_t)len) ? buflen : len;
memcpy (buf, header->blurb + off, len);
}
else
{
len = header->blurb_len - off;
if (len > 0)
{
char *nl = memchr (header->blurb + off, '\n', len);
if (nl)
len = nl - (header->blurb + off) + 1;
len = (buflen < (size_t)len) ? buflen : len;
memcpy (buf, header->blurb + off, len);
}
else
len = 0;
}
len = 0;
if (pn)
*pn = len;
buf[len] = '\0';
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
Copyright (C) 1999, 2000, 2001 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
......@@ -43,11 +43,12 @@ extern "C" {
struct _body
{
void *owner;
/* it's better and more portable to use stdio */
FILE *file;
char *filename;
stream_t stream;
stream_t fstream;
property_t property;
int flags;
int (*_size) (body_t, size_t*);
int (*_lines) (body_t, size_t*);
};
......
......@@ -40,6 +40,14 @@ extern "C" {
# endif
#endif /*__P */
struct default_properties
{
char *key;
char *value;
int (*_set_value) __P ((property_t, const char *, const char *));
int (*_get_value) __P ((property_t, const char *, char *, size_t, size_t *));
};
struct _mailbox
{
/* Data */
......@@ -48,7 +56,7 @@ struct _mailbox
ticket_t ticket;
authority_t authority;
property_t property;
struct property_list *properties;
struct default_properties *properties;
size_t properties_count;
locker_t locker;
stream_t stream;
......@@ -81,7 +89,7 @@ struct _mailbox
int (*_scan) __P ((mailbox_t, size_t msgno, size_t *count));
int (*_is_updated) __P ((mailbox_t));
int (*_size) __P ((mailbox_t, off_t *size));
int (*_get_size) __P ((mailbox_t, off_t *size));
};
......
......@@ -53,6 +53,14 @@ extern "C" {
#define MAILER_LINE_BUF_SIZE 1000
struct default_properties
{
char *key;
char *value;
int (*_set_value) __P ((property_t, const char *, const char *));
int (*_get_value) __P ((property_t, const char *, char *, size_t, size_t *));
};
struct _mailer
{
stream_t stream;
......@@ -62,7 +70,7 @@ struct _mailer
int flags;
monitor_t monitor;
property_t property;
struct property_list *properties;
struct default_properties *properties;
size_t properties_count;
/* Pointer to the specific mailer data. */
......
......@@ -50,7 +50,9 @@ struct _message
header_t header;
body_t body;
int flags;
stream_t stream;
property_t property;
attribute_t attribute;
monitor_t monitor;
mime_t mime;
......
......@@ -41,10 +41,13 @@
extern "C" {
#endif
struct property_private
struct property_data
{
size_t hash;
int *address;
char *key;
char *value;
int (*_set_value) __P ((property_t, const char *, const char *));
int (*_get_value) __P ((property_t, const char *, char *, size_t, size_t *));
};
struct _property
......
......@@ -48,6 +48,7 @@ struct rbuffer
struct _stream
{
void *owner;
property_t property;
int flags;
int state;
......
......@@ -274,11 +274,11 @@ mailbox_scan (mailbox_t mbox, size_t msgno, size_t *pcount)
}
int
mailbox_size (mailbox_t mbox, off_t *psize)
mailbox_get_size (mailbox_t mbox, off_t *psize)
{
if (mbox == NULL || mbox->_size == NULL)
if (mbox == NULL || mbox->_get_size == NULL)
return ENOSYS;
return mbox->_size (mbox, psize);
return mbox->_get_size (mbox, psize);
}
int
......@@ -426,10 +426,12 @@ mailbox_get_property (mailbox_t mbox, property_t *pproperty)
/* Add the defaults. */
for (i = 0; i < mbox->properties_count; i++)
{
status = property_add_default (mbox->property,
mbox->properties[i].key,
&(mbox->properties[i].value),
mbox);
status = property_add_defaults (mbox->property,
mbox->properties[i].key,
mbox->properties[i].value,
mbox->properties[i]._set_value,
mbox->properties[i]._get_value,
mbox);
if (status != 0)
{
property_destroy (&(mbox->property), mbox);
......
......@@ -145,6 +145,8 @@ mailer_destroy (mailer_t *pmailer)
{
if (mailer->properties[i].key)
free (mailer->properties[i].key);
if (mailer->properties[i].value)
free (mailer->properties[i].value);
}
free (mailer->properties);
}
......@@ -237,10 +239,12 @@ mailer_get_property (mailer_t mailer, property_t *pproperty)
/* Add the defaults. */
for (i = 0; i < mailer->properties_count; i++)
{
status = property_add_default (mailer->property,
mailer->properties[i].key,
&(mailer->properties[i].value),
mailer);
status = property_add_defaults (mailer->property,
mailer->properties[i].key,
mailer->properties[i].value,
mailer->properties[i]._set_value,
mailer->properties[i]._get_value,
mailer);
if (status != 0)
{
property_destroy (&(mailer->property), mailer);
......
......@@ -145,14 +145,12 @@ _mailbox_imap_init (mailbox_t mailbox)
m_imap->mailbox = mailbox;
/* Set our properties. */
mailbox->properties = calloc (2, sizeof (*(mailbox->properties)));
mailbox->properties = calloc (1, sizeof (*(mailbox->properties)));
if (mailbox->properties == NULL)
return ENOMEM;
mailbox->properties_count = 2;
mailbox->properties[0].key = strdup ("IMAP4");
mailbox->properties[0].value = 1;
mailbox->properties[1].key = strdup ("RFC822");
mailbox->properties[1].value = 0;
mailbox->properties_count = 1;
mailbox->properties[0].key = strdup ("TYPE");
mailbox->properties[0].value = strdup ("IMAP");
return 0;
}
......@@ -436,6 +434,7 @@ imap_get_message0 (msg_imap_t msg_imap, message_t *pmsg)
/* Set the UID on the message. */
message_set_uid (msg, imap_message_uid, msg_imap);
message_set_mailbox (msg, mailbox, msg_imap);
*pmsg = msg;
return 0;
......@@ -720,6 +719,7 @@ imap_submessage_size (msg_imap_t msg_imap, size_t *psize)
{
if (psize)
{
*psize = 0;
if (msg_imap->message_size == 0)
{
size_t i, size;
......@@ -1129,13 +1129,10 @@ imap_header_get_value (header_t header, const char *field, char * buffer,
/* Hack, if buffer == NULL they want to know how big is the field value,
Unfortunately IMAP does not say, so we take a guess hoping that the
value will not be over 1024. */
/* FIXME: This is stupid, find a way to fix this. */
if (buffer == NULL || buflen == 0)
len = 1024;
else
len = strlen (field) + buflen + 4;
value = alloca (len);
/*memset (value, '0', len); */
if (f_imap->state == IMAP_NO_STATE)
{
......@@ -1151,14 +1148,18 @@ imap_header_get_value (header_t header, const char *field, char * buffer,
f_imap->state = IMAP_FETCH;
}
value = calloc (len, sizeof (*value));
status = message_operation (f_imap, msg_imap, value, len, &len);
if (status == 0)
{
char *colon;
/* The field-matching is case-insensitive but otherwise exact. In all
cases, the delimiting blank line between the header and the body is
always included. */
/* The field-matching is case-insensitive. In all cases, the delimiting
newline between the header and the body is always included.
Nuke it */
value[len - 1] = '\0';
/* Move pass the field-name. */
colon = strchr (value, ':');
if (colon)
{
......@@ -1183,8 +1184,8 @@ imap_header_get_value (header_t header, const char *field, char * buffer,
if (len == 0)
status = ENOENT;
}
free (value);
return status;
}
static int
......
......@@ -46,11 +46,6 @@
#include <registrar0.h>
#include <mailbox0.h>
/* See porperties in _init. */
#define PROP_TYPE 0
#define PROP_RFC822 1
#define ATTRIBUTE_IS_DELETED(flag) (flag & MU_ATTRIBUTE_DELETED)
#define ATTRIBUTE_IS_EQUAL(flag1, flag2) (flag1 == flag2)
......@@ -110,14 +105,6 @@ struct _mbox_message
off_t body;
off_t body_end;
/* Save the offset for rfc822 format. */
struct _rfc822
{
off_t r_offset;
off_t f_offset;
int residue;
} rfc822;
/* Fast header retrieve, we save here the most common headers. This will
speed the header search. The entire headers are copied, when modified,
by the header_t object, we do not have to worry about updating them. */
......@@ -177,7 +164,7 @@ static int mbox_uidvalidity __P ((mailbox_t, unsigned long *));
static int mbox_uidnext __P ((mailbox_t, size_t *));
static int mbox_scan __P ((mailbox_t, size_t, size_t *));
static int mbox_is_updated __P ((mailbox_t));
static int mbox_size __P ((mailbox_t, off_t *));
static int mbox_get_size __P ((mailbox_t, off_t *));
/* private stuff */
static int mbox_scan0 __P ((mailbox_t, size_t, size_t *, int));
......@@ -195,9 +182,6 @@ static int mbox_body_read __P ((stream_t, char *, size_t, off_t,
size_t *));
static int mbox_body_readline __P ((stream_t, char *, size_t, off_t,
size_t *));
static int mbox_readstream_rfc822 __P ((mbox_message_t, char *, size_t,
off_t, size_t *, int, off_t,
off_t));
static int mbox_readstream __P ((mbox_message_t, char *, size_t,
off_t, size_t *, int, off_t,
off_t));
......@@ -275,17 +259,15 @@ _mailbox_mbox_init (mailbox_t mailbox)
mailbox->_scan = mbox_scan;
mailbox->_is_updated = mbox_is_updated;
mailbox->_size = mbox_size;
mailbox->_get_size = mbox_get_size;
/* Set our properties. */
mailbox->properties = calloc (2, sizeof (*(mailbox->properties)));
mailbox->properties = calloc (1, sizeof (*(mailbox->properties)));
if (mailbox->properties == NULL)
return ENOMEM;
mailbox->properties_count = 2;
mailbox->properties[0].key = strdup ("MBOX");
mailbox->properties[0].value = 1;
mailbox->properties[1].key = strdup ("RFC822");
mailbox->properties[1].value = 0;
mailbox->properties_count = 1;
mailbox->properties[0].key = strdup ("TYPE");
mailbox->properties[0].value = strdup ("MBOX");
MAILBOX_DEBUG1 (mailbox, MU_DEBUG_TRACE, "mbox_init(%s)\n", mud->name);
return 0; /* okdoke */
......@@ -993,12 +975,8 @@ mbox_body_readline (stream_t is, char *buffer, size_t buflen,
message_t msg = body_get_owner (body);
mbox_message_t mum = message_get_owner (msg);
if (mum->mud->mailbox->properties[PROP_RFC822].value)
return mbox_readstream_rfc822 (mum, buffer, buflen, off, pnread, 1,
mum->body, mum->body_end);
else
return mbox_readstream (mum, buffer, buflen, off, pnread, 1,
mum->body, mum->body_end);
return mbox_readstream (mum, buffer, buflen, off, pnread, 1,
mum->body, mum->body_end);
}
static int
......@@ -1008,98 +986,8 @@ mbox_body_read (stream_t is, char *buffer, size_t buflen,
body_t body = stream_get_owner (is);
message_t msg = body_get_owner (body);
mbox_message_t mum = message_get_owner (msg);
if (mum->mud->mailbox->properties[PROP_RFC822].value)
return mbox_readstream_rfc822 (mum, buffer, buflen, off, pnread, 0,
mum->body, mum->body_end);
else
return mbox_readstream (mum, buffer, buflen, off, pnread, 0,
mum->body, mum->body_end);
}
static int
mbox_readstream_rfc822 (mbox_message_t mum, char *buffer, size_t buflen,
off_t off, size_t *pnread, int isreadline,
off_t start, off_t end)
{
size_t total = 0;
int status = 0;
if (isreadline)
buflen--;
/* Catch up i.e bring us to the current offset. */
if (mum->rfc822.r_offset != off)
{
mum->rfc822.r_offset = off - mum->body_lines;
mum->rfc822.residue = 0;
if (mum->rfc822.r_offset < 0)
mum->rfc822.r_offset = 0;
mum->rfc822.f_offset = mum->rfc822.r_offset;
while (mum->rfc822.r_offset < off)
{
char c;
size_t n = 0;
status = stream_read (mum->mud->mailbox->stream, &c, 1,
mum->rfc822.f_offset, &n);
if (status != 0)
return status;
if (n == 0)
break;
if (c == '\n')
{
mum->rfc822.r_offset++;
if (mum->rfc822.r_offset == off)
{
mum->rfc822.residue = 1;
break;
}
}
mum->rfc822.r_offset++;
mum->rfc822.f_offset++;
}
}
do
{
size_t nread = 0;
status = mbox_readstream (mum, buffer, buflen, mum->rfc822.f_offset,
&nread, 1, start, end);
if (status != 0)
return status;
if (nread == 0)
break;
mum->rfc822.f_offset += nread;
mum->rfc822.r_offset += nread;
total += nread;
buflen -= nread;
if (buffer[nread - 1] == '\n')
{
if (!mum->rfc822.residue)
{
buffer[nread - 1] = '\r';
if (buflen == 0)
{
mum->rfc822.residue = 1;
break;
}
buffer[nread] = '\n';
buflen--;
nread++;
total++;
mum->rfc822.r_offset++;
}
else
mum->rfc822.residue = 0;
}
buffer += nread;
} while (buflen > 0 || !isreadline);
if (isreadline)
*buffer = '\0';
if (pnread)
*pnread = total;
return status;
return mbox_readstream (mum, buffer, buflen, off, pnread, 0,
mum->body, mum->body_end);
}
static int
......@@ -1187,28 +1075,8 @@ mbox_header_get_fvalue (header_t header, const char *name, char *buffer,
{
/* For the null. */
buflen--;
/* Convert to \r\n */
if (mum->mud->mailbox->properties[PROP_RFC822].value)
{
char *s = mum->fhdr[i];
for (fv_len = 0; *s && fv_len < buflen;
s++, fv_len++)
{
if (*s == '\n')
{
buffer[fv_len] = '\r';
/* Side effect. */
if (++fv_len >= buflen)
break;
}
buffer[fv_len] = *s;
}
}
else
{
fv_len = (fv_len < buflen) ? fv_len : buflen;
memcpy (buffer, mum->fhdr[i], fv_len);
}
fv_len = (fv_len < buflen) ? fv_len : buflen;
memcpy (buffer, mum->fhdr[i], fv_len);
buffer[fv_len] = '\0';
}
err = 0;
......@@ -1232,13 +1100,7 @@ mbox_header_size (header_t header, size_t *psize)
if (mum == NULL)
return EINVAL;
if (psize)
{
*psize = mum->body - mum->header_from_end;
#if 1
if (mum->mud->mailbox->properties[PROP_RFC822].value)
*psize += mum->header_lines;
#endif
}
*psize = mum->body - mum->header_from_end;
return 0;
}
......@@ -1262,13 +1124,7 @@ mbox_body_size (body_t body, size_t *psize)
if (mum == NULL)
return EINVAL;
if (psize)
{
*psize = mum->body_end - mum->body + 1;
#if 1
if (mum->mud->mailbox->properties[PROP_RFC822].value)
*psize += mum->body_lines;
#endif
}
*psize = mum->body_end - mum->body + 1;
return 0;
}
......@@ -1421,16 +1277,12 @@ mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg)
/* Set the header. */
{
header_t header = NULL;
property_t property = NULL;
status = header_create (&header, NULL, 0, msg);
if (status != 0)
{
message_destroy (&msg, mum);
return status;
}
/* Force the mailbox to register the properties. */
mailbox_get_property (mailbox, &property);
header_set_property (header, property, msg);
header_set_fill (header, mbox_header_fill, msg);
header_set_get_fvalue (header, mbox_header_get_fvalue, msg);
header_set_size (header, mbox_header_size, msg);
......@@ -1458,7 +1310,9 @@ mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg)
body_t body = NULL;
stream_t stream = NULL;
if ((status = body_create (&body, msg)) != 0
|| (status = stream_create (&stream, mailbox->flags, body)) != 0)
|| (status = stream_create (&stream,
mailbox->flags | MU_STREAM_SEEKABLE,
body)) != 0)
{
body_destroy (&body, msg);
stream_destroy (&stream, body);
......@@ -1493,7 +1347,7 @@ mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg)
/* Attach the message to the mailbox mbox data. */
mum->message = msg;
message_set_mailbox (msg, mailbox);
message_set_mailbox (msg, mailbox, mum);
*pmsg = msg;
return 0;
......@@ -1832,7 +1686,7 @@ mbox_append_message0 (mailbox_t mailbox, message_t msg, off_t *psize,
}
static int
mbox_size (mailbox_t mailbox, off_t *psize)
mbox_get_size (mailbox_t mailbox, off_t *psize)
{
off_t size;
int status;
......
......@@ -87,7 +87,7 @@ static int pop_is_updated __P ((mailbox_t));
/* The implementation of message_t */
static int pop_user __P ((authority_t));
static int pop_size __P ((mailbox_t, off_t *));
static int pop_get_size __P ((mailbox_t, off_t *));
/* We use pop_top for retreiving headers. */
/* static int pop_header_read (header_t, char *, size_t, off_t, size_t *); */
static int pop_body_fd __P ((stream_t, int *));
......@@ -292,17 +292,15 @@ _mailbox_pop_init (mailbox_t mbox)
mbox->_scan = pop_scan;
mbox->_is_updated = pop_is_updated;
mbox->_size = pop_size;
mbox->_get_size = pop_get_size;
/* Properties. */
mbox->properties = calloc (2, sizeof (*(mbox->properties)));
mbox->properties = calloc (1, sizeof (*(mbox->properties)));
if (mbox->properties == NULL)
return ENOMEM;
mbox->properties_count = 2;
mbox->properties[0].key = strdup ("POP3");
mbox->properties[0].value = 1;
mbox->properties[1].key = strdup ("RFC822");
mbox->properties[1].value = 0;
mbox->properties_count = 1;
mbox->properties[0].key = strdup ("TYPE");
mbox->properties[0].value = strdup ("POP3");
return 0; /* Okdoke. */
}
......@@ -799,7 +797,7 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
monitor_unlock (mbox->monitor);
/* Save The message pointer. */
message_set_mailbox (msg, mbox);
message_set_mailbox (msg, mbox, mpm);
*pmsg = mpm->message = msg;
return 0;
......@@ -1005,7 +1003,7 @@ pop_expunge (mailbox_t mbox)
/* Mailbox size ? It is part of the STAT command */
static int
pop_size (mailbox_t mbox, off_t *psize)
pop_get_size (mailbox_t mbox, off_t *psize)
{
pop_data_t mpd = mbox->data;
int status = 0;
......@@ -1865,14 +1863,12 @@ pop_readline (pop_data_t mpd)
mpd->nl = NULL;
}
}
/* \r\n --> \n\0, conversion, If the propety is set no conversion
is done. */
if (mpd->mbox->properties[PROP_RFC822].value == 0)
if (mpd->nl > mpd->buffer)
{
*(mpd->nl - 1) = '\n';
*(mpd->nl) = '\0';
mpd->ptr = mpd->nl;
}
/* \r\n --> \n\0, conversion. */
if (mpd->nl > mpd->buffer)
{
*(mpd->nl - 1) = '\n';
*(mpd->nl) = '\0';
mpd->ptr = mpd->nl;
}
return 0;
}
......
......@@ -182,10 +182,43 @@ message_clear_modified (message_t msg)
}
int
message_set_mailbox (message_t msg, mailbox_t mailbox)
message_set_property (message_t msg, property_t property, void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
header_set_property (msg->header, property, msg);
body_set_property (msg->body, property, msg);
property_destroy (&(msg->property), msg);
msg->property = property;
return 0;
}
int
message_get_property (message_t msg, property_t *pproperty)
{
if (msg == NULL || pproperty == NULL)
return EINVAL;
if (msg->property == NULL)
{
int status = property_create (&(msg->property), msg);
if (status != 0)
return status;
header_set_property (msg->header, msg->property, msg);
body_set_property (msg->body, msg->property, msg);
}
*pproperty = msg->property;
return 0;
}
int
message_set_mailbox (message_t msg, mailbox_t mailbox, void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->mailbox = mailbox;
return 0;
}
......
......@@ -21,9 +21,13 @@
#include <property0.h>
static int property_find __P ((list_t, const char *, struct property_list **));
static int property_add __P ((property_t, const char *, int, int *));
static void property_update __P ((struct property_list *));
static int property_find __P ((list_t, const char *, struct property_data **));
static int property_add __P ((property_t, const char *, const char *,
int (*_set_value)
__P ((property_t, const char *, const char *)),
int (*_get_value)
__P ((property_t, const char *, char *,
size_t, size_t *))));
static size_t property_hash __P ((const char *));
int
......@@ -51,22 +55,21 @@ property_destroy (property_t *pp, void *owner)
/* Destroy the list and is properties. */
if (prop->list)
{
struct property_list *pl = NULL;
struct property_data *pd = NULL;
iterator_t iterator = NULL;
iterator_create (&iterator, prop->list);
for (iterator_first (iterator); !iterator_is_done (iterator);
iterator_next (iterator))
{
iterator_current (iterator, (void **)&pl);
if (pl)
iterator_current (iterator, (void **)&pd);
if (pd)
{
if (pl->key)
free (pl->key);
if (pl->private_)
free (pl->private_);
free (pl);
if (pd->key)
free (pd->key);
if (pd->value)
free (pd->value);
free (pd);
}
}
iterator_destroy (&iterator);
......@@ -85,98 +88,126 @@ property_get_owner (property_t prop)
}
int
property_add_default (property_t prop, const char *key, int *address,
property_add_defaults (property_t prop, const char *key, const char *value,
int (*_set_value) __P ((property_t, const char *,
const char *)),
int (*_get_value) __P ((property_t, const char *,
char *, size_t, size_t *)),
void *owner)
{
if (prop == NULL)
return EINVAL;
if (prop->owner != owner)
return EACCES;
return property_add (prop, key, 0, address);
return property_add (prop, key, value, _set_value, _get_value);
}
int
property_set_value (property_t prop, const char *key, int value)
property_set_value (property_t prop, const char *key, const char *value)
{
if (prop == NULL)
return EINVAL;
return property_add (prop, key, value, NULL);
return property_add (prop, key, value, NULL, NULL);
}
int
property_get_value (property_t prop, const char *key, int *pvalue)
property_get_value (property_t prop, const char *key, char *buffer,
size_t buflen, size_t *n)
{
struct property_list *pl = NULL;
struct property_data *pd = NULL;
int status;
size_t len;
if (prop == NULL)
return EINVAL;
status = property_find (prop->list, key, &pl);
status = property_find (prop->list, key, &pd);
if (status != 0)
return status;
if (pl == NULL)
if (pd == NULL)
return ENOENT;
/* Update the value. */
property_update (pl);
if (pvalue)
*pvalue = pl->value;
if (pd->_get_value)
return pd->_get_value (prop, key, buffer, buflen, n);
len = (pd->value) ? strlen (pd->value) : 0;
if (buffer && buflen != 0)
{
buflen--;
len = (buflen < len) ? buflen : len;
strncpy (buffer, pd->value, len)[len] = '\0';
}
if (n)
*n = len;
return 0;
}
#if 0
int
property_set (property_t prop, const char *k)
property_load (property_t prop, stream_t stream)
{
return property_set_value (prop, k, 1);
size_t n = 0;
off_t off = 0;
int status;
int buflen = 512;
char *buf = calloc (buflen, sizeof (*buf));
if (buf == NULL)
return ENOMEM;
while ((status = stream_readline (stream, buf, buflen, off, &n)) == 0
&& n > 0)
{
char *sep;
if (buf[n] != '\n')
{
char *tmp;
buflen *= 2;
tmp = realloc (buf, buflen);
if (tmp == NULL)
{
free (buf);
return ENOMEM;
}
buf = tmp;
continue;
}
sep = strchr (buf, '=');
if (sep)
{
*sep++ = '\0';
property_set_value (prop, buf, sep);
}
else
property_set (prop, buf);
}
return 0;
}
#endif
int
property_unset (property_t prop, const char *k)
property_set (property_t prop, const char *k)
{
int v = 0;
property_get_value (prop, k, &v);
if (v != 0)
return property_set_value (prop, k, 0);
if (!property_is_set (prop, k))
return property_set_value (prop, k, "1");
return 0;
}
int
property_is_set (property_t prop, const char *k)
property_unset (property_t prop, const char *k)
{
int v = 0;
property_get_value (prop, k, &v);
return (v != 0);
if (property_is_set (prop, k))
return property_set_value (prop, k, NULL);
return 0;
}
int
property_get_list (property_t prop, list_t *plist)
property_is_set (property_t prop, const char *k)
{
struct property_list *pl = NULL;
iterator_t iterator = NULL;
int status;
if (plist == NULL || prop == NULL)
return EINVAL;
status = iterator_create (&iterator, prop->list);
if (status != 0)
return status;
/* Make sure the values are updated before passing it outside. */
for (iterator_first (iterator); !iterator_is_done (iterator);
iterator_next (iterator))
{
iterator_current (iterator, (void **)&pl);
if (pl)
property_update (pl);
}
iterator_destroy (&iterator);
*plist = prop->list;
return 0;
int n = 0;
property_get_value (prop, k, NULL, 0, &n);
return (n != 0);
}
/* Taking from an article in Dr Dobbs. */
......@@ -196,24 +227,12 @@ property_hash (const char *s)
return hashval;
}
static void
property_update (struct property_list *pl)
{
/* Update the value. */
if (pl->private_)
{
struct property_private *private_ = pl->private_;
if (private_->address)
pl->value = *(private_->address);
}
}
static int
property_find (list_t list, const char *key, struct property_list **p)
property_find (list_t list, const char *key, struct property_data **p)
{
int status;
size_t h;
struct property_list *pl = NULL;
struct property_data *pd = NULL;
iterator_t iterator;
status = iterator_create (&iterator, list);
......@@ -224,28 +243,30 @@ property_find (list_t list, const char *key, struct property_list **p)
for (iterator_first (iterator); !iterator_is_done (iterator);
iterator_next (iterator))
{
iterator_current (iterator, (void **)&pl);
if (pl)
iterator_current (iterator, (void **)&pd);
if (pd)
{
struct property_private *private_ = pl->private_;
if (private_->hash == h)
if (strcasecmp (pl->key, key) == 0)
if (pd->hash == h)
if (pd->key && strcasecmp (pd->key, key) == 0)
break;
}
pl = NULL;
pd = NULL;
}
iterator_destroy (&iterator);
*p = pl;
*p = pd;
return 0;
}
static int
property_add (property_t prop, const char *key, int value, int *address)
property_add (property_t prop, const char *key, const char *value,
int (*_set_value) __P ((property_t, const char *, const char *)),
int (*_get_value) __P ((property_t, const char *, char *,
size_t, size_t *)))
{
struct property_list *pl = NULL;
struct property_data *pd = NULL;
int status;
if (key == NULL)
if (key == NULL || *key == '\0')
return EINVAL;
if (prop->list == NULL)
......@@ -255,47 +276,26 @@ property_add (property_t prop, const char *key, int value, int *address)
return status;
}
status = property_find (prop->list, key, &pl);
status = property_find (prop->list, key, &pd);
if (status != 0)
return status;
/* None find create a new one. */
if (pl == NULL)
if (pd == NULL)
{
struct property_private *private_;
pl = calloc (1, sizeof (*pl));
if (pl == NULL)
pd = calloc (1, sizeof (*pd));
if (pd == NULL)
return ENOMEM;
private_ = calloc (1, sizeof (*private_));
if (private_ == NULL)
{
free (pl);
return ENOMEM;
}
pl->key = strdup (key);
if (pl->key == NULL)
{
free (private_);
free (pl);
return ENOMEM;
}
pl->value = value;
private_->hash = property_hash (key);
private_->address = address;
pl->private_ = private_;
list_append (prop->list, (void *)pl);
}
else
{
struct property_private *private_ = pl->private_;
if (address)
private_->address = address;
else
{
if (private_->address)
*(private_->address) = value;
pl->value = value;
}
pd->hash = property_hash (key);
list_append (prop->list, (void *)pd);
}
if (pd->key == NULL)
pd->key = strdup (key);
if (pd->value)
free (pd->value);
pd->value = (value) ? strdup (value) : NULL;
pd->_set_value = _set_value;
pd->_get_value = _get_value;
return 0;
}
......
......@@ -86,8 +86,8 @@ _mailer_sendmail_init (mailer_t mailer)
if (mailer->properties == NULL)
return ENOMEM;
mailer->properties_count = 1;
mailer->properties[0].key = strdup ("SENDMAIL");
mailer->properties[0].value = 1;
mailer->properties[0].key = strdup ("TYPE");
mailer->properties[0].value = strdup ("SENDMAIL");
return 0;
}
......
......@@ -164,8 +164,8 @@ _mailer_smtp_init (mailer_t mailer)
if (mailer->properties == NULL)
return ENOMEM;
mailer->properties_count = 1;
mailer->properties[0].key = strdup ("SMTP");
mailer->properties[0].value = 1;
mailer->properties[0].key = strdup ("TYPE");
mailer->properties[0].value = strdup ("SMTP");
return 0;
}
......
......@@ -41,7 +41,9 @@ static int refill (stream_t, off_t);
/* Stream is a way for object to do I/O, they can take over(overload) the
the read/write functions for there needs. We are doing some very
minimal buffering on the read when the stream_bufsiz is set, this
unfortunately does not take to account the offset, this buffering is more
unfortunately does not take to account the offset i.e if the offset ask
is different then the offset we maintain internally, the buffer is flushed
and a new buffer is use, this buffering is more
for networking stream (POP/IMAP). No buffering on the write. */
int
stream_create (stream_t *pstream, int flags, void *owner)
......@@ -116,6 +118,12 @@ stream_close (stream_t stream)
}
int
stream_is_seekable (stream_t stream)
{
return (stream) ? stream->flags & MU_STREAM_SEEKABLE : 0;
}
int
stream_setbufsiz (stream_t stream, size_t size)
{
if (stream == NULL)
......@@ -396,6 +404,34 @@ stream_get_flags (stream_t stream, int *pfl)
}
int
stream_set_property (stream_t stream, property_t property, void *owner)
{
if (stream == NULL)
return EINVAL;
if (stream->owner != owner)
return EACCES;
if (stream->property)
property_destroy (&(stream->property), stream);
stream->property = property;
return 0;
}
int
stream_get_property (stream_t stream, property_t *pp)
{
if (stream == NULL)
return EINVAL;
if (stream->property == NULL)
{
int status = property_create (&(stream->property), stream);
if (status != 0)
return status;
}
*pp = stream->property;
return 0;
}
int
stream_size (stream_t stream, off_t *psize)
{
if (stream == NULL || stream->_size == NULL)
......
......@@ -19,7 +19,6 @@
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
......@@ -37,185 +36,200 @@
struct _trans_stream
{
stream_t stream; /* encoder/decoder read/writes data to/from here */
int t_offset;
stream_t stream; /* encoder/decoder read/writes data to/from here */
int t_offset;
int min_size;
int s_offset;
char *s_buf; /* used when read it not big enough to handle min_size for decoder/encoder */
int min_size;
int s_offset;
char *s_buf; /* Used when read if not big enough to handle min_size
for decoder/encoder */
int offset; /* current stream offset */
int line_len;
int offset; /* Current stream offset */
int line_len;
int w_rhd; /* working buffer read head */
int w_whd; /* working buffer write head */
char w_buf[MU_TRANS_BSIZE]; /* working source/dest buffer */
int w_rhd; /* Working buffer read ahead */
int w_whd; /* Working buffer write ahead */
char w_buf[MU_TRANS_BSIZE]; /* working source/dest buffer */
int (*transcoder)(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len);
int (*transcoder) __P ((const char *iptr, size_t isize, char *optr,
size_t osize, size_t *nbytes, int *line_len));
};
struct _ts_desc
{
const char *encoding;
const char *encoding;
int (*_init)(struct _trans_stream *ts, int type);
int (*_decode)(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len);
int (*_encode)(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len);
int (*_init) __P ((struct _trans_stream *ts, int type));
int (*_decode) __P ((const char *iptr, size_t isize, char *optr,
size_t osize, size_t *nbytes, int *line_len));
int (*_encode) __P ((const char *iptr, size_t isize, char *optr,
size_t osize, size_t *nbytes, int *line_len));
};
static int _base64_init(struct _trans_stream *ts, int type);
static int _base64_decode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len);
static int _base64_encode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len);
static int _qp_init(struct _trans_stream *ts, int type);
static int _qp_decode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len);
static int _qp_encode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len);
#define NUM_TRANSCODERS 5
struct _ts_desc tslist[NUM_TRANSCODERS] = {
{ "base64", _base64_init, _base64_decode, _base64_encode},
{ "quoted-printable", _qp_init, _qp_decode, _qp_encode},
{ "7bit", NULL, NULL, NULL},
{ "8bit", NULL, NULL, NULL},
{ "binary", NULL, NULL, NULL}
static int _base64_init __P ((struct _trans_stream *ts, int type));
static int _base64_decode __P ((const char *iptr, size_t isize, char *optr,
size_t osize, size_t *nbytes, int *line_len));
static int _base64_encode __P ((const char *iptr, size_t isize, char *optr,
size_t osize, size_t *nbytes, int *line_len));
static int _qp_init __P ((struct _trans_stream *ts, int type));
static int _qp_decode __P ((const char *iptr, size_t isize, char *optr,
size_t osize, size_t *nbytes, int *line_len));
static int _qp_encode __P ((const char *iptr, size_t isize, char *optr,
size_t osize, size_t *nbytes, int *line_len));
/* #define NUM_TRANSCODERS 6 */
/* struct _ts_desc tslist[NUM_TRANSCODERS] = */
struct _ts_desc tslist[] =
{
{ "base64", _base64_init, _base64_decode, _base64_encode },
{ "quoted-printable", _qp_init, _qp_decode, _qp_encode },
{ "7bit", NULL, NULL, NULL },
{ "8bit", NULL, NULL, NULL },
{ "binary", NULL, NULL, NULL }
};
static void
_trans_destroy(stream_t stream)
_trans_destroy (stream_t stream)
{
struct _trans_stream *ts = stream_get_owner(stream);
stream_destroy(&(ts->stream), NULL);
free(ts);
struct _trans_stream *ts = stream_get_owner (stream);
stream_destroy (&(ts->stream), NULL);
free (ts);
}
static int
_trans_read(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nbytes)
_trans_read (stream_t stream, char *optr, size_t osize, off_t offset,
size_t *n_bytes)
{
struct _trans_stream *ts = stream_get_owner(stream);
size_t obytes, wbytes;
int ret = 0, i;
if ( nbytes == NULL || optr == NULL || osize == 0 )
return EINVAL;
*nbytes = 0;
if ( ts->transcoder == NULL )
return stream_read(ts->stream, optr, osize, offset, nbytes);
if ( offset && ts->t_offset != offset )
return ESPIPE;
if ( offset == 0 )
ts->s_offset = ts->t_offset = ts->w_whd = ts->w_rhd = ts->offset = ts->line_len = 0;
while ( *nbytes < osize ) {
if ( ( ts->w_rhd + ts->min_size ) >= ts->w_whd ) {
memmove(ts->w_buf, ts->w_buf + ts->w_rhd, ts->w_whd - ts->w_rhd);
ts->w_whd = ts->w_whd - ts->w_rhd;
ts->w_rhd = 0;
if ( ( ret = stream_read( ts->stream, ts->w_buf + ts->w_whd, MU_TRANS_BSIZE - ts->w_whd, ts->offset, &wbytes ) ) != 0 )
break;
ts->offset += wbytes;
ts->w_whd += wbytes;
}
if ( (osize - *nbytes) >= ts->min_size && ts->s_offset == 0 && ts->w_whd - ts->w_rhd ) {
ts->w_rhd += ts->transcoder(ts->w_buf + ts->w_rhd, ts->w_whd - ts->w_rhd, optr + *nbytes, osize - *nbytes, &obytes, &ts->line_len);
if ( ts->w_rhd > ts->w_whd ) /* over shot due to padding */
ts->w_rhd = ts->w_whd;
*nbytes += obytes;
ts->t_offset += obytes;
} else {
if ( ts->s_offset == 0 && ts->w_whd - ts->w_rhd) {
ts->w_rhd += ts->transcoder(ts->w_buf + ts->w_rhd, ts->w_whd - ts->w_rhd, ts->s_buf, ts->min_size, &obytes, &ts->line_len);
if ( ts->w_rhd > ts->w_whd ) /* over shot due to padding */
ts->w_rhd = ts->w_whd;
ts->s_offset = obytes;
}
for ( i = ts->s_offset; i > 0; i-- ) {
optr[(*nbytes)++] = ts->s_buf[ts->s_offset - i];
ts->t_offset++;
if ( *nbytes >= osize ) {
i--;
memmove(ts->s_buf, &ts->s_buf[ts->s_offset - i], i );
break;
}
}
ts->s_offset = i;
struct _trans_stream *ts = stream_get_owner (stream);
size_t obytes, wbytes;
int ret = 0, i;
size_t bytes, *nbytes = &bytes;
if (optr == NULL || osize == 0)
return EINVAL;
if (ts->transcoder == NULL)
return stream_read (ts->stream, optr, osize, offset, n_bytes);
if (n_bytes)
nbytes = n_bytes;
*nbytes = 0;
if (offset && ts->t_offset != offset)
return ESPIPE;
if (offset == 0)
ts->s_offset = ts->t_offset = ts->w_whd = ts->w_rhd =
ts->offset = ts->line_len = 0;
while (*nbytes < osize)
{
if ((ts->w_rhd + ts->min_size) >= ts->w_whd)
{
memmove (ts->w_buf, ts->w_buf + ts->w_rhd, ts->w_whd - ts->w_rhd);
ts->w_whd = ts->w_whd - ts->w_rhd;
ts->w_rhd = 0;
ret = stream_read (ts->stream, ts->w_buf + ts->w_whd,
MU_TRANS_BSIZE - ts->w_whd, ts->offset,
&wbytes );
if (ret != 0)
break;
ts->offset += wbytes;
ts->w_whd += wbytes;
}
if ((osize - *nbytes) >= ts->min_size
&& ts->s_offset == 0
&& ts->w_whd - ts->w_rhd)
{
ts->w_rhd += ts->transcoder (ts->w_buf + ts->w_rhd,
ts->w_whd - ts->w_rhd,
optr + *nbytes, osize - *nbytes,
&obytes, &ts->line_len);
if (ts->w_rhd > ts->w_whd) /* over shot due to padding */
ts->w_rhd = ts->w_whd;
*nbytes += obytes;
ts->t_offset += obytes;
}
else
{
if (ts->s_offset == 0 && ts->w_whd - ts->w_rhd)
{
ts->w_rhd += ts->transcoder (ts->w_buf + ts->w_rhd,
ts->w_whd - ts->w_rhd, ts->s_buf,
ts->min_size, &obytes,
&ts->line_len);
if (ts->w_rhd > ts->w_whd) /* over shot due to padding */
ts->w_rhd = ts->w_whd;
ts->s_offset = obytes;
}
for (i = ts->s_offset; i > 0; i--)
{
optr[(*nbytes)++] = ts->s_buf[ts->s_offset - i];
ts->t_offset++;
if (*nbytes >= osize)
{
i--;
memmove (ts->s_buf, &ts->s_buf[ts->s_offset - i], i);
break;
}
if ( wbytes == 0 && ts->s_offset == 0 )
break;
}
ts->s_offset = i;
}
return ret;
if (wbytes == 0 && ts->s_offset == 0)
break;
}
return ret;
}
static int
_trans_write(stream_t stream, const char *iptr, size_t isize, off_t offset, size_t *nbytes)
_trans_write (stream_t stream, const char *iptr, size_t isize, off_t offset,
size_t *nbytes)
{
struct _trans_stream *ts = stream_get_owner(stream);
if ( nbytes == NULL || iptr == NULL || isize == 0 )
return EINVAL;
*nbytes = 0;
if ( ts->transcoder == NULL )
return stream_write(ts->stream, iptr, isize, offset, nbytes);
if ( offset && ts->offset != offset )
return ESPIPE;
if ( offset == 0 )
ts->t_offset = ts->w_whd = ts->w_rhd = ts->offset = 0;
return EINVAL;
struct _trans_stream *ts = stream_get_owner (stream);
return stream_write (ts->stream, iptr, isize, offset, nbytes);
}
static int
_trans_open (stream_t stream, const char *filename, int port, int flags)
{
struct _trans_stream *ts = stream_get_owner(stream);
return stream_open(ts->stream, filename, port, flags);
struct _trans_stream *ts = stream_get_owner (stream);
return stream_open (ts->stream, filename, port, flags);
}
static int
_trans_truncate (stream_t stream, off_t len)
{
struct _trans_stream *ts = stream_get_owner(stream);
return stream_truncate(ts->stream, len);
struct _trans_stream *ts = stream_get_owner (stream);
return stream_truncate (ts->stream, len);
}
static int
_trans_size (stream_t stream, off_t *psize)
{
struct _trans_stream *ts = stream_get_owner(stream);
return stream_size(ts->stream, psize);
struct _trans_stream *ts = stream_get_owner (stream);
return stream_size (ts->stream, psize);
}
static int
_trans_flush (stream_t stream)
{
struct _trans_stream *ts = stream_get_owner(stream);
return stream_flush(ts->stream);
struct _trans_stream *ts = stream_get_owner(stream);
return stream_flush (ts->stream);
}
static int
_trans_get_fd (stream_t stream, int *pfd)
{
struct _trans_stream *ts = stream_get_owner(stream);
return stream_get_fd(ts->stream, pfd);
struct _trans_stream *ts = stream_get_owner (stream);
return stream_get_fd (ts->stream, pfd);
}
static int
_trans_close (stream_t stream)
{
struct _trans_stream *ts = stream_get_owner(stream);
return stream_close(ts->stream);
struct _trans_stream *ts = stream_get_owner (stream);
return stream_close (ts->stream);
}
/*------------------------------------------------------
......@@ -223,93 +237,109 @@ _trans_close (stream_t stream)
*----------------------------------------------------*/
static int
_b64_input(char c)
_b64_input (char c)
{
const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int i;
for (i = 0; i < 64; i++) {
if (table[i] == c)
return i;
}
return -1;
const char table[64] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int i;
for (i = 0; i < 64; i++)
{
if (table[i] == c)
return i;
}
return -1;
}
static int
_base64_init(struct _trans_stream *ts, int type)
_base64_init (struct _trans_stream *ts, int type)
{
ts->min_size = 4;
if ( ( ts->s_buf = malloc(4) ) == NULL )
return ENOMEM;
return 0;
ts->min_size = 4;
ts->s_buf = calloc (4, 1);
if (ts->s_buf == NULL)
return ENOMEM;
return 0;
}
static int
_base64_decode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len)
_base64_decode (const char *iptr, size_t isize, char *optr, size_t osize,
size_t *nbytes, int *line_len)
{
int i = 0, tmp = 0, pad = 0;
size_t consumed = 0;
char data[4];
*nbytes = 0;
while ( consumed < isize && (*nbytes)+3 < osize ) {
while ( ( i < 4 ) && ( consumed < isize ) ) {
tmp = _b64_input(*iptr++);
consumed++;
if ( tmp != -1 )
data[i++] = tmp;
else if ( *(iptr-1) == '=' ) {
data[i++] = '\0';
pad++;
}
}
if ( i == 4 ) { // I have a entire block of data 32 bits
// get the output data
*optr++ = ( data[0] << 2 ) | ( ( data[1] & 0x30 ) >> 4 );
*optr++ = ( ( data[1] & 0xf ) << 4 ) | ( ( data[2] & 0x3c ) >> 2 );
*optr++ = ( ( data[2] & 0x3 ) << 6 ) | data[3];
(*nbytes) += 3 - pad;
}
else // I did not get all the data
{
consumed -= i;
return consumed;
}
i = 0;
int i = 0, tmp = 0, pad = 0;
size_t consumed = 0;
char data[4];
*nbytes = 0;
while (consumed < isize && (*nbytes)+3 < osize)
{
while (( i < 4 ) && (consumed < isize))
{
tmp = _b64_input (*iptr++);
consumed++;
if (tmp != -1)
data[i++] = tmp;
else if (*(iptr-1) == '=')
{
data[i++] = '\0';
pad++;
}
}
/* I have a entire block of data 32 bits get the output data. */
if (i == 4)
{
*optr++ = (data[0] << 2) | ((data[1] & 0x30) >> 4);
*optr++ = ((data[1] & 0xf) << 4) | ((data[2] & 0x3c) >> 2);
*optr++ = ((data[2] & 0x3) << 6) | data[3];
(*nbytes) += 3 - pad;
}
return consumed;
else
{
/* I did not get all the data. */
consumed -= i;
return consumed;
}
i = 0;
}
return consumed;
}
#define BASE64_LINE_MAX 77
static int
_base64_encode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len)
_base64_encode (const char *iptr, size_t isize, char *optr, size_t osize,
size_t *nbytes, int *line_len)
{
size_t consumed = 0;
int pad = 0;
const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
*nbytes = 0;
if ( isize <= 3 )
pad = 1;
while ( ( ( consumed + 3 ) <= isize && ( *nbytes + 4 ) <= osize ) || pad ) {
if (*line_len == 76 ) {
*optr++ = '\n';
(*nbytes)++;
(*line_len) = 0;
if ( (*nbytes + 4 ) > osize )
return consumed;
}
*optr++ = b64[iptr[0] >> 2];
*optr++ = b64[((iptr[0] << 4) + (--isize ? (iptr[1] >> 4): 0)) & 0x3f];
*optr++ = isize ? b64[((iptr[1] << 2) + (--isize ? (iptr[2] >> 6) : 0 )) & 0x3f] : '=';
*optr++ = isize ? b64[iptr[2] & 0x3f] : '=';
iptr += 3;
consumed += 3;
(*nbytes) += 4;
(*line_len) +=4;
pad = 0;
size_t consumed = 0;
int pad = 0;
const char *b64 =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
*nbytes = 0;
if (isize <= 3)
pad = 1;
while (((consumed + 3) <= isize && (*nbytes + 4) <= osize) || pad)
{
if (*line_len == 76)
{
*optr++ = '\n';
(*nbytes)++;
(*line_len) = 0;
if ((*nbytes + 4) > osize)
return consumed;
}
return consumed;
*optr++ = b64[iptr[0] >> 2];
*optr++ = b64[((iptr[0] << 4) + (--isize ? (iptr[1] >> 4): 0)) & 0x3f];
*optr++ = isize ?
b64[((iptr[1] << 2) + (--isize ? (iptr[2] >> 6) : 0 )) & 0x3f]
: '=';
*optr++ = isize ? b64[iptr[2] & 0x3f] : '=';
iptr += 3;
consumed += 3;
(*nbytes) += 4;
(*line_len) +=4;
pad = 0;
}
return consumed;
}
/*------------------------------------------------------
......@@ -318,214 +348,255 @@ _base64_encode(const char *iptr, size_t isize, char *optr, size_t osize, size_t
static const char _hexdigits[16] = "0123456789ABCDEF";
static int
_qp_init(struct _trans_stream *ts, int type)
_qp_init (struct _trans_stream *ts, int type)
{
ts->min_size = 4;
if ( ( ts->s_buf = malloc(4) ) == NULL )
return ENOMEM;
return 0;
}
#if 0
static int
_ishex(int c)
{
int i;
if (c == '\n')
return 0;
for (i = 0; i < 16; i++)
if (c == _hexdigits[i])
return 1;
return 0;
ts->min_size = 4;
ts->s_buf = calloc (4, 1);
if (ts->s_buf == NULL)
return ENOMEM;
return 0;
}
#endif
static int
_qp_decode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len)
_qp_decode (const char *iptr, size_t isize, char *optr, size_t osize,
size_t *nbytes, int *line_len)
{
char c;
int last_char = 0;
size_t consumed = 0;
*nbytes = 0;
while (consumed < isize && *nbytes < osize ) {
c = *iptr++;
if (c == '=') {
// there must be 2 more characters before I consume this
if ((consumed + 2) >= isize)
return consumed;
else {
// you get =XX where XX are hex characters
char chr[2];
int new_c;
chr[0] = *iptr++;
if (chr[0] != '\n') { // ignore LF
chr[1] = *iptr++;
new_c = strtoul(chr, NULL, 16);
*optr++ = new_c;
(*nbytes)++;
consumed += 3;
}
else
consumed += 2;
}
}
else if (c == '\r') { // CR character
// there must be at least 1 more character before I consume this
if ((consumed + 1) >= isize )
return (consumed);
else {
iptr++; // skip the CR character
*optr++ = '\n';
(*nbytes)++;
consumed += 2;
}
}
else if ((c == 9) || (c == 32)) {
if ((last_char == 9) || (last_char == 32))
consumed++;
else {
*optr++ = c;
(*nbytes)++;
consumed++;
}
}
else {
*optr++ = c;
(*nbytes)++;
consumed++;
char c;
int last_char = 0;
size_t consumed = 0;
*nbytes = 0;
while (consumed < isize && *nbytes < osize)
{
c = *iptr++;
if (c == '=')
{
/* There must be 2 more characters before I consume this. */
if ((consumed + 2) >= isize)
return consumed;
else
{
/* you get =XX where XX are hex characters. */
char chr[2];
int new_c;
chr[0] = *iptr++;
/* Ignore LF. */
if (chr[0] != '\n')
{
chr[1] = *iptr++;
new_c = strtoul (chr, NULL, 16);
*optr++ = new_c;
(*nbytes)++;
consumed += 3;
}
last_char = c;
else
consumed += 2;
}
}
return consumed;
/* CR character. */
else if (c == '\r')
{
/* There must be at least 1 more character before I consume this. */
if ((consumed + 1) >= isize )
return (consumed);
else
{
iptr++; /* Skip the CR character. */
*optr++ = '\n';
(*nbytes)++;
consumed += 2;
}
}
else if ((c == 9) || (c == 32))
{
if ((last_char == 9) || (last_char == 32))
consumed++;
else
{
*optr++ = c;
(*nbytes)++;
consumed++;
}
}
else
{
*optr++ = c;
(*nbytes)++;
consumed++;
}
last_char = c;
}
return consumed;
}
static int
_qp_encode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len)
_qp_encode (const char *iptr, size_t isize, char *optr, size_t osize,
size_t *nbytes, int *line_len)
{
#define QP_LINE_MAX 76
int c;
size_t consumed = 0;
*nbytes = 0;
while (consumed < isize && (*nbytes + 4) < isize) {
if (*line_len == QP_LINE_MAX) {
*optr++ = '=';
*optr++ = '\n';
(*nbytes) += 2;
*line_len = 0;
}
int c;
size_t consumed = 0;
*nbytes = 0;
while (consumed < isize && (*nbytes + 4) < isize)
{
if (*line_len == QP_LINE_MAX)
{
*optr++ = '=';
*optr++ = '\n';
(*nbytes) += 2;
*line_len = 0;
}
c = *iptr++;
consumed++;
if ( ((c >= 32) && (c <= 60)) || ((c >= 62) && (c <= 126)) || (c == 9)) {
*optr++ = c;
(*nbytes)++;
(*line_len)++;
}
else {
if (*line_len >= (QP_LINE_MAX - 3)) {
// add spaces
while (*line_len < QP_LINE_MAX) {
*optr++ = ' ';
(*nbytes)++;
(*line_len)++;
}
consumed--;
iptr--;
}
else {
*optr++ = '=';
*optr++ = _hexdigits[c & 0xf];
*optr++ = _hexdigits[(c/16) & 0xf];
(*nbytes) += 3;
(*line_len) += 3;
}
c = *iptr++;
consumed++;
if (((c >= 32) && (c <= 60)) || ((c >= 62) && (c <= 126)) || (c == 9))
{
*optr++ = c;
(*nbytes)++;
(*line_len)++;
}
else
{
if (*line_len >= (QP_LINE_MAX - 3))
{
/* add spaces. */
while (*line_len < QP_LINE_MAX)
{
*optr++ = ' ';
(*nbytes)++;
(*line_len)++;
}
consumed--;
iptr--;
}
else
{
*optr++ = '=';
*optr++ = _hexdigits[c & 0xf];
*optr++ = _hexdigits[(c/16) & 0xf];
(*nbytes) += 3;
(*line_len) += 3;
}
}
return consumed;
}
return consumed;
}
int
encoder_stream_create(stream_t *stream, stream_t iostream, const char *encoding)
encoder_stream_create (stream_t *stream, stream_t iostream,
const char *encoding)
{
struct _trans_stream *ts;
int i, ret;
if ( stream == NULL || iostream == NULL || encoding == NULL )
return EINVAL;
if ( ( ts = calloc(sizeof(struct _trans_stream), 1) ) == NULL )
return ENOMEM;
for( i = 0; i < NUM_TRANSCODERS; i++ ) {
if ( strcasecmp( encoding, tslist[i].encoding ) == 0 )
break;
}
if ( i == NUM_TRANSCODERS )
return ENOTSUP;
if ( ( ret = stream_create(stream, MU_STREAM_RDWR |MU_STREAM_NO_CHECK, ts) ) != 0 )
return ret;
ts->transcoder = tslist[i]._encode;
/* pass thur */
stream_set_open(*stream, _trans_open, ts );
stream_set_close(*stream, _trans_close, ts );
stream_set_fd(*stream, _trans_get_fd, ts );
stream_set_truncate(*stream, _trans_truncate, ts );
stream_set_size(*stream, _trans_size, ts );
stream_set_flush(*stream, _trans_flush, ts );
ts->stream = iostream;
if ( tslist[i]._init != NULL && (ret = tslist[i]._init(ts, MU_TRANS_ENCODE)) != 0 )
stream_destroy(stream, NULL);
else {
stream_set_read(*stream, _trans_read, ts );
stream_set_write(*stream, _trans_write, ts );
stream_set_destroy(*stream, _trans_destroy, ts );
struct _trans_stream *ts;
int i, ret;
int NUM_TRANSCODERS = sizeof (tslist)/sizeof (*tslist);
if (stream == NULL || iostream == NULL || encoding == NULL)
return EINVAL;
ts = calloc (sizeof (struct _trans_stream), 1);
if (ts == NULL)
return ENOMEM;
for (i = 0; i < NUM_TRANSCODERS; i++)
{
if (strcasecmp (encoding, tslist[i].encoding) == 0)
break;
}
if (i == NUM_TRANSCODERS)
{
free (ts);
return ENOTSUP;
}
if (tslist[i]._init != NULL)
{
ret = tslist[i]._init (ts, MU_TRANS_ENCODE);
if (ret != 0)
{
free (ts);
return ret;
}
return ret;
}
ret = stream_create (stream, MU_STREAM_RDWR | MU_STREAM_NO_CHECK, ts);
if (ret != 0)
{
free (ts);
return ret;
}
ts->transcoder = tslist[i]._encode;
ts->stream = iostream;
stream_set_open (*stream, _trans_open, ts);
stream_set_close (*stream, _trans_close, ts);
stream_set_fd (*stream, _trans_get_fd, ts);
stream_set_truncate (*stream, _trans_truncate, ts);
stream_set_size (*stream, _trans_size, ts);
stream_set_flush (*stream, _trans_flush, ts);
stream_set_read (*stream, _trans_read, ts);
stream_set_write (*stream, _trans_write, ts);
stream_set_destroy (*stream, _trans_destroy, ts);
return ret;
}
int
decoder_stream_create(stream_t *stream, stream_t iostream, const char *encoding)
decoder_stream_create (stream_t *stream, stream_t iostream,
const char *encoding)
{
struct _trans_stream *ts;
int i, ret;
if ( stream == NULL || iostream == NULL || encoding == NULL )
return EINVAL;
if ( ( ts = calloc(sizeof(struct _trans_stream), 1) ) == NULL )
return ENOMEM;
for( i = 0; i < NUM_TRANSCODERS; i++ ) {
if ( strcasecmp( encoding, tslist[i].encoding ) == 0 )
break;
}
if ( i == NUM_TRANSCODERS )
return ENOTSUP;
if ( ( ret = stream_create(stream, MU_STREAM_RDWR |MU_STREAM_NO_CHECK, ts) ) != 0 )
return ret;
ts->transcoder = tslist[i]._decode;
/* pass thur */
stream_set_open(*stream, _trans_open, ts );
stream_set_close(*stream, _trans_close, ts );
stream_set_fd(*stream, _trans_get_fd, ts );
stream_set_truncate(*stream, _trans_truncate, ts );
stream_set_size(*stream, _trans_size, ts );
stream_set_flush(*stream, _trans_flush, ts );
ts->stream = iostream;
if ( tslist[i]._init != NULL && (ret = tslist[i]._init(ts, MU_TRANS_DECODE)) != 0 )
stream_destroy(stream, NULL);
else {
stream_set_read(*stream, _trans_read, ts );
stream_set_write(*stream, _trans_write, ts );
stream_set_destroy(*stream, _trans_destroy, ts );
struct _trans_stream *ts;
int i, ret;
int NUM_TRANSCODERS = sizeof (tslist)/sizeof (*tslist);
if (stream == NULL || iostream == NULL || encoding == NULL)
return EINVAL;
ts = calloc (sizeof (struct _trans_stream), 1);
if (ts == NULL )
return ENOMEM;
for (i = 0; i < NUM_TRANSCODERS; i++)
{
if (strcasecmp (encoding, tslist[i].encoding) == 0)
break;
}
if (i == NUM_TRANSCODERS)
{
free (ts);
return ENOTSUP;
}
if (tslist[i]._init != NULL)
{
ret = tslist[i]._init (ts, MU_TRANS_DECODE);
if (ret != 0)
{
free (ts);
return ret;
}
return ret;
}
ret = stream_create (stream, MU_STREAM_RDWR | MU_STREAM_NO_CHECK, ts);
if (ret != 0)
{
free (ts);
return ret;
}
ts->transcoder = tslist[i]._decode;
ts->stream = iostream;
stream_set_open (*stream, _trans_open, ts );
stream_set_close (*stream, _trans_close, ts );
stream_set_fd (*stream, _trans_get_fd, ts );
stream_set_truncate (*stream, _trans_truncate, ts );
stream_set_size (*stream, _trans_size, ts );
stream_set_flush (*stream, _trans_flush, ts );
stream_set_read (*stream, _trans_read, ts);
stream_set_write (*stream, _trans_write, ts);
stream_set_destroy (*stream, _trans_destroy, ts);
return ret;
}
......