/*
 * Program:	Cat a mailbox from an IMAP source
 *
 * Author:	Eric Horst
 *		Networks and Distributed Computing
 *		University of Washington
 *		Administration Building, AG-44
 *		Seattle, WA  98195
 *		Internet: erich@CAC.Washington.EDU
 *
 * Date:	19 February 1998
 * Last Edited:	2 January 2002
 *
 * The IMAP tools software provided in this Distribution is
 * Copyright 2002 University of Washington.
 * The full text of our legal notices is contained in the file called
 * CPYRIGHT, included with this Distribution.
 */

#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <pwd.h>
#include "mail.h"
#include "osdep.h"
#include "rfc822.h"
#include "smtp.h"
#include "nntp.h"
#include "misc.h"

#define OPT_A 1
#define OPT_FA 2
#define OPT_FD 4
#define OPT_FF 8
#define OPT_FN 16
#define OPT_FO 32

char *curhst = NIL;		/* currently connected host */
char *curusr = NIL;		/* current login user */
char personalname[MAILTMPLEN];	/* user's personal name */
int nostatus = NIL, nomsgno = NIL, nodate = NIL,  /* flags */
  notime = NIL, altffmt = NIL, nolimit = NIL;
char *since,*before,*ondate;
char sstr[MAILTMPLEN];

int main (int argc,char *argv[]);
void mm (MAILSTREAM *stream,long debug);
void prompt (char *msg,char *txt);
int fail (char *string,int code);
char *getpass ();
int validdatefmt (char *d);

/* Main program - initialization */

int main (int argc,char *argv[])
{
  MAILSTREAM *stream = NIL;
  char *s,tmp[MAILTMPLEN];
  char *help = "usage: icat [-a] [-d[bos] <date>] [-f[adfno]] [-m[tscfbx] <string> [-h|?] mailbox";
  char *sword = "ALL";
  long debug;
  int options = 0;
#include "linkage.c"

  /* make sure have some arguments */
  if (--argc < 1) _exit (fail (help,1));
  /* process all flags */
  while (argc && *(s = *++argv) == '-') {
    argc--;                     /* gobble this argument */
    switch (s[1])		/* what is this flag? */
      {             
      case 'a':                 /* spew all messages */
	if (!(options & OPT_A) && (options |= OPT_A))
	  strcat(sstr, "ALL ");
	break;
      case 'd':                   /* spew matching date */
	switch(s[2])
	  {
	  case 'b':  sword = "BEFORE";  break;
	  case 'o':  sword = "ON";      break;
	  case 's':  sword = "SINCE";   break;
	  default:
	    sprintf(tmp, "unknown option %s", s);
	    _exit (fail (tmp,1));
	  }

	if (argc--) {
	  if (validdatefmt(*(++argv))) {
	    sprintf(tmp,"%s %s ", sword, *argv);
	    strcat(sstr, tmp);
	  }
	  else {
	    sprintf(tmp, "bad date format in %s, must be DD-MMM-YYYY", s);
	    _exit (fail (tmp,1));
	  }
	}
	else {
	  sprintf(tmp, "missing argument to %s", s);
	  _exit (fail (tmp,1));
	}

	break;

      case 'f':                   /* spew those flagged */
	switch(s[2])              /* i'm punting on the NOTs, xcept new/old */
	      {
	      case 'a':
		if (!(options & OPT_FA) && (options |= OPT_FA))
		  strcat(sstr, "ANSWERED ");
		break;
	      case 'd':
		if (!(options & OPT_FD) && (options |= OPT_FD))
		  strcat(sstr, "DELETED ");
		break;
	      case 'f':
		if (!(options & OPT_FF) && (options |= OPT_FF))
		  strcat(sstr, "FLAGGED ");
		break;
	      case 'n': 
		if (!(options & OPT_FN) && (options |= OPT_FN))
		  strcat(sstr, "UNSEEN ");  /* NEW prob not what user wants */
		break;
	      case 'o':
		if (!(options & OPT_FO) && (options |= OPT_FO))
		  strcat(sstr, "SEEN ");    /* OLD prob not what user wants */
		break;
	      default:
		sprintf(tmp, "unknown option %s", s );
		_exit (fail (tmp,1));
	      }
	    break;

      case 'm':                   /* spew matching a string */
	switch(s[2])
	  {
	  case 't':  sword = "TO";      break;
	  case 'f':  sword = "FROM";    break;
	  case 'c':  sword = "CC";      break;
	  case 's':  sword = "SUBJECT"; break;
	  case 'b':  sword = "BODY";    break;
	  case 'x':  sword = "TEXT";    break;
	  default:   
	    sprintf(tmp, "unknown option %s", s);
	    _exit (fail (tmp,1));
	  }
	      
	if (argc--) {
	  sprintf(tmp,"%s \"%s\" ", sword, *++argv);
	  strcat(sstr, tmp);
	}
	else {
	  sprintf(tmp, "missing argument to %s", s);
	  _exit (fail (tmp,1));
	}
	break;

      case '?':                   /* give usage */
      case 'h':
	_exit (fail (help,1));
	break;

      default:                    /* anything else */
	_exit (fail ("unknown switch",1));
      }
  }

  if (!(argc--)) {
    _exit (fail ("missing mailbox specification",1));
  }

  curusr = cpystr(myusername()); /* current user is this name */
  {
    char *suffix;
    struct passwd *pwd = getpwnam (curusr);
    if (pwd) {
      strcpy (tmp,pwd->pw_gecos);
      /* dyke out the office and phone poop */
      if (suffix = strchr (tmp,',')) suffix[0] = '\0';
      strcpy (personalname,tmp);/* make a permanent copy of it */
    }
    else personalname[0] = '\0';
  }

  curhst = cpystr (mylocalhost ());
  if (!*personalname) prompt ("Personal name: ",personalname);
  debug =  NIL;
  stream = mail_open (stream,*argv,OP_READONLY);
  if (stream) mm (stream,debug);	  /* run user interface if opened */

  return NIL;
}

