/*
**
** Copyright (C) 1994 Swedish University Network (SUNET)
**
**
** This program is developed by UDAC, Uppsala University by commission
** of the Swedish University Network (SUNET). 
**
** 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 of the License, 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 FITTNESS 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.
**
**
**                                        Martin.Wendel@udac.uu.se
**                                        Torbjorn.Wictorin@udac.uu.se
**
**                                        UDAC	
**                                        P.O. Box 174
**                                        S-751 04 Uppsala
**                                        Sweden
**
*/


#include "emil.h"
extern FILE *out_fd;
extern int smtp_client;
static	void	print_rheader(struct header *, int); /* forward */
static void print_hvalue(struct hprs *);
static void	print_hbody(struct data *);
char *eol = NULL;

void	out_message(struct message *m)
{
  if (m == NULL)
    return;
  if (eol == NULL)
    {
      if (smtp_client)
	eol = NEWSTR("\r\n");
      else
	eol = NEWSTR("\n");
    }
  
    
  if (det_sket_sig == TRUE)
    {
      m->sd->offset = 0;
      m->sd->bodystart = 0;
      m->sd->bodyend = m->sd->end;
      print_body(m->sd);
      return;
    }

  if (m->parent != NULL && target->iformat != RFC822)
    if (m->parent->td->startbound != NULL)
      {
#ifdef DEBUG
	if (edebug)
	  fprintf(stderr, "+ Start boundary %s\n", m->parent->td->startbound);
#endif
	if (target->iformat == MIME)
	  fprintf(out_fd, "%s%s%s", eol, m->parent->td->startbound, eol);
	else
	  if (m->td->encoding != EMULTI)
	    fprintf(out_fd, "%s%s", m->parent->td->startbound, eol);
      }
/*  encode_header(m); */

  if (target->iformat != RFC822 || m->level == 0)
    {
#ifdef DEBUG
      if (edebug)
	fprintf(stderr, "+ Printing header.\n");
#endif
      print_rheader(m->h, target->iformat);
      fprintf(out_fd, "%s", eol); /* End of header */
    }

  if (m->td->bodyend)
    m->td->end = m->td->bodyend;

  m->td->offset = m->td->bodystart;

  if (m->td->encoding != EMULTI)
    print_body(m->td);

  if (m->child != NULL)
    out_message(m->child);
  if (m->td->endbound != NULL && target->iformat == MIME)
    {
#ifdef DEBUG
      if (edebug)
	fprintf(stderr, "+ End boundary %s\n", m->td->endbound);
#endif
      fprintf(out_fd, "%s%s%s", eol, m->td->endbound, eol);
    }
  if (m->sibling != NULL)
    out_message(m->sibling);
  fflush(out_fd);
}

void	print_body(struct data *d)
{
  struct data *line;
  long count;
  int len;
  
  if (d == NULL)
    {
#ifdef DEBUG
      fprintf(stderr, "*  print_body: Called with NULL input, ignoring...\n");
#endif
      return;
    }

  line = (struct data *)Yalloc(sizeof(struct data));
  if (det_sket_sig == TRUE)
    {
#ifdef DEBUG
      if (edebug)
	fprintf(stderr, "*** Printing transparent.\n");
#endif
      count = 0;
    }
  else
    {
      count = 1;
#ifdef DEBUG
      if (edebug)
	fprintf(stderr, "+ Print body.\n");
#endif
    }
  d->offset = d->bodystart;
  while ((len = getline(d)) != 0)
    {
      line->end = 0;
      append_data(line, (d->contents + d->offset), len, MED_BUF);
      if (strcmp(line->contents, ".\n") == 0 ||
	  strcmp(line->contents, ".\r\n") == 0)
	fprintf(out_fd, ".");
      if (count)
	{
	  if (strncmp(line->contents, "From ", 5) == 0)
	    fprintf(out_fd, ">");
	  print_line(line->contents);
	}
      else
	{
	  if (want_unix_from == 0)
	    {
	      if (strncmp(line->contents, "From ", 5) == 0)
		{
		  d->offset += len;
		  count++;
		  continue;
		}
	      else
		print_line(line->contents);
	    }
	  else
	    {
	      if (strncmp(line->contents, "From ", 5) == 0)
		print_line(line->contents);
	      else
		{
		  fprintf(out_fd, "From %s%s", sender, eol);
		  print_line(line->contents);
		}
	    }
	  
	}
      d->offset += len;
      count++;
      fflush(out_fd);
    }
  fflush(out_fd);
}

static	void print_rheader(struct header *h, int format)
{
  struct header *th;
  static int hcount = 0;
  for (th = h; th != NULL; th = th->next)
    {
      if (th->type == UNIXFROM && want_unix_from == 0)
	continue;
      if (hcount == 0 && want_unix_from && th->type != UNIXFROM
	  && sender != NULL)
	fprintf(out_fd, "From %s%s", sender, eol);
      hcount++;
      if (th->field != NULL && th->field->end != 0 && 
	  (th->format == RFC822 || th->format == format))
	{
	  parse_rfc1522(th);
#ifdef DEBUG
	  if (edebug)
	    fprintf(stderr, "+ Print header (%s).\n",
		    th->field->contents);
#endif
/*
	   if (*th->field->contents == '>')
            fprintf(out_fd, "%s", th->field->contents + 1);
          else
*/
	  fprintf(out_fd, "%s", th->field->contents);
	  if (th->type != UNIXFROM)
	    {
	      fprintf(out_fd, ": ");
	      if (th->hvalue != NULL)
		(void)print_hvalue(th->hvalue);
	      else
		if (th->value != NULL && th->value->end != 0)
		  print_line(th->value->contents);
	    }
	  fprintf(out_fd, "%s", eol);
      }
    }
}

static void print_hvalue(struct hprs *h)
{
#ifdef DEBUG
  if (edebug)
    fprintf(stderr, "+ Printing hvalue structure.\n");
#endif
  switch (h->type)
    {
    case ATOM:
    case DELIMITER:
    case RFC1522:
      h->td->offset = h->td->bodystart;
      print_hbody(h->td);
      break;
    case DLITERAL:
      fprintf(out_fd, "[");
      break;
    case COMMENT:
      fprintf(out_fd, "(");
      break;
    case HQSTRING:
      fprintf(out_fd, "\"");
      break;
    case RADDR:
      fprintf(out_fd, "<");
      break;
    default:
      break;
    }
  if (h->child != NULL)
    print_hvalue(h->child);
  switch(h->type)
    {
    case DLITERAL:
      fprintf(out_fd, "]");
      break;
    case COMMENT:
      fprintf(out_fd, ")");
      break;
    case HQSTRING:
      fprintf(out_fd, "\"");
      break;
    case RADDR:
      fprintf(out_fd, ">");
      break;
    default:
      break;
    }
  if (h->sibling != NULL)
    print_hvalue(h->sibling);
}

static void	print_hbody(struct data *d)
{
  struct data * line;

  line = (struct data *)Yalloc(sizeof(struct data));
  append_data(line, (d->contents + d->offset), d->bodyend - d->offset, MED_BUF);
  print_line(line->contents);
}
int
print_line(char *s)
{
  char *e, *c;
  
  if (s == NULL)
    return(OK);
  while ((c = index(s, '\n')) != NULL)
    {
      e = c + 1;
      while (*c == '\n' || *c == '\r')
	{
	  *c = '\0';
	  c--;
	}
      fprintf(out_fd, "%s%s", s, eol);
      s = e;
    }
  if (*s != '\0')
      fprintf(out_fd, "%s", s);
  return(OK);
}    
  
  
      
  
