pop3_iterator.c 4.21 KB
/* GNU Mailutils -- a suite of utilities for electronic mail
   Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.

   GNU Mailutils 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.

   GNU Mailutils 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 GNU Mailutils; 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 <mailutils/sys/pop3.h>

static int   p_ref     __P ((iterator_t));
static void  p_destroy __P ((iterator_t *));
static int   p_first   __P ((iterator_t));
static int   p_next    __P ((iterator_t));
static int   p_current __P ((iterator_t, void *));
static int   p_is_done __P ((iterator_t));

static struct _iterator_vtable p_i_vtable =
{
  /* Base.  */
  p_ref,
  p_destroy,

  p_first,
  p_next,
  p_current,
  p_is_done
};

int
pop3_iterator_create (pop3_t pop3, iterator_t *piterator)
{
  struct p_iterator *p_iterator;

  p_iterator = malloc (sizeof *p_iterator);
  if (p_iterator == NULL)
    return MU_ERROR_NO_MEMORY;

  mu_refcount_create (&p_iterator->refcount);
  if (p_iterator->refcount == NULL)
    {
      free (p_iterator);
      return MU_ERROR_NO_MEMORY;
    }
  p_iterator->item = NULL;
  p_iterator->done = 0;
  p_iterator->pop3= pop3;
  p_iterator->base.vtable = &p_i_vtable;
  *piterator = &p_iterator->base;
  return 0;
}

static int
p_ref (iterator_t iterator)
{
  struct p_iterator *p_iterator = (struct p_iterator *)iterator;
  return mu_refcount_inc (p_iterator->refcount);
}

static void
p_destroy (iterator_t *piterator)
{
  struct p_iterator *p_iterator = (struct p_iterator *)*piterator;
  if (mu_refcount_dec (p_iterator->refcount) == 0)
    {
      if (!p_iterator->done)
	{
	  char buf[128];
	  size_t n = 0;
	  while (pop3_readline (p_iterator->pop3, buf, sizeof buf, &n) > 0
		 && n > 0)
	    n = 0;
	}
      if (p_iterator->item)
	free (p_iterator->item);
      p_iterator->pop3->state = POP3_NO_STATE;
      mu_refcount_destroy (&p_iterator->refcount);
      free (p_iterator);
    }
}

static int
p_first  (iterator_t iterator)
{
  return p_next (iterator);
}

static int
p_next (iterator_t iterator)
{
  struct p_iterator *p_iterator = (struct p_iterator *)iterator;
  size_t n = 0;
  int status = 0;

  if (p_iterator)
    {
      mu_refcount_lock (p_iterator->refcount);
      if (!p_iterator->done)
	{
	  /* The first readline will not consume the buffer, we just need to
	     know how much to read.  */
	  status = pop3_readline (p_iterator->pop3, NULL, 0, &n);
	  if (status == 0)
	    {
	      if (n)
		{
		  char *buf;
		  buf = calloc (n + 1, 1);
		  if (buf)
		    {
		      /* Consume.  */
		      pop3_readline (p_iterator->pop3, buf, n + 1, NULL);
		      if (buf[n - 1] == '\n')
			buf[n - 1] = '\0';
		      if (p_iterator->item)
			free (p_iterator->item);
		      p_iterator->item = buf;
		    }
		  else
		    status = MU_ERROR_NO_MEMORY;
		}
	      else
		{
		  p_iterator->done = 1;
		  p_iterator->pop3->state = POP3_NO_STATE;
		}
	    }
	}
      mu_refcount_unlock (p_iterator->refcount);
    }
  return status;
}

static int
p_is_done (iterator_t iterator)
{
  struct p_iterator *p_iterator = (struct p_iterator *)iterator;
  int status = 1;
  if (p_iterator)
    {
      mu_refcount_lock (p_iterator->refcount);
      status = p_iterator->done;
      mu_refcount_unlock (p_iterator->refcount);
    }
  return status;
}

static int
p_current (iterator_t iterator, void *item)
{
  struct p_iterator *p_iterator = (struct p_iterator *)iterator;
  if (p_iterator)
    {
      mu_refcount_lock (p_iterator->refcount);
      if (item)
	{
	  *((char **)item) = p_iterator->item;
	  p_iterator->item = NULL;
	}
      mu_refcount_unlock (p_iterator->refcount);
    }
  return 0;
}