/* Report an error
 * Accepts: string to output
 */
int fail (char *string,int code)
{
  mm_log (string,ERROR);        /* pass up the string */
  return code;                  /* error code to return */
}

/* Check a date for correct format
 * Accepts: string somebody thinks looks like a date
 * Note: This is really rough.  c-client already checks better but 
 * has a horrible error message so we just make sure that it is at
 * least the correct form
 */
int validdatefmt (char *d)
{
  int day, year;
  char month[4];
  
  return ( sscanf(d, "%2d%*[-]%3s%*[-]%4d", &day, month, &year) == 3
	   && day > 0 && day < 32 
	   && year > 1900 && year < 9999
	   );
}

/* MM command loop
 * Accepts: MAIL stream
 */

void mm (MAILSTREAM *stream,long debug)
{
  unsigned long i;
  char tmp[MAILTMPLEN];
  char *m;
  int msg = 0;
  MESSAGECACHE *elt;

  mail_search(stream, sstr);
  for (i = 1; i <= stream->nmsgs; ++i) {
    if ((elt = mail_elt (stream,i))->searched) {
      if (!elt->valid) {
	sprintf (tmp,"%lu",i);
	mail_fetchfast (stream,tmp);
      }
      mail_cdate (tmp,elt);

      if (msg) printf("\n"); else msg = 1;
      printf ("From %s@%s %s",myusername (),mylocalhost (), tmp);

      m = mail_fetchheader (stream,i);
      while (*m != 0) {
	if (*m != '\r')
	  fwrite(m, 1, 1, stdout);
	m++;
      }
      m = mail_fetchtext (stream,i);
      while (*m != 0) {
	if (*m != '\r')
	  fwrite(m, 1, 1, stdout);
	m++;
      }
    }
  }

  mail_close (stream);
  stream = NIL;

  return;
}

/* Prompt user for input
 * Accepts: pointer to prompt message
 *          pointer to input buffer
 */

void prompt (char *msg,char *txt)
{
  printf ("%s",msg);
  gets (txt);
}

/* Interfaces to C-client */


void mm_searched (MAILSTREAM *stream,unsigned long number)
{
}


void mm_exists (MAILSTREAM *stream,unsigned long number)
{
}


void mm_expunged (MAILSTREAM *stream,unsigned long number)
{
}


void mm_flags (MAILSTREAM *stream,unsigned long number)
{
}


void mm_notify (MAILSTREAM *stream,char *string,long errflg)
{
  mm_log (string,errflg);
}


void mm_list (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
{
}


void mm_lsub (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
{
}


void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
{
}


void mm_log (char *string,long errflg)
{
  switch ((short) errflg) {
  case NIL:
    break;
  case PARSE:
    break;
  case WARN:
    fprintf (stderr, "%%%s\n",string);
    break;
  case ERROR:
    fprintf (stderr, "?%s\n",string);
    break;
  }
}


void mm_dlog (char *string)
{
  fprintf (stderr, "%s\n",string);
}


void mm_login (NETMBX *mb,char *user,char *pwd,long trial)
{
  char tmp[MAILTMPLEN];
  if (curhst) fs_give ((void **) &curhst);
  curhst = (char *) fs_get (1+strlen (mb->host));
  strcpy (curhst,mb->host);
  if (*mb->user) {
    strcpy (user,mb->user);
    sprintf (tmp,"{%s/%s/user=%s} password: ",mb->host,mb->service,mb->user);
  }
  else {
    sprintf (tmp,"{%s/%s} username: ",mb->host,mb->service);
    prompt (tmp,user);
    strcpy (tmp,"Password: ");
  }
  if (curusr) fs_give ((void **) &curusr);
  curusr = cpystr (user);
  strcpy (pwd,getpass (tmp));
}


void mm_critical (MAILSTREAM *stream)
{
}


void mm_nocritical (MAILSTREAM *stream)
{
}


long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
{
  kill (getpid (),SIGSTOP);
  return NIL;
}


void mm_fatal (char *string)
{
  fprintf (stderr,"?%s\n",string);
}


