/* movemail.c
   Copyright (C) 1995-1996 Eberhard Mattes

This file is part of GNU Emacs.

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

GNU Emacs 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 GNU Emacs; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */


#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#include <share.h>
#include <time.h>
#include "mailutil.h"
#include "poputil.h"


static char const uupc_delim[] = "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1";


static char *cmd (FILE *f, const char *fmt, ...)
{
  va_list arg_ptr;
  char *answer;
  int rc;

  va_start (arg_ptr, fmt);
  rc = pop_vcmd (f, &answer, fmt, arg_ptr);
  va_end (arg_ptr);
  if (rc == EX_POPERR)
    {
      fprintf (stderr, "%s\n", answer);
      pop_abort (f);
      exit (2);
    }
  else if (rc != EX_OK)
    {
      perror ("pop_vcmd()");
      pop_abort (f);
      exit (2);
    }
  return (answer);
}


static void move_pop3 (char *input_fname, char *output_fname)
{
  char *user, *host, *pass, *cookie, *p;
  int i, msg_count, msg_size, rc, in_header;
  FILE *inp, *out;
  time_t t;

  rc = pop_user_host (input_fname, &user, &host);
  if (rc == EX_MAILHOST)
    {
      fputs ("MAILHOST not set\n", stderr);
      exit (1);
    }
  else if (rc != EX_OK)
    {
      perror ("pop_user_host()");
      exit (1);
    }

  cookie = pop_cookie (user, host);

  rc = pop_open (host, 110, &inp);
  if (rc != EX_OK)
    {
      fputs ("pop_open() failed\n", stderr);
      exit (2);
    }
  rc = pop_answer (inp, &p);
  if (rc == EX_POPERR)
    {
      fprintf (stderr, "%s\n", p);
      exit (2);
    }
  else if (rc != EX_OK)
    {
      perror ("pop_answer()");
      exit (2);
    }

  cmd (inp, "USER %s", user);

  pass = pop_getpass (cookie);
  if (pass == NULL) goto failure;
  cmd (inp, "PASS %s", pass);
  memset (pass, 0, POP_GETPASS_LEN);

  p = cmd (inp, "STAT");
  if (sscanf (p, "+OK %d %d", &msg_count, &msg_size) != 2)
    {
      fprintf (stderr, "Cannot parse answer of STAT command\n");
      goto failure;
    }

  out = fopen (output_fname, "w");
  if (out == NULL)
    {
      perror (output_fname);
      goto failure;
    }

  rc = EX_EOF;
  for (i = 1; i <= msg_count; ++i)
    {
      cmd (inp, "RETR %d", i);
      time (&t);
      fprintf (out, "From dummy@dummy  %s", ctime (&t));
      in_header = 1;
      while ((rc = read_line (inp, 0, &p)) == EX_OK)
        {
          if (strcmp (p, ".") == 0)
            break;
          if (*p == '.')
            ++p;
          if (*p == 0)
            in_header = 0;
          if (!in_header && strncmp (p, "From", 4) == 0)
            fputc ('>', out);
          fputs (p, out);
          fputc ('\n', out);
        }
      fputc ('\n', out);
    }
  if (rc != EX_OK && rc != EX_EOF)
    {
      perror ("read_line()");
      fclose (out); remove (output_fname);
      goto failure;
    }
  if (fclose (out) != 0)
    {
      remove (output_fname);
      goto failure;
    }

  for (i = 1; i <= msg_count; ++i)
    cmd (inp, "DELE %d", i);

  cmd (inp, "QUIT");
  fclose (inp);
  return;

failure:
  pop_abort (inp);
  fclose (inp);
  exit (1);
}


