#!/usr/local/bin/pike -w
#pragma strict_types

class Mbox_iterator
{
  static
  {
    constant BSIZE = 8192;
    Stdio.Stream f;
    int which;
    string current;
    string buf = ""; // read-ahead into the stream
  }

  static int(0..1) find_next()
  {
    int offset;

    /* find the beginning, usually we're already there.. */
    while((offset=search(buf, "\n\nFrom "))==-1)
      {
	string tmp = f->read(BSIZE);
	if(!sizeof(tmp))
	  {
	    current = "";
	    return 0;
	  }
	buf += tmp;
      }

    buf = buf[offset..];

    /* ..then the end */
    while((offset=search(buf, "\n\nFrom ", 7))==-1)
      {
	string tmp = f->read(BSIZE);
	if(!sizeof(tmp))
	  {
	    current = buf[2..]; // snip leading newlines
	    buf = "";
	    return 1;
	  }
	else
	  {
	    buf += tmp;
	  }
      }

    current = buf[2..offset-1]; // snip leading newlines
    buf = buf[offset..];
    return 1;
  }

  int index()
  {
    return which;
  }

  string value()
  {
    return current;
  }

  int(0..1) `!()  // return 1 if the iterator is 'done'
  {
    return !sizeof(current);
  }

#if 0
  Mbox_iterator `+(int(0..) nsteps)
  {
    error("Mbox_iterator.`+(): not implemented.\n");
  }
#endif

  Mbox_iterator `+=(int(0..) nsteps)
  {
    while(nsteps--)
      next();
    return this_object();
  }

  int(0..1) next()  // like `+=(1), but return 0 if the iterator is finished
  {
    return find_next() ? (++which, 1) : 0;
  }

  int(0..1) first()  // restart, return 0 if it fails
  {
    return 0;
  }

  static void create(Stdio.Stream _f)
  {
    f = _f;
    buf = f->read(BSIZE);
    if(buf[..4]!="From ")
      {
	find_next();
	return;
      }
    else // beginning is OK, find end
      {
	int offset;

	while((offset=search(buf,"\n\nFrom ", 5))==-1)
	  {
	    string tmp = f->read(BSIZE);
	    if(!sizeof(tmp))
	      {
		current = buf; // no leading newlines here
		buf = "";
		return;
	      }
	    else
	      {
		buf += tmp;
	      }
	  }

	current = buf[..offset-1]; // no leading newlines here
	buf = buf[offset..];
	return;
      }
  }
}

int main(int ac, array(string) av)
{
  Stdio.Stream mbox;
  array(array(string)) header_data = ({});

  if(ac>1)
    {
      if(av[1]=="-")
	mbox = Stdio.stdin;
      else
	mbox = Stdio.File(av[1], "r");
    }
  else
    {
      string mpath = (string)(getenv("MAIL") || 
			      ("/var/mail/" + ( getenv("USER") || getenv("LOGNAME"))));
      mbox = Stdio.File(mpath, "r");
    }

  Mbox_iterator it = Mbox_iterator(mbox);
  
  while(!!it)
    {
      header_data += ({ ({ (string)(it->index()+1) }) + headers(it->value()) });
      it->next();
    }

  int cols = [int](Stdio.stderr->tcgetattr()->columns) || 80;
  string format = "%{%-3s %!-"+(string)((cols-6)*2/5)+"s  %!-"+(string)((cols-6)*3/5)+
    "s\n%}";

  write(format, header_data);
  return 0;
}

array(string) headers(string current)
{
  array(string) res = ({"",""});
  
  array(string) tmp = current/"\n\n";
  if(tmp[0] == "")
    {
      current=tmp[1];
    }
  else if(tmp[0][..4]=="From ")
    {
      current = tmp[0];
    }
  else
    error("headers(): unexpected malformed argument.");

  foreach(current/"\n", string line)
    {
      if(lower_case(line[..4])=="from:")
	{
	  res[0] = line[5..];
	}
      else if(lower_case(line[..7])=="subject:")
	{
	  res[1] = line[8..];
	}
    }
  return res;
}