msglist.c 3.74 KB
/* 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 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 General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */

#include "readmsg.h"


static int
addset (int **set, int *n, unsigned val)
{
  int *tmp;
  tmp = realloc (*set, (*n + 1) * sizeof (**set));
  if (tmp == NULL)
    {
      if (*set)
        free (*set);
      *n = 0;
      *set = NULL;
      return ENOMEM;
    }
  *set = tmp;
  (*set)[*n] = val;
  (*n)++;
  return 0;
}

static int
is_number (const char *s)
{
  int result = 1;
  if (*s == '\0')
    result = 0;
  for (; *s; s++)
    {
      if (!isdigit ((unsigned char)*s))
	{
	  result = 0;
	  break;
	}
    }
  return result;
}

/*
  According to ELM readmsg(1):

  1.     A lone ``*'' means select all messages in the mailbox.

  2.     A list of message numbers may be specified.  Values of ``0'' and ``$'' in  the
  list both mean the last message in the mailbox.  For example:

  readmsg 1 3 0

  extracts  three messages from the folder:  the first, the third, and the last.

  3.     Finally, the selection may be some text to match.  This  will  select  a  mail
  message which exactly matches the specified text.  For example,

  readmsg staff meeting

  extracts the message which contains the words ``staff meeting.''  Note that it
  will not match a message containing ``Staff Meeting'' - the matching  is  case
  sensitive.   Normally only the first message which matches the pattern will be
  printed.  The -a option discussed in a moment changes this.
*/

int
msglist (mailbox_t mbox, int show_all, int argc, char **argv, int **set, int *n)
{
  int i = 0;
  size_t total = 0;

  mailbox_messages_count (mbox, &total);

  for (i = 0; i < argc; i++)
    {
      /* 1.     A lone ``*'' means select all messages in the mailbox. */
      if (!strcmp (argv[i], "*"))
	{
	  size_t j;
	  /* all messages */
	  for (j = 1; j <= total; j++)
	    addset (set, n, j);
	  j = argc + 1;
	}
      /* 2.     A list of message numbers may be specified.  Values of ``0'' and ``$'' in  the
	 list both mean the last message in the mailbox.  */
      else if (!strcmp (argv[i], "$") || !strcmp (argv[i], "0"))
	{
	  size_t j;
	  mailbox_messages_count (mbox, &total);
	  for (j = 1; j < total; j++)
	    addset (set, n, j);
	}
      /* 3.     Finally, the selection may be some text to match.  This  will  select  a  mail
	 message which exactly matches the specified text.  */
      else if (!is_number(argv[i]))
	{
	  size_t j;
	  int found = 0;
	  for (j = 1; j <= total; j++)
	    {
	      char buf[128];
	      size_t len = 0;
	      off_t offset = 0;
	      message_t msg = NULL;
	      stream_t stream = NULL;
	      mailbox_get_message (mbox, j, &msg);
	      message_get_stream (msg, &stream);
	      while (stream_readline (stream, buf, sizeof buf, offset, &len) == 0 && len > 0)
		{
		  if (strstr (buf, argv[i]) != NULL)
		    {
		      addset (set, n, j);
		      found = 1;
		      break;
		    }
		  offset += len;
		}
	      if (found && !show_all)
		break;
	    }
	}
      else if (isdigit (argv[i][0]))
	{
	  /* single message */
	  addset (set, n, strtol (argv[i], NULL, 10));
	}
    }

  return 0;
}