/* -*- mode: C; mode: fold; -*- */
/* Copyright (c) 1998 John E. Davis (davis@space.mit.edu)
 *
 * This file is part of slrn.
 *
 * Slrn 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.
 * 
 * Slrn 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 Slrn; see the file COPYING.  If not, write to the Free
 * Software Foundation, 59 Temple Place - Suite 330, 
 * Boston, MA  02111-1307, USA.
 */

#include "config.h"
#include "slrnfeat.h"

#include <stdio.h>
#include <string.h>

#ifdef __WIN32__
# include <windows.h>
#endif

#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif

#include "print.h"
#include "misc.h"
#include "util.h"
#include "ttymsg.h"

char *Slrn_Printer_Name;

/* I am using prefixes such as popen_ for the benefit of those without a 
 * folding editor.
 */
#ifdef USE_NOTEPAD_PRINT_CODE
# define np_open_printer slrn_open_printer
# define np_close_printer slrn_close_printer
# define np_write_to_printer write_to_printer
# ifdef __WIN32__
#  define NOTEPAD_PRINT_CMD	"start /m notepad /p %s"
# else
#  ifdef VMS
#   define NOTEPAD_PRINT_CMD	"PRINT/QUEUE=SYS$PRINT %s"
#  else
#   define NOTEPAD_PRINT_CMD	"lpr %s"
#  endif
# endif
#else
# ifdef __WIN32__
#  define USE_WIN32_PRINT_CODE	1
#  define win32_open_printer slrn_open_printer
#  define win32_close_printer slrn_close_printer
#  define win32_write_to_printer write_to_printer
# else
#  ifdef __unix__
#   define USE_POPEN_PRINT_CODE	1
#   define popen_open_printer slrn_open_printer
#   define popen_close_printer slrn_close_printer
#   define popen_write_to_printer write_to_printer
#  else
#   define USE_DUMMY_PRINT_CODE	1
#   define dummy_open_printer slrn_open_printer
#   define dummy_close_printer slrn_close_printer
#   define dummy_write_to_printer write_to_printer
#  endif
# endif
#endif


#ifdef USE_WIN32_PRINT_CODE /*{{{*/

# ifdef HAVE_WINSPOOL_H
#  include <winspool.h>
# else
extern WINBOOL WINAPI OpenPrinterA(LPTSTR, LPHANDLE, LPVOID);
extern WINBOOL WINAPI ClosePrinter(HANDLE);
extern DWORD WINAPI StartDocPrinterA(HANDLE, DWORD, LPBYTE);
extern WINBOOL WINAPI EndDocPrinter(HANDLE);
extern WINBOOL WINAPI StartPagePrinter(HANDLE);
extern WINBOOL WINAPI EndPagePrinter(HANDLE);
extern WINBOOL WINAPI WritePrinter(HANDLE, LPVOID, DWORD, LPDWORD);
# endif

struct _Slrn_Print_Type
{
   int error_status;
   HANDLE h;
};

int win32_close_printer (Slrn_Print_Type *p)
{
   if ((p == NULL)
       || (p->h == INVALID_HANDLE_VALUE))
     return 0;
   
   EndDocPrinter (p->h);
   ClosePrinter (p->h);
   slrn_free ((char *) p);
   return 0;
}

Slrn_Print_Type *win32_open_printer (void)
{
   char printer_name_buf [256];
   HANDLE h;
   static DOC_INFO_1 doc_info = 
     {
	"slrn-print-file",	       /* name of the document */
	NULL,			       /* name of output file to use */
	"RAW"			       /* data type */
     };
   Slrn_Print_Type *p;
   char *printer_name;

   if (NULL == (p = (Slrn_Print_Type *) SLmalloc (sizeof (Slrn_Print_Type))))
     return NULL;
   
   memset ((char *) p, 0, sizeof(Slrn_Print_Type));

   if (NULL == (printer_name = Slrn_Printer_Name))
     {
	(void) GetProfileString("windows", "device", "LPT1,,", printer_name_buf, sizeof(printer_name_buf));
	printer_name = slrn_strchr (printer_name_buf, ',');
	if (NULL != printer_name)
	  *printer_name = 0;
	
	printer_name = printer_name_buf;
     }
   
   if (FALSE == OpenPrinterA (printer_name, &h, NULL))
     {
	slrn_error ("OpenPrinterA failed: %d", GetLastError ());
	slrn_free ((char *) p);
	return NULL;
     }
   
   
   if (FALSE == StartDocPrinterA (h, 1, (unsigned char *) &doc_info))
     {
	slrn_error ("StartDocPrinterA failed: %d", GetLastError ());
	ClosePrinter (h);
	slrn_free ((char *) p);
	return NULL;
     }
   
   p->h = h;
   return p;
}

static int win32_write_to_printer (Slrn_Print_Type *p, char *buf, unsigned int len)
{
   DWORD nlen;
   
   if ((p == NULL) || (p->h == INVALID_HANDLE_VALUE) || (p->error_status != 0))
     return -1;

   if (FALSE == WritePrinter (p->h, buf, len, &nlen))
     {
	p->error_status = 1;
	slrn_error ("Write to printer failed: %d", GetLastError ());
	return -1;
     }
   
   return 0;
}

/*}}}*/
#endif				       /* USE_WIN32_PRINT_CODE */

#ifdef USE_NOTEPAD_PRINT_CODE /*{{{*/

struct _Slrn_Print_Type
{
   int error_status;
   FILE *fp;
   char file [SLRN_MAX_PATH_LEN];
};

int np_close_printer (Slrn_Print_Type *p)
{
   char cmd [256 + SLRN_MAX_PATH_LEN];

   if ((p == NULL) || (p->fp == NULL))
     return 0;
   
   (void) slrn_fclose (p->fp);
   sprintf (cmd, NOTEPAD_PRINT_CMD, p->file);
   slrn_posix_system (cmd, 1);
   (void) slrn_delete_file (p->file);
   
   slrn_free ((char *) p);
   return 0;
}

Slrn_Print_Type *np_open_printer (void)
{
   Slrn_Print_Type *p;

   if (NULL == (p = (Slrn_Print_Type *) SLmalloc (sizeof (Slrn_Print_Type))))
     return NULL;
   
   memset ((char *) p, 0, sizeof(Slrn_Print_Type));

   if (NULL == (p->fp = slrn_open_tmpfile (p->file, "w")))
     {
	slrn_error ("Failed to open tmp file");
	slrn_free ((char *) p);
	return NULL;
     }

   return p;
}

static int np_write_to_printer (Slrn_Print_Type *p, char *buf, unsigned int len)
{
   if ((p == NULL) || (p->fp == NULL) || (p->error_status))
     return -1;

   if (len != fwrite (buf, 1, len, p->fp))
     {
	p->error_status = 1;
	slrn_error ("Write to printer failed");
	return -1;
     }

   return 0;
}

/*}}}*/
#endif

#ifdef USE_POPEN_PRINT_CODE /*{{{*/
struct _Slrn_Print_Type
{
   int error_status;
   FILE *fp;
};

int popen_close_printer (Slrn_Print_Type *p)
{
   int code;

   if ((p == NULL) || (p->fp == NULL))
     return 0;
   
   code = _slrn_pclose (p->fp);

   slrn_free ((char *) p);

   if (code == 0) return 0;
   
   slrn_error ("Printer process returned error code %d", code);
   return -1;
}

Slrn_Print_Type *popen_open_printer (void)
{
   char *print_cmd;
   Slrn_Print_Type *p;
   char print_cmd_buf[1024];

   if (NULL == (print_cmd = Slrn_Printer_Name))
     {
	print_cmd = getenv ("PRINTER");
	if (print_cmd == NULL) print_cmd = "";
	sprintf (print_cmd_buf, "lpr -P%s", print_cmd);
	print_cmd = print_cmd_buf;
     }

   if (NULL == (p = (Slrn_Print_Type *) SLmalloc (sizeof (Slrn_Print_Type))))
     return NULL;
   
   memset ((char *) p, 0, sizeof(Slrn_Print_Type));

   if (NULL == (p->fp = popen (print_cmd, "w")))
     {
	slrn_error ("Failed to open process %s", print_cmd);
	popen_close_printer (p);
	return NULL;
     }
   
   return p;
}

static int popen_write_to_printer (Slrn_Print_Type *p, char *buf, unsigned int len)
{
   if ((p == NULL) || (p->fp == NULL) || (p->error_status))
     return -1;

   if (len != fwrite (buf, 1, len, p->fp))
     {
	p->error_status = 1;
	slrn_error ("Error writing to print process");
	return -1;
     }
   
   return 0;
}

/*}}}*/
#endif				       /* USE_POPEN_PRINT_CODE */

#ifdef USE_DUMMY_PRINT_CODE /*{{{*/
struct _Slrn_Print_Type
{
   int error_status;
};

Slrn_Print_Type *dummy_open_printer (void)
{
   slrn_error ("Printer not supported");
   return NULL;
}

static int dummy_write_to_printer (Slrn_Print_Type *p, char *buf, unsigned int len)
{
   return -1;
}

int dummy_close_printer (Slrn_Print_Type *p)
{
   return -1;
}

/*}}}*/
#endif				       /* USE_DUMMY_PRINT_CODE */


int slrn_write_to_printer (Slrn_Print_Type *p, char *buf, unsigned int len)
{
   char *b, *bmax;

   /* Map \n to \r\n */
   b = buf;
   bmax = b + len;
	
   while (b < bmax)
     {
	if (*b != '\n') 
	  {
	     b++;
	     continue;
	  }
	
	len = (unsigned int) (b - buf);
	if (len)
	  {
	     if (*(b - 1) == '\r')
	       {
		  b++;
		  continue;
	       }
	     
	     if (-1 == write_to_printer (p, buf, len))
	       return -1;
	  }
	
	if (-1 == write_to_printer (p, "\r\n", 2))
	  return -1;
	
	b++;
	buf = b;
     }
   
   len = (unsigned int) (b - buf);
   if (len)
     return write_to_printer (p, buf, len);
   
   return 0;
}

int slrn_print_file (char *file)
{
   Slrn_Print_Type *p;
   FILE *fp;
   char line [1024];

   if (file == NULL) return -1;

   fp = fopen (file, "r");
   if (fp == NULL)
     {
	slrn_error ("Unable to open %s for printing", file);
	return -1;
     }
   
   p = slrn_open_printer ();
   if (p == NULL)
     {
	fclose (fp);
	return -1;
     }
   
   while (NULL != fgets (line, sizeof (line), fp))
     {
	if (-1 == slrn_write_to_printer (p, line, strlen(line)))
	  {
	     fclose (fp);
	     slrn_close_printer (p);
	     return -1;
	  }
     }
   
   fclose (fp);
   
   return slrn_close_printer (p);
}
