/*
 * TBCP port monitor for CUPS.
 *
 * Copyright 2007-2014 by Apple Inc.
 * Copyright 1993-2006 by Easy Software Products.
 *
 * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
 */

/*
 * Include necessary headers...
 */

#include <cups/cups-private.h>
#include <cups/ppd.h>


/*
 * Local functions...
 */

static char		*psgets(char *buf, size_t *bytes, FILE *fp);
static ssize_t		pswrite(const char *buf, size_t bytes);


/*
 * 'main()' - Main entry...
 */

int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line args */
     char *argv[])			/* I - Command-line arguments */
{
  FILE		*fp;			/* File to print */
  int		copies;			/* Number of copies left */
  char		line[1024];		/* Line/buffer from stream/file */
  size_t	linelen;		/* Length of line */


 /*
  * Check command-line...
  */

  if (argc < 6 || argc > 7)
  {
    _cupsLangPrintf(stderr,
                    _("Usage: %s job-id user title copies options [file]"),
		    argv[0]);
    return (1);
  }

  if (argc == 6)
  {
    copies = 1;
    fp     = stdin;
  }
  else
  {
    copies = atoi(argv[4]);
    fp     = fopen(argv[6], "rb");

    if (!fp)
    {
      perror(argv[6]);
      return (1);
    }
  }

 /*
  * Copy the print file to stdout...
  */

  while (copies > 0)
  {
    copies --;

   /*
    * Read the first line...
    */

    linelen = sizeof(line);
    if (!psgets(line, &linelen, fp))
      break;

   /*
    * Handle leading PJL fun...
    */

    if (!strncmp(line, "\033%-12345X", 9) || !strncmp(line, "@PJL ", 5))
    {
     /*
      * Yup, we have leading PJL fun, so copy it until we hit a line
      * with "ENTER LANGUAGE"...
      */

      while (strstr(line, "ENTER LANGUAGE") == NULL)
      {
        fwrite(line, 1, linelen, stdout);

	linelen = sizeof(line);
	if (psgets(line, &linelen, fp) == NULL)
          break;
      }
    }
    else
    {
     /*
      * No PJL stuff, just add the UEL...
      */

      fputs("\033%-12345X", stdout);
    }

   /*
    * Switch to TBCP mode...
    */

    fputs("\001M", stdout);

   /*
    * Loop until we see end-of-file...
    */

    while (pswrite(line, linelen) > 0)
    {
      linelen = sizeof(line);
      if (psgets(line, &linelen, fp) == NULL)
	break;
    }

    fflush(stdout);
  }

  return (0);
}


/*
 * 'psgets()' - Get a line from a file.
 *
 * Note:
 *
 *   This function differs from the gets() function in that it
 *   handles any combination of CR, LF, or CR LF to end input
 *   lines.
 */

static char *				/* O  - String or NULL if EOF */
psgets(char   *buf,			/* I  - Buffer to read into */
       size_t *bytes,			/* IO - Length of buffer */
       FILE   *fp)			/* I  - File to read from */
{
  char		*bufptr;		/* Pointer into buffer */
  int		ch;			/* Character from file */
  size_t	len;			/* Max length of string */


  len    = *bytes - 1;
  bufptr = buf;
  ch     = EOF;

  while ((size_t)(bufptr - buf) < len)
  {
    if ((ch = getc(fp)) == EOF)
      break;

    if (ch == '\r')
    {
     /*
      * Got a CR; see if there is a LF as well...
      */

      ch = getc(fp);

      if (ch != EOF && ch != '\n')
      {
        ungetc(ch, fp);	/* Nope, save it for later... */
        ch = '\r';
      }
      else
        *bufptr++ = '\r';
      break;
    }
    else if (ch == '\n')
      break;
    else
      *bufptr++ = (char)ch;
  }

 /*
  * Add a trailing newline if it is there...
  */

  if (ch == '\n' || ch == '\r')
  {
    if ((size_t)(bufptr - buf) < len)
      *bufptr++ = (char)ch;
    else
      ungetc(ch, fp);
  }

 /*
  * Nul-terminate the string and return it (or NULL for EOF).
  */

  *bufptr = '\0';
  *bytes  = (size_t)(bufptr - buf);

  if (ch == EOF && bufptr == buf)
    return (NULL);
  else
    return (buf);
}


/*
 * 'pswrite()' - Write data from a file.
 */

static ssize_t				/* O - Number of bytes written */
pswrite(const char *buf,		/* I - Buffer to write */
        size_t     bytes)		/* I - Bytes to write */
{
  size_t	count;			/* Remaining bytes */


  for (count = bytes; count > 0; count --, buf ++)
    switch (*buf)
    {
      case 0x04 : /* CTRL-D */
          if (bytes == 1)
	  {
	   /*
	    * Don't quote the last CTRL-D...
	    */

	    putchar(0x04);
	    break;
	  }

      case 0x01 : /* CTRL-A */
      case 0x03 : /* CTRL-C */
      case 0x05 : /* CTRL-E */
      case 0x11 : /* CTRL-Q */
      case 0x13 : /* CTRL-S */
      case 0x14 : /* CTRL-T */
      case 0x1b : /* CTRL-[ (aka ESC) */
      case 0x1c : /* CTRL-\ */
	  if (putchar(0x01) < 0)
	    return (-1);
	  if (putchar(*buf ^ 0x40) < 0)
	    return (-1);
	  break;

      default :
	  if (putchar(*buf) < 0)
	    return (-1);
	  break;
    }

  return ((ssize_t)bytes);
}