static void move_mbox (char *input_fname, char *output_fname)
{
  FILE *inp, *out;
  char *p;
  int rc;

  remove (output_fname);

  inp = _fsopen (input_fname, "r+b", SH_DENYRW);
  if (inp == NULL)
    {
      perror (input_fname);
      exit (2);
    }

  out = fopen (output_fname, "w");
  if (out == NULL)
    {
      perror (output_fname);
      exit (2);
    }

  rc = read_line (inp, 0, &p);
  if (rc == EX_OK)
    {
      if (strcmp (p, uupc_delim) == 0)
        {
          int in_header;

          /* UUPC */
          in_header = 1;
          while ((rc = read_line (inp, 0, &p)) == EX_OK)
            {
              if (strcmp (p, uupc_delim) == 0)
                {
                  in_header = 1;
                  fputc ('\n', out);
                }
              else
                {
                  if (*p == 0)
                    in_header = 0;
                  else if (!in_header && strncmp (p, "From ", 5) == 0)
                    fputc ('>', out);
                  fputs (p, out);
                  fputc ('\n', out);
                }
            }
        }
      else
        do
          {
            fputs (p, out);
            fputc ('\n', out);
          } while ((rc = read_line (inp, 0, &p)) == EX_OK);
    }

  if (rc != EX_OK && rc != EX_EOF)
    {
      perror ("read_line()");
      fclose (out);
      remove (output_fname);
      exit (2);
    }

  if (fclose (out) != 0)
    {
      perror (output_fname);
      remove (output_fname);
      exit (2);
    }
  ftruncate (fileno (inp), 0);
  fclose (inp);
}


static void move_lamail (char *input_fname, char *output_fname)
{
  FILE *idx, *out;
  char *p;
  char line[1024];
  char note_dir[260];
  int len;
  struct slist lines;
  struct slist del;
  struct snode *np;

  slist_init (&lines);
  slist_init (&del);

  idx = _fsopen (input_fname, "r+", SH_DENYRW);
  if (idx == NULL)
    {
      perror (input_fname);
      exit (2);
    }

  p = _getname (input_fname);
  len = p - input_fname;
  memcpy (note_dir, input_fname, len);
  note_dir[len] = 0;

  out = fopen (output_fname, "w");
  if (out == NULL)
    {
      perror (output_fname);
      exit (2);
    }

  while (fgets (line, sizeof (line), idx) != NULL)
    {
      FILE *inp;
      char *p;
      int in_header, first_line, rc;
      char note_name[512];
      time_t t;

      sprintf (note_name, "%s%.8s.%.3s", note_dir, line + 27, line + 36);
      inp = fopen (note_name, "rb");
      if (inp == NULL)
        slist_add (&lines, line);
      else
        {
          in_header = first_line = 1;
          while ((rc = read_line (inp, 0, &p)) == EX_OK)
            {
              if (*p == 0)
                in_header = 0;
              if (strncmp (p, "From ", 5) != 0)
                {
                  if (first_line)
                    {
                      time (&t);
                      fprintf (out, "From dummy@dummy  %s", ctime (&t));
                    }
                  fputs (p, out);
                  fputc ('\n', out);
                }
              else
                {
                  if (!in_header)
                    fputc ('>', out);
                  if (first_line || !in_header)
                    {
                      fputs (p, out);
                      fputc ('\n', out);
                    }
                }
              first_line = 0;
            }
          if (rc != EX_OK && rc != EX_EOF)
            {
              perror ("read_line()");
              fclose (out); remove (output_fname);
              exit (2);
            }
          fputc ('\n', out);

          fclose (inp);

          if (fflush (out) != 0)
            {
              perror ("Output file");
              fclose (out); remove (output_fname);
              exit (2);
            }
          slist_add (&del, note_name);
        }
    }

  if (fclose (out) != 0)
    {
      perror ("Output file");
      fclose (out); remove (output_fname);
      exit (2);
    }

  /* Now truncate the index file to 0 bytes.  We don't delete the file
     because that would create a timing window. */

  rewind (idx);
  ftruncate (fileno (idx), 0L);

  /* Add the unprocessed index lines. */

  for (np = lines.first; np != NULL; np = np->next)
    fputs (np->str, idx);

  /* Delete note files. */

  for (np = del.first; np != NULL; np = np->next)
    remove (np->str);

  fclose (idx);
}


int main (int argc, char *argv[])
{
  if (argc != 3)
    {
      fprintf (stderr, "Usage: movemail <input_file> <output_file>\n");
      return (1);
    }

  if (strncmp (argv[1], "po:", 3) == 0)
    move_pop3 (argv[1] + 3, argv[2]);
  else if (stricmp (_getname (argv[1]), "inbox.ndx") == 0)
    move_lamail (argv[1], argv[2]);
  else
    move_mbox (argv[1], argv[2]);
  return (0);
}
