Commit 95b548f1 95b548f15ffef626acdb00811ecd746856812fc1 by Alain Magloire

Use the iterator_t instead of a list.

1 parent 94ae43f4
......@@ -37,6 +37,7 @@ libmu_nntp_la_SOURCES = \
nntp_head.c \
nntp_help.c \
nntp_ihave.c \
nntp_iterator.c \
nntp_last.c \
nntp_list_active.c \
nntp_list_distribpats.c \
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 2004 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. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <mailutils/sys/nntp.h>
static int nntp_itr_dup (void **ptr, void *owner);
static int nntp_itr_destroy (iterator_t itr, void *owner);
static int nntp_itr_first (void *owner);
static int nntp_itr_next (void *woner);
static int nntp_itr_getitem (void *owner, void **pret);
static int nntp_itr_curitem_p (void *owner, void *data);
static int nntp_itr_finished_p (void *owner);
struct nntp_iterator
{
mu_nntp_t nntp;
int done;
char *item;
};
int
mu_nntp_iterator_create (mu_nntp_t nntp, iterator_t *piterator)
{
struct nntp_iterator *nntp_iterator;
iterator_t iterator;
int status;
nntp_iterator = malloc (sizeof *nntp_iterator);
if (nntp_iterator == NULL)
return ENOMEM;
nntp_iterator->item = NULL;
nntp_iterator->done = 0;
nntp_iterator->nntp= nntp;
status = iterator_create (&iterator, nntp_iterator);
if (status != 0)
{
free (nntp_iterator);
return status;
}
iterator_set_first (iterator, nntp_itr_first);
iterator_set_next (iterator, nntp_itr_next);
iterator_set_getitem (iterator, nntp_itr_getitem);
iterator_set_finished_p (iterator, nntp_itr_finished_p);
iterator_set_curitem_p (iterator, nntp_itr_curitem_p);
iterator_set_destroy (iterator, nntp_itr_destroy);
iterator_set_dup (iterator, nntp_itr_dup);
*piterator = iterator;
return 0;
}
static int
nntp_itr_dup (void **ptr, void *owner)
{
struct nntp_iterator *nntp_iterator = (struct nntp_iterator *)owner;
struct nntp_iterator *clone = malloc (sizeof *nntp_iterator);
if (clone == NULL)
return ENOMEM;
/* let the assignement operator copy the elements. */
*clone = *nntp_iterator;
*ptr = clone;
return 0;
}
static int
nntp_itr_destroy (iterator_t iterator, void *owner)
{
struct nntp_iterator *nntp_iterator = (struct nntp_iterator *)owner;
/* Delicate situation if they did not finish to drain the result
We take te approach to do it for the user. FIXME: Not sure
if this is the rigth thing to do. The other way is to close the stream */
if (!nntp_iterator->done)
{
char buf[128];
size_t n = 0;
while (mu_nntp_readline (nntp_iterator->nntp, buf, sizeof buf, &n) > 0 && n > 0)
n = 0;
}
if (nntp_iterator->item)
free (nntp_iterator->item);
nntp_iterator->nntp->state = MU_NNTP_NO_STATE;
free (nntp_iterator);
return 0;
}
static int
nntp_itr_first (void *data)
{
return nntp_itr_next (data);
}
static int
nntp_itr_next (void *owner)
{
struct nntp_iterator *nntp_iterator = (struct nntp_iterator *)owner;
size_t n = 0;
int status = 0;
if (!nntp_iterator->done)
{
/* The first readline will not consume the buffer, we just need to
know how much to read. */
status = mu_nntp_readline (nntp_iterator->nntp, NULL, 0, &n);
if (status == 0)
{
if (n)
{
char *buf;
buf = calloc (n + 1, 1);
if (buf)
{
/* Consume. */
mu_nntp_readline (nntp_iterator->nntp, buf, n + 1, NULL);
if (buf[n - 1] == '\n')
buf[n - 1] = '\0';
if (nntp_iterator->item)
free (nntp_iterator->item);
nntp_iterator->item = buf;
}
else
status = ENOMEM;
}
else
{
nntp_iterator->done = 1;
nntp_iterator->nntp->state = MU_NNTP_NO_STATE;
}
}
}
return status;
}
static int
nntp_itr_getitem (void *owner, void **item)
{
struct nntp_iterator *nntp_iterator = (struct nntp_iterator *)owner;
if (item)
{
*((char **)item) = nntp_iterator->item;
nntp_iterator->item = NULL;
}
return 0;
}
static int
nntp_itr_finished_p (void *owner)
{
struct nntp_iterator *nntp_iterator = (struct nntp_iterator *)owner;
return nntp_iterator->done;
}
static int
nntp_itr_curitem_p (void *owner, void *item)
{
struct nntp_iterator *nntp_iterator = (struct nntp_iterator *)owner;
return *((char **)item) == nntp_iterator->item;
}
......@@ -28,17 +28,17 @@
#include <mailutils/sys/nntp.h>
/*
LIST EXTENSIONS command, return a list that contains the result.
It is the responsability of the caller to destroy the list(list_destroy).
LIST EXTENSIONS command, return a iterator that contains the result.
It is the responsability of the caller to destroy the iterator(iterator_destroy).
*/
int
mu_nntp_list_active (mu_nntp_t nntp, const char *wildmat, list_t *plist)
mu_nntp_list_active (mu_nntp_t nntp, const char *wildmat, iterator_t *piterator)
{
int status;
int status = 0;
if (nntp == NULL)
return EINVAL;
if (plist == NULL)
if (piterator == NULL)
return MU_ERR_OUT_PTR_NULL;
switch (nntp->state)
......@@ -63,41 +63,12 @@ mu_nntp_list_active (mu_nntp_t nntp, const char *wildmat, list_t *plist)
MU_NNTP_CHECK_EAGAIN (nntp, status);
mu_nntp_debug_ack (nntp);
MU_NNTP_CHECK_CODE (nntp, MU_NNTP_RESP_CODE_LIST_FOLLOW);
status = list_create (plist);
status = mu_nntp_iterator_create (nntp, piterator);
MU_NNTP_CHECK_ERROR(nntp, status);
list_set_destroy_item(*plist, free);
nntp->state = MU_NNTP_LIST_ACTIVE_RX;
case MU_NNTP_LIST_ACTIVE_RX:
{
/* line is 512 octets maximum according to RFC. */
char *active;
size_t n = 0;
active = malloc (512);
if (active == NULL)
{
/* MU_NNTP_CHECK_ERROR(nntp, ENOMEM);
We need to destroy the list if error. */
nntp->io.ptr = nntp->io.buf;
nntp->state = MU_NNTP_ERROR;
list_destroy (*plist);
return ENOMEM;
}
while ((status = mu_nntp_readline (nntp, active, 512, &n)) == 0 && n > 0)
{
/* Nuke the trailing newline */
if (active[n - 1] == '\n')
active[n - 1] = '\0';
/* add to the list. */
list_append (*plist, strdup (active));
n = 0;
}
free (active);
MU_NNTP_CHECK_EAGAIN (nntp, status);
nntp->state = MU_NNTP_NO_STATE;
break;
}
/* They must deal with the error first by reopening. */
case MU_NNTP_ERROR:
......
......@@ -28,17 +28,17 @@
#include <mailutils/sys/nntp.h>
/*
LIST xxxx command, return a list that contains the result.
It is the responsability of the caller to destroy the list(list_destroy).
LIST xxxx command, return an iterator that contains the result.
It is the responsability of the caller to destroy the iterator(iterator_destroy).
*/
int
mu_nntp_list_distrib_pats (mu_nntp_t nntp, list_t *plist)
mu_nntp_list_distrib_pats (mu_nntp_t nntp, iterator_t *piterator)
{
int status;
int status = 0;
if (nntp == NULL)
return EINVAL;
if (plist == NULL)
if (piterator == NULL)
return MU_ERR_OUT_PTR_NULL;
switch (nntp->state)
......@@ -60,41 +60,12 @@ mu_nntp_list_distrib_pats (mu_nntp_t nntp, list_t *plist)
MU_NNTP_CHECK_EAGAIN (nntp, status);
mu_nntp_debug_ack (nntp);
MU_NNTP_CHECK_CODE (nntp, MU_NNTP_RESP_CODE_LIST_FOLLOW);
status = list_create (plist);
status = mu_nntp_iterator_create (nntp, piterator);
MU_NNTP_CHECK_ERROR(nntp, status);
list_set_destroy_item(*plist, free);
nntp->state = MU_NNTP_LIST_DISTRIB_PATS_RX;
case MU_NNTP_LIST_DISTRIB_PATS_RX:
{
/* line are 512 octets maximum according to RFC. */
char *distributions;
size_t n = 0;
distributions = malloc (512);
if (distributions == NULL)
{
/* MU_NNTP_CHECK_ERROR(nntp, ENOMEM);
We need to destroy the list if error. */
nntp->io.ptr = nntp->io.buf;
nntp->state = MU_NNTP_ERROR;
list_destroy (*plist);
return ENOMEM;
}
while ((status = mu_nntp_readline (nntp, distributions, 512, &n)) == 0 && n > 0)
{
/* Nuke the trailing newline */
if (distributions[n - 1] == '\n')
distributions[n - 1] = '\0';
/* add to the list. */
list_append (*plist, strdup (distributions));
n = 0;
}
free (distributions);
MU_NNTP_CHECK_EAGAIN (nntp, status);
nntp->state = MU_NNTP_NO_STATE;
break;
}
/* They must deal with the error first by reopening. */
case MU_NNTP_ERROR:
......
......@@ -28,17 +28,17 @@
#include <mailutils/sys/nntp.h>
/*
LIST xxxx command, return a list that contains the result.
It is the responsability of the caller to destroy the list(list_destroy).
LIST xxxx command, return an iterator that contains the result.
It is the responsability of the caller to destroy the iterator(iterator_destroy).
*/
int
mu_nntp_list_distributions (mu_nntp_t nntp, const char *wildmat, list_t *plist)
mu_nntp_list_distributions (mu_nntp_t nntp, const char *wildmat, iterator_t *piterator)
{
int status;
int status = 0;
if (nntp == NULL)
return EINVAL;
if (plist == NULL)
if (piterator == NULL)
return MU_ERR_OUT_PTR_NULL;
switch (nntp->state)
......@@ -63,41 +63,12 @@ mu_nntp_list_distributions (mu_nntp_t nntp, const char *wildmat, list_t *plist)
MU_NNTP_CHECK_EAGAIN (nntp, status);
mu_nntp_debug_ack (nntp);
MU_NNTP_CHECK_CODE (nntp, MU_NNTP_RESP_CODE_LIST_FOLLOW);
status = list_create (plist);
status = mu_nntp_iterator_create (nntp, piterator);
MU_NNTP_CHECK_ERROR(nntp, status);
list_set_destroy_item(*plist, free);
nntp->state = MU_NNTP_LIST_DISTRIBUTIONS_RX;
case MU_NNTP_LIST_DISTRIBUTIONS_RX:
{
/* line are 512 octets maximum according to RFC. */
char *distributions;
size_t n = 0;
distributions = malloc (512);
if (distributions == NULL)
{
/* MU_NNTP_CHECK_ERROR(nntp, ENOMEM);
We need to destroy the list if error. */
nntp->io.ptr = nntp->io.buf;
nntp->state = MU_NNTP_ERROR;
list_destroy (*plist);
return ENOMEM;
}
while ((status = mu_nntp_readline (nntp, distributions, 512, &n)) == 0 && n > 0)
{
/* Nuke the trailing newline */
if (distributions[n - 1] == '\n')
distributions[n - 1] = '\0';
/* add to the list. */
list_append (*plist, strdup (distributions));
n = 0;
}
free (distributions);
MU_NNTP_CHECK_EAGAIN (nntp, status);
nntp->state = MU_NNTP_NO_STATE;
break;
}
/* They must deal with the error first by reopening. */
case MU_NNTP_ERROR:
......
......@@ -28,17 +28,17 @@
#include <mailutils/sys/nntp.h>
/*
LIST EXTENSIONS command, return a list that contains the result.
It is the responsability of the caller to destroy the list(list_destroy).
LIST EXTENSIONS command, return an iterator that contains the result.
It is the responsability of the caller to destroy the iterator(iterator_destroy).
*/
int
mu_nntp_list_extensions (mu_nntp_t nntp, list_t *plist)
mu_nntp_list_extensions (mu_nntp_t nntp, iterator_t *piterator)
{
int status;
int status = 0;
if (nntp == NULL)
return EINVAL;
if (plist == NULL)
if (piterator == NULL)
return MU_ERR_OUT_PTR_NULL;
switch (nntp->state)
......@@ -60,42 +60,12 @@ mu_nntp_list_extensions (mu_nntp_t nntp, list_t *plist)
MU_NNTP_CHECK_EAGAIN (nntp, status);
mu_nntp_debug_ack (nntp);
MU_NNTP_CHECK_CODE (nntp, MU_NNTP_RESP_CODE_EXTENSIONS_FOLLOW);
status = list_create (plist);
status = mu_nntp_iterator_create (nntp, piterator);
MU_NNTP_CHECK_ERROR(nntp, status);
list_set_destroy_item(*plist, free);
nntp->state = MU_NNTP_LIST_EXTENSIONS_RX;
case MU_NNTP_LIST_EXTENSIONS_RX:
{
/* CAPA line are 512 octets maximum according to RFC 2449.
But do not use the stack and malloc. */
char *capability;
size_t n = 0;
capability = malloc (512);
if (capability == NULL)
{
/* MU_NNTP_CHECK_ERROR(nntp, ENOMEM);
We need to destroy the list if error. */
nntp->io.ptr = nntp->io.buf;
nntp->state = MU_NNTP_ERROR;
list_destroy (*plist);
return ENOMEM;
}
while ((status = mu_nntp_readline (nntp, capability, 512, &n)) == 0 && n > 0)
{
/* Nuke the trailing newline */
if (capability[n - 1] == '\n')
capability[n - 1] = '\0';
/* add to the list. */
list_append (*plist, strdup (capability));
n = 0;
}
free (capability);
MU_NNTP_CHECK_EAGAIN (nntp, status);
nntp->state = MU_NNTP_NO_STATE;
break;
}
/* They must deal with the error first by reopening. */
case MU_NNTP_ERROR:
......
......@@ -28,17 +28,17 @@
#include <mailutils/sys/nntp.h>
/*
LIST NEWSGROUPS command, return a list that contains the result.
It is the responsability of the caller to destroy the list(list_destroy).
LIST NEWSGROUPS command, return an iterator that contains the result.
It is the responsability of the caller to destroy the iterator(iterator_destroy).
*/
int
mu_nntp_list_newsgroups (mu_nntp_t nntp, const char *wildmat, list_t *plist)
mu_nntp_list_newsgroups (mu_nntp_t nntp, const char *wildmat, iterator_t *piterator)
{
int status;
int status = 0;
if (nntp == NULL)
return EINVAL;
if (plist == NULL)
if (piterator == NULL)
return MU_ERR_OUT_PTR_NULL;
switch (nntp->state)
......@@ -63,41 +63,12 @@ mu_nntp_list_newsgroups (mu_nntp_t nntp, const char *wildmat, list_t *plist)
MU_NNTP_CHECK_EAGAIN (nntp, status);
mu_nntp_debug_ack (nntp);
MU_NNTP_CHECK_CODE (nntp, MU_NNTP_RESP_CODE_LIST_FOLLOW);
status = list_create (plist);
status = mu_nntp_iterator_create (nntp, piterator);
MU_NNTP_CHECK_ERROR(nntp, status);
list_set_destroy_item(*plist, free);
nntp->state = MU_NNTP_LIST_NEWSGROUPS_RX;
case MU_NNTP_LIST_NEWSGROUPS_RX:
{
/* line are 512 octets maximum according to RFC. */
char *newsgroups;
size_t n = 0;
newsgroups = malloc (512);
if (newsgroups == NULL)
{
/* MU_NNTP_CHECK_ERROR(nntp, ENOMEM);
We need to destroy the list if error. */
nntp->io.ptr = nntp->io.buf;
nntp->state = MU_NNTP_ERROR;
list_destroy (*plist);
return ENOMEM;
}
while ((status = mu_nntp_readline (nntp, newsgroups, 512, &n)) == 0 && n > 0)
{
/* Nuke the trailing newline */
if (newsgroups[n - 1] == '\n')
newsgroups[n - 1] = '\0';
/* add to the list. */
list_append (*plist, strdup (newsgroups));
n = 0;
}
free (newsgroups);
MU_NNTP_CHECK_EAGAIN (nntp, status);
nntp->state = MU_NNTP_NO_STATE;
break;
}
/* They must deal with the error first by reopening. */
case MU_NNTP_ERROR:
......
......@@ -28,17 +28,17 @@
#include <mailutils/sys/nntp.h>
/*
LIST EXTENSIONS command, return a list that contains the result.
It is the responsability of the caller to destroy the list(list_destroy).
LIST EXTENSIONS command, return an iterator that contains the result.
It is the responsability of the caller to destroy the iterator(iterator_destroy).
*/
int
mu_nntp_list_active_times (mu_nntp_t nntp, const char *wildmat, list_t *plist)
mu_nntp_list_active_times (mu_nntp_t nntp, const char *wildmat, iterator_t *piterator)
{
int status;
int status = 0;
if (nntp == NULL)
return EINVAL;
if (plist == NULL)
if (piterator == NULL)
return MU_ERR_OUT_PTR_NULL;
switch (nntp->state)
......@@ -63,41 +63,12 @@ mu_nntp_list_active_times (mu_nntp_t nntp, const char *wildmat, list_t *plist)
MU_NNTP_CHECK_EAGAIN (nntp, status);
mu_nntp_debug_ack (nntp);
MU_NNTP_CHECK_CODE (nntp, MU_NNTP_RESP_CODE_LIST_FOLLOW);
status = list_create (plist);
status = mu_nntp_iterator_create (nntp, piterator);
MU_NNTP_CHECK_ERROR(nntp, status);
list_set_destroy_item(*plist, free);
nntp->state = MU_NNTP_LIST_ACTIVE_TIMES_RX;
case MU_NNTP_LIST_ACTIVE_TIMES_RX:
{
/* line are 512 octets maximum according to RFC. */
char *active;
size_t n = 0;
active = malloc (512);
if (active == NULL)
{
/* MU_NNTP_CHECK_ERROR(nntp, ENOMEM);
We need to destroy the list if error. */
nntp->io.ptr = nntp->io.buf;
nntp->state = MU_NNTP_ERROR;
list_destroy (*plist);
return ENOMEM;
}
while ((status = mu_nntp_readline (nntp, active, 512, &n)) == 0 && n > 0)
{
/* Nuke the trailing newline */
if (active[n - 1] == '\n')
active[n - 1] = '\0';
/* add to the list. */
list_append (*plist, strdup (active));
n = 0;
}
free (active);
MU_NNTP_CHECK_EAGAIN (nntp, status);
nntp->state = MU_NNTP_NO_STATE;
break;
}
/* They must deal with the error first by reopening. */
case MU_NNTP_ERROR:
......
......@@ -26,9 +26,9 @@
int
mu_nntp_newgroups (mu_nntp_t nntp, unsigned int year, unsigned int month, unsigned int day,
unsigned int hour, unsigned int minute, unsigned int second, int is_gmt, list_t *plist)
unsigned int hour, unsigned int minute, unsigned int second, int is_gmt, iterator_t *piterator)
{
int status;
int status = 0;
if (nntp == NULL)
return EINVAL;
......@@ -56,42 +56,12 @@ mu_nntp_newgroups (mu_nntp_t nntp, unsigned int year, unsigned int month, unsign
mu_nntp_debug_ack (nntp);
MU_NNTP_CHECK_CODE (nntp, MU_NNTP_RESP_CODE_NEWGROUPS_FOLLOW);
status = list_create (plist);
status = mu_nntp_iterator_create (nntp, piterator);
MU_NNTP_CHECK_ERROR(nntp, status);
list_set_destroy_item(*plist, free);
nntp->state = MU_NNTP_NEWGROUPS_RX;
case MU_NNTP_NEWGROUPS_RX:
{
/* line should not be over 512 octets maximum. */
char *lista;
size_t n = 0;
lista = malloc (512);
if (lista == NULL)
{
/* MU_NNTP_CHECK_ERROR(nntp, ENOMEM);
Do not use the macro we need to clear the list if errors. */
nntp->io.ptr = nntp->io.buf;
nntp->state = MU_NNTP_ERROR;
list_destroy (plist);
return ENOMEM;
}
while ((status = mu_nntp_readline (nntp, lista, 512, &n)) == 0 && n > 0)
{
/* Nuke the trailing newline */
if (lista[n - 1] == '\n')
lista[n - 1] = '\0';
/* add to the list. */
list_append (*plist, strdup (lista));
n = 0;
}
free (lista);
MU_NNTP_CHECK_EAGAIN (nntp, status);
nntp->state = MU_NNTP_NO_STATE;
break;
}
/* They must deal with the error first by reopening. */
case MU_NNTP_ERROR:
......
......@@ -26,9 +26,9 @@
int
mu_nntp_newnews (mu_nntp_t nntp, const char *wildmat, unsigned int year, unsigned int month, unsigned int day,
unsigned int hour, unsigned int minute, unsigned int second, int is_gmt, list_t *plist)
unsigned int hour, unsigned int minute, unsigned int second, int is_gmt, iterator_t *piterator)
{
int status;
int status = 0;
if (nntp == NULL)
return EINVAL;
......@@ -72,42 +72,12 @@ mu_nntp_newnews (mu_nntp_t nntp, const char *wildmat, unsigned int year, unsigne
mu_nntp_debug_ack (nntp);
MU_NNTP_CHECK_CODE (nntp, MU_NNTP_RESP_CODE_NEWNEWS_FOLLOW);
status = list_create (plist);
status = mu_nntp_iterator_create (nntp, piterator);
MU_NNTP_CHECK_ERROR(nntp, status);
list_set_destroy_item(*plist, free);
nntp->state = MU_NNTP_NEWNEWS_RX;
case MU_NNTP_NEWNEWS_RX:
{
/* line should not be over 512 octets maximum. */
char *lista;
size_t n = 0;
lista = malloc (512);
if (lista == NULL)
{
/* MU_NNTP_CHECK_ERROR(nntp, ENOMEM);
Do not use the macro we need to clear the list if errors. */
nntp->io.ptr = nntp->io.buf;
nntp->state = MU_NNTP_ERROR;
list_destroy (plist);
return ENOMEM;
}
while ((status = mu_nntp_readline (nntp, lista, 512, &n)) == 0 && n > 0)
{
/* Nuke the trailing newline */
if (lista[n - 1] == '\n')
lista[n - 1] = '\0';
/* add to the list. */
list_append (*plist, strdup (lista));
n = 0;
}
free (lista);
MU_NNTP_CHECK_EAGAIN (nntp, status);
nntp->state = MU_NNTP_NO_STATE;
break;
}
/* They must deal with the error first by reopening. */
case MU_NNTP_ERROR:
......