/* ttink.c
 *
 * Copyright (C) 2001 Jean-Jacques Sarton jj.sarton@t-online.de
 */
/*
 * 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 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <strings.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

#ifdef MACOS
#include "usbHlp.h"
#endif

#include "mtink.h"
#include "access.h"

#include "rcfile.h"
#include "rdRes.h"

#include "cmd.h"
#include "version.h"

#include "d4lib.h"

#include "rdPrtDesc.h"
#define defaultConfigData configData
#define defaultConfigDataSize configEntries


#ifndef TEST
#define TEST 0
#endif

int   deviceHdl         = -1; /* for write / read to / from printer */
char *prgName;
int   pb                = 0;
int   pc                = 0;
int   pm                = 0;
int   py                = 0;
int   plc               = 0;
int   plm               = 0;
int   plb               = 0;
int   plp               = 0;
int   plx               = 0;
char *printerName       = NULL;
char *printerState;
int   findDevice        = 0;

configData_t actConfig;
char *mainResource;

int doReset             = 0;
int doClean             = 0;
int doCheck             = 0;
int doStatus            = 0;
int doAlign             = 0;
int doExchangeCartridge = 0;
int cycle               = 0;
int doIdent             = 0;
int utf8                = 0;

int d4Printer           = 0;
char *model             = NULL;
char *device            = NULL;

#define NAME "EpsonUtil"


int decodePrinterType(unsigned char *buf, int len);
int getPrinterInfo();
int decodeStatus(unsigned char *buf, int len, char *lang);
int alignHeads(char *lang, configData_t actConfig);
int exchangeInk(char *lang, configData_t actConfig);

int setConfig(char *lang);

int (*ynFunc)(char*,char*);

extern int inFromFile;

/*******************************************************************/
/* Function sigKill(int code)                                      */
/*                                                                 */
/* terminate gacefully if a sigkill occured                        */
/*                                                                 */
/*******************************************************************/

static void sigKill(int code)
{
   callPrg(TERMINATE,NULL, 0, 0, 0, NULL, NULL);
   exit(0);
}

/*******************************************************************/
/* Function setPrinterStateLabel(int state)                        */
/*                                                                 */
/* set the printer state label accpording to state                 */
/*                                                                 */
/*******************************************************************/

void setPrinterStateLabel(int state)
{
#if 0 /* not now */
   switch(state)
   {
      case 0:  printerState = appResourceRec.error;    break;
      case 1:  printerState = appResourceRec.selfTest; break;
      case 2:  printerState = appResourceRec.busy;     break;
      case 3:  printerState = appResourceRec.printing; break;
      case 4:  printerState = appResourceRec.ok;       break;
      case 7:  printerState = appResourceRec.cleaning; break;
      default: printerState = appResourceRec.unknown;
   }
   printf("%s\n"printerState);
#endif
}

/*******************************************************************/
/* Function exit_CB(...)                                           */
/*                                                                 */
/* terminate the programm                                          */
/*                                                                 */
/*******************************************************************/

void exit_CB(int val)
{
   callPrg(TERMINATE,NULL, 0, 0, 0, NULL, NULL);
#ifdef MACOS
   unlinkFiles();
#endif
   exit(val);
}

/*******************************************************************/
/* Function printSyntax                                            */
/*                                                                 */
/* print syntax and exit                                           */
/*                                                                 */
/*******************************************************************/

void printSyntax(int error, char *lang)
{
   FILE *out;
   if ( error )
      out = stderr;
   else
      out = stdout;

   fprintText(out, "%s", lang, "syntax1");
   fprintf(out, "%s\n",prgName);
#ifdef MACOS
   fprintText(out, "%s\n", lang, "syntaxM");
   unlinkFiles();
#else
   fprintText(out, "%s\n", lang, "syntax2");
#endif

   exit(error);
}

/*******************************************************************/
/* Function parseArgs(int argc, char **argv)                       */
/*                                                                 */
/* check for call parameters                                       */
/*                                                                 */
/*******************************************************************/

void parseArgs(int argc, char **argv, char *lang)
{
   int i;
   char *s;
   char *t;
   char  buf[256];

   /* look first for the option -u */
   for (i = 0; i < argc;i++ )
   {
      if ( strncmp("-u", argv[i], 2) == 0 ||
                strncmp("--u", argv[i], 3) == 0 )
      {
          utf8 = 1;
          lang[2] = '8'; lang[3] = '\0';
      }
   }

   while ( argc )
   {
      if ( strncmp("-F", argv[0], 2) == 0)
      {
         inFromFile = 1;
      }
      else
      if ( strncmp("-h", argv[0], 2) == 0 ||
                strncmp("--h", argv[0], 3) == 0 )
      {
         printSyntax(0, lang);
      }
      if ( strncmp("-f", argv[0], 2) == 0 ||
                strncmp("--f", argv[0], 3) == 0 )
      {
         findDevice = 1;;
      }
      else
      if ( strncmp("-W", argv[0], 2) == 0 )
      {
         ynFunc = askYn;
      }
      else if ( strncmp("-d", argv[0], 2) == 0 ||
                strncmp("--d", argv[0], 3) == 0 )
      {
          /* set device file */
          if ( argc > 1 )
          {
             device = strdup(argv[1]);
             argc--;
             argv++;
          }
          else
          {
             printSyntax(1, lang);
          }
      }
      else if ( strncmp("-m", argv[0], 2) == 0 ||
                strncmp("--m", argv[0], 3) == 0 )
      {
          /* set model name  */

          if ( argc > 1 )
          {
             model = argv[1];
             argc--;
             argv++;
          }
          else
          {
             printSyntax(1, lang);
          }
      }
      else if ( strncmp("-r", argv[0], 2) == 0 ||
                strncmp("--r", argv[0], 3) == 0 )
      {
          /* reset printer  command */
           doReset  = 1;
      }
      else if ( strncmp("-i", argv[0], 2) == 0 ||
                strncmp("--i", argv[0], 3) == 0 )
      {
          /* identity printer  command */
           doIdent  = 1;
      }
      else if ( strncmp("-D", argv[0], 2) == 0 ||
                strncmp("--D", argv[0], 3) == 0 )
      {
          /* identity printer  command */
           d4Printer  = 1;
      }
      else if ( strncmp("-a", argv[0], 2) == 0 ||
                strncmp("--a", argv[0], 3) == 0 )
      {
          /* align head command */
           doAlign  = 1;
      }
      else if ( strncmp("-c", argv[0], 2) == 0 ||
                strncmp("--c", argv[0], 3) == 0 )
      {
          /* clean printer command*/
          doClean = 1;

      }
      else if ( strncmp("-R", argv[0], 2) == 0 ||
                strncmp("--R", argv[0], 3) == 0 )
      {
          /* set device file */
          if ( argc > 1 )
          {
             cycle = atoi(argv[1]);
             argc--;
             argv++;
             if ( cycle < 0 )
             {
                printSyntax(1, lang);
             }
          }
          else
          {
             printSyntax(1, lang);
          }
      }
      else if ( strncmp("-n", argv[0], 2) == 0 ||
                strncmp("--n", argv[0], 3) == 0 )
      {
          /* nozzle check command*/
          doCheck = 1;

      }
      else if ( strncmp("-e", argv[0], 2) == 0 ||
                strncmp("--e", argv[0], 3) == 0 )
      {
          /* nozzle check command*/
          doExchangeCartridge = 1;

      }
      else if ( strncmp("-s", argv[0], 2) == 0 ||
                strncmp("--s", argv[0], 3) == 0 )
      {
          /* printer status command*/
          doStatus = 1;

      }
      else if ( strncmp("-u", argv[0], 2) == 0 ||
                strncmp("--u", argv[0], 3) == 0 )
      {
          utf8 = 1;
          lang[2] = '8'; lang[3] = '\0';
      }
      else if ( strncmp("-L", argv[0], 2) == 0  )
      {
          /* printer status command*/
          debugD4 = 1;
      }
      else if ( strncmp("-v", argv[0], 2) == 0 ||
                strncmp("--v", argv[0], 3) == 0 )
      {
         printf("%-8s: %s\n",prgName,VERSION);
         printf("compiled: %s %s\n",__DATE__,__TIME__);
         printf("Author  : Jean-Jacques Sarton\n");
         printf("URL     : http://xwtools.automatix.de\n");
         exit(0);
      }
      else if ( strncmp("-l", argv[0], 2) == 0 ||
                strncmp("--l", argv[0], 3) == 0 )
      {
         /* list known printers */
         i = 0;
         while (i < defaultConfigDataSize-1)
         {
            /* skip the stylus part */
            s = defaultConfigData[i].name + 7;
            t = buf;
            /* and replace ' ' by _ */
            while ( *s )
            {
               if ( *s   == ' ' )
                  *t = '_';
               else
                  *t = *s;
               s++;
               t++;
            }
            *t = '\0';
            
            printf("%3d: %-20s %s\n",i+1,buf, defaultConfigData[i].name);
            i++;       
         }
         exit(0);
      }
      argc--;
      argv++;
   }
   if ( doReset == 0 && doClean == 0 && doCheck == 0 && doAlign == 0 && doExchangeCartridge == 0 && doIdent == 0 )
      doStatus = 1;
   if ( (doReset + doClean + doCheck + doStatus + doAlign + doExchangeCartridge + doIdent) > 1 )
      printSyntax(1, lang);
#ifndef MACOS
   if ( device == NULL )
      printSyntax(1,lang);
#endif
}


/*******************************************************************/
/* Function main()                                                 */
/*                                                                 */
/* The begin of the world                                          */
/*                                                                 */
/*******************************************************************/

int main(int argc, char **argv)
{
   char           *s;
   int             state;
   wConfig_data_t  data;
   char           *retBuf       = NULL;
   char            printerFound = 0;
   char           *lang         = NULL;
   int             retVal       = 0;
#ifdef MACOS
   char            prtFile[512];
#endif
   ynFunc = askYn;

   prgName = argv[0];
   if ( (s = strrchr(prgName, '/')) != NULL )
   {
      prgName = s + 1;
   }

   /* try to get language spec from environment */
   
   lang = getenv("LANG");

   if ( lang == NULL )
   {
      if ( (lang = getenv("LC_ALL")) == NULL )
      {
         if ( (lang = getenv("LC_CTYPE")) == NULL )
         {   
            lang = (char*) strdup("en");
         }
      }
   }

   /* if no environment for language we have set en */

   if ( strlen(lang) >= 2 )
   {
      /* language may be valid */
      s = lang;
   }
   else
   {
      /* language spec 2 char long ! */
      s = "en";
   }

   if ( strstr(lang, "UTF-8") )
   {
      utf8 = 1;
   }

   lang = (char *)malloc(4);
   if ( lang == NULL )
   {
      exit(1);
   }
   *lang = '\0';

   lang[0] = toupper(s[0]);
   lang[1] = s[1];
   lang[2] = '\0';

   if ( utf8 )
   {
      lang[2] = '8';
      lang[3] = '\0';
   }

   initResource();
   
   readPrinterData();
   parseArgs(argc,argv, lang);
   if ( utf8 )
   {
      lang[2] = '8';
      lang[3] = '\0';
   }

   signal(SIGINT,  sigKill);
   signal(SIGQUIT, sigKill);
   signal(SIGSEGV, sigKill);
#ifndef MACOS
   if ( device )
   {
      /* Check access rights to the device */
      if ( fileAccess(device,R_OK|W_OK) == -1 )
      {
         /* we have not the permission to write
          * and read
          */
          fprintText(stderr,"%s\n", lang, "noAccess");
          exit_CB(1);         
      }
   }

   if ( (model == NULL || doIdent ) && ! d4Printer )
   {
      /* try to detect the printer model */
      state = callPrg(TEST_DEV, device, NO_PROT, 0, 0, &retBuf, NULL );
      /* look for the operation result */
      if ( state == -1 )
      {
          fprintText(stderr,"%s\n", lang, "noAccess");
          exit_CB(1);         
      }
      else if ( state == 0 && retBuf )
      {
         /* may be OK, check for model name */
         state = decodePrinterType((unsigned char*)retBuf, strlen(retBuf));
         if ( state )
         {
            printerFound = 1;
         }
         else
         {
            /* test with D4 exit */
            printerFound = 0;
         }
      }
      else if ( state == 1 )
      {
         /* may be OK but no answer from device */
         printerFound = 2;
      }
      else if ( state == 2 )
      {
         /* may be OK and a D4 device */
         printerFound = 2;
      }
   }
   else if ( !d4Printer )
   {
      printerFound = 1;
      printerName = strdup(model);
   } 

   if ( (printerFound == 0 || printerFound == 2) &&  !d4Printer )
   {
      retBuf = NULL;
      state = callPrg(GET_ID, device, PROT_EXIT|PROT_OLD, 0, 0, &retBuf, NULL );
      if ( state == 0 && retBuf )
      {
         /* may be OK, check for model name */
         state = decodePrinterType((unsigned char*)retBuf, strlen(retBuf));
         if ( state )
         {
            printerFound = 1;
         }
         else
         {
            /* test with D4 */
            printerFound = 0;
         }
      }
      else
      {
         /* may be OK and a D4 device */
         printerFound = 0;
      }
   }
#else
   /* on MacOS we use the lib usb */
   if ( (state = usbInit()) > 0 )
   {
      /* printers detected */
      if ( createFiles() == 0 )
      {
         int i;
         /* device given, check if OK */
         if ( device != NULL )
         {
            /* look for usb: */
            s = strstr(device, USB_PRT_NAME_PREFIX);
            if ( s )
            {
               s += strlen(USB_PRT_NAME_PREFIX);
               if ( isdigit(*s) )
               {
                  i = atoi(s);
               }
               else /* expect usb:<number>:printer name */
               {
                  i = -1;
               }

               if ( i > -1 && i < state )
               {
                  s = strchr(s, ':');
                  if ( s )
                  {
                     s++;
                     if ( strcmp(s,getPrinterName(i)) )
                     {
                        free(device);
                        device = NULL;
                     }
                     else
                     {
                        state = i + 1;
                     }
                  }
               }
               else /* no match */
               {
                  free(device);
                  device = NULL;
               }
            }
            else /* wrong name build */
            {
               free(device);
               device = NULL;
            }
         }

         if ( state > 1 && device == NULL && findDevice == 0 )
         {
            /* choose printer model */
            fprintText(stdout, "%s\n", lang,"followingPrintersFound");
            for ( i = 0; i < state; i++)
            {
               printf("%2d: %s\n",i+1, devices[i].prtname);
            }
            fprintText(stdout, "%s\n", lang,"ChoosePrinter");
            state = askNo(1,state);
         }

         /* user told to print only device file name */
         if (findDevice)
         {
            for ( i = 0; i < state; i++)
            {
               printf(USB_PRT_NAME_PREFIX"%02d:%s\n",i,devices[i].prtname);
            }
            exit_CB(0);
         }
         
         /* build device file name */
         if ((s = getPrinterName(state-1)))
         {
            state--;
            snprintf(prtFile, sizeof(prtFile),USB_PRT_NAME_PREFIX"%02d:%s",state,s);
            model  = strdup(s);
            printerName = strdup(s);
            device = prtFile;
            printerFound = 1;
         }
      }
      else
      {
         fprintText(stderr,"%s\n",lang, "noEnoughMemory");
      }
   }
   else
   {
   }
#endif
  /* we may have set the -D flag d4Printer in order to avoid detection */
  /* via non D4 protocol. in this case the detection is to be done     */
  /* on the following conditions:
   *  doIdent is set and printerFound is 0 
   *
   */

  if ( printerFound == 0 )
  {
      retBuf = NULL;
      state = callPrg(GET_ID, device, PROT_D4, 0, 0, &retBuf, NULL );

      /* look for the operation result */
      if ( state == 0 && retBuf )
      {
         /* may be OK, check for model name */
         state = decodePrinterType((unsigned char*)retBuf, strlen(retBuf));
         if ( state )
         {
            printerFound = 1;
         }
         else
         {
            /* test with D4 */
            printerFound = 0;
         }
      }
      else
      {
         /* not an Epson printer */
         printerFound = 0;
      }
   }

   if ( printerFound == 0 && (!d4Printer && doIdent) )
   {
      printText("%s\n",lang, "noDetected");
      exit_CB(1);
   }
   if ( printerFound == 0 )
   {
      if ( model )
      {
         printerName = strdup(model);
      }
      else
      {
         printerName = strdup("?");
      }
   }
   
   /* get the printer data from our data base */
   actConfig.name   = printerName;

   if ( ! setConfig(lang) )
   {
      fprintText(stderr,"%s\n",lang, "unknownModel");
      actConfig.name   = printerName;
   }
   data.ptrVal      = actConfig.dev;
   actConfig.dev    = device;

   if ( doIdent )
   {
       if ( printerName )
          printf("%s\n", printerName);
   }

   /* the printer name will be found in printerName */
   if ( doStatus )
   {
loop:
      retBuf = NULL;
      callPrg(GET_IQ, actConfig.dev, actConfig.prot, 0, 0, &retBuf, NULL);
      if ( retBuf != NULL && *retBuf )
      {
         if ( *retBuf == '\0' )
         {
            printerFound = 0;
         }
         else
         {
            if ( decodeStatus((unsigned char*)retBuf, strlen(retBuf), lang) )
            {
               printerFound = 1;
               if ( cycle )
               {
                  sleep(cycle);
                  goto loop;
               }
            }
            else
            {
               printerFound = 0;
            }
         }
      }
      else
      {
         //if ( !actConfig.id || )
         {
            printerFound = 0;
         }
      }

      if ( printerFound == 0 )
      {
         printText("%s\n", lang, "noOPen");
         exit_CB(1);
      }
   }

   if ( doCheck )
   {
      retVal = callPrg(CHECK_NOZZLE, actConfig.dev,actConfig.prot, 0, actConfig.checkNeedReset, NULL, NULL);
   }

   if ( doClean )
   {
      retVal = callPrg(CLEAN_NOZZLE, actConfig.dev,actConfig.prot, 0, 0, NULL, NULL);
   }

   if ( doReset )
   {
      retVal = callPrg(RESET_PRT, actConfig.dev, actConfig.reset, 0, 0, NULL, NULL);
   }
   if ( retVal < 0 )
   {
      retVal = 1;
      printText("%s\n", lang, "noOPen");
   }
   /* from here inter actice functions */

   if ( doAlign )
   {
      alignHeads(lang, actConfig);
   }
   
   if ( doExchangeCartridge )
   {
      exchangeInk(lang, actConfig);
   }

   exit_CB(0);

   return 0;
}


/*******************************************************************/
/* Function percent                                                */
/*                                                                 */
/* translate the value passed as HEX (2 chars) in decimal          */
/*                                                                 */
/* Input: unsigned char *buf The hex value to be translated        */
/*                                                                 */
/* Return: the decimal value according to hex value                */
/*                                                                 */
/*******************************************************************/

int percent(unsigned char *buf)
{
   int val = 0;;
   if ( buf[0] >= '0' &&  buf[0] <= '9' )
      val = (buf[0] - '0') * 16;
   else if ( buf[0] >= 'A' &&  buf[0] <= 'F' )
      val = (buf[0] - 'A' + 10 ) * 16;
   else if ( buf[0] >= 'a' &&  buf[0] <= 'f' )
      val = (buf[0] - 'a' + 10 ) * 16;

   if ( buf[1] >= '0' &&  buf[1] <= '9' )
      val += (buf[1] - '0');
   else if ( buf[1] >= 'A' &&  buf[1] <= 'F' )
      val += (buf[1] - 'A' + 10 );
   else if ( buf[1] >= 'a' &&  buf[1] <= 'f' )
      val += (buf[1] - 'a' + 10 );

   return val;
}

/*******************************************************************/
/* Function colorType                                              */
/*                                                                 */
/* translate the value passed as HEX (1 char) in decimal           */
/*                                                                 */
/* Input: unsigned char *buf The hex value to be translated        */
/*                                                                 */
/* Return: the decimal value according to hex value                */
/*                                                                 */
/*******************************************************************/

int colorType(unsigned char *buf)
{
   int val = 0;;
   if ( buf[0] >= '0' &&  buf[0] <= '9' )
      val = (buf[0] - '0') * 16;
   else if ( buf[0] >= 'A' &&  buf[0] <= 'F' )
      val = (buf[0] - 'A' + 10 ) * 16;
   else if ( buf[0] >= 'a' &&  buf[0] <= 'f' )
      val = (buf[0] - 'a' + 10 ) * 16;

   return val;
}

/*******************************************************************/
/* Function decodeStatus                                           */
/*                                                                 */
/* decode the string returned from printer and print the           */
/* informations in an human readable way                           */
/*                                                                 */
/* Input: unsigned char *buf The String returned from printer      */
/*        int            len Size of string                        */
/*                                                                 */
/* Return: 1 if any info found                                     */
/*                                                                 */
/*******************************************************************/

int decodeStatus(unsigned char *buf, int len, char *lang)
{
   int           i;
   int           infOk = 0;
   char         *s;
   char          code[3];

   int colIdx;

   pb  = 0;
   pc  = 0;
   pm  = 0;
   py  = 0;
   plc = 0;
   plm = 0;
   plb = 0;
   plp = 0;
   plx = 0;

   if ( buf == NULL )
      return infOk;

   for ( i = 0; i < len;)
   {
      if ( strncmp((char*)&buf[i], "ST:", 3 ) == 0 )
      {
         infOk = 1;
         i += 3;
         printerState = "unknown";
         switch( buf[i+1] )
         {
            case '0': printerState = "error";    break;
            case '1': printerState = "selfTest"; break;
            case '2': printerState = "busy";     break;
            case '3': printerState = "printing"; break;
            case '4': printerState = "ok";       break;
            case '7': printerState = "cleaning"; break;
         }
         i +=3;
         printText("\t%-20s:",lang,"printerState");
         printText(" %s\n\n",lang,printerState);
      }
      else if ( strncmp((char*)&buf[i], "ER:", 3 ) == 0 )
      {
         i += 3;
         s = NULL;
         switch( buf[i+1] )
         {
            case '1': s = "interfaceNotSelected"; break;
            case '4': s = "paperJamError";        break;
            case '5': s = "inkOutError";          break;
            case '6': s = "paperOutError";        break;
            default: s = code;
                    code[0] = buf[i];
                    code[1] = buf[i+1];
                    code[2] = 0;
         }
         if ( s )
         {
            printText("\t%s: ", lang, "error");
            printText("%s\n", lang, s);
         }
         i +=3;
      }
      else if ( strncmp((char*)&buf[i], "IQ:", 3 ) == 0 )
      {
         infOk = 1;
         i += 3;
         colIdx = 0;
         while ( i < len && colIdx < 7 && buf[i] != ';' )
         {
            switch(colIdx)
            {
               case 0: pb  = percent(buf+i);
               printText("\t%-20s:",lang,"black");
               printf(" %2d %%\n",pb);
               break;
               case 1: pc  = percent(buf+i);
               printText("\t%-20s:",lang,"cyan");
               printf(" %2d %%\n",pc);
               break;
               case 2: pm  = percent(buf+i);
               printText("\t%-20s:",lang,"magenta");
               printf(" %2d %%\n",pm);
               break;
               case 3: py  = percent(buf+i);
               printText("\t%-20s:",lang,"yellow");
               printf(" %2d %%\n",py);
               break;
               case 4: plc = percent(buf+i);
               printText("\t%-20s:",lang,"lcyan");
               printf(" %2d %%\n",plc);
               break;
               case 5: plm = percent(buf+i);
               printText("\t%-20s:",lang,"lmagenta");
               printf(" %2d %%\n",plm);
               break;
               case 6: plb = percent(buf+i);
               printText("\t%-20s:",lang,"lblack");
               printf(" %2d %%\n",plb);
               break;
            }
            colIdx++;
            i += 2;
         }
      }
#if 1
      else if ( strncmp((char*)&buf[i], "INQ:", 4 ) == 0 )
      {
         char colorModel;
         infOk = 1;
         i += 4;
         colIdx = 0;
         colorModel = buf[i];
         i++;
         while ( i < len && colIdx < 8 && buf[i] != ';' )
         {
            switch(colIdx)
            {
               case 0: pb  = percent(buf+i);
                  printText("\t%-20s:",lang,"black");
                  printf(" %2d %%\n",pb);
               break;
               case 1: pc  = percent(buf+i);
                  printText("\t%-20s:",lang,"cyan");
                  printf(" %2d %%\n",pc);
               break;
               case 2: pm  = percent(buf+i);
                  printText("\t%-20s:",lang,"magenta");
                  printf(" %2d %%\n",pm);
               break;
               case 3: py  = percent(buf+i);
                  printText("\t%-20s:",lang,"yellow");
                  printf(" %2d %%\n",py);
               break;
               case 4: plc = percent(buf+i);
                  if ( colorModel == MODEL_KCMycm  ||
                       colorModel == MODEL_KCMycmY ||
                       colorModel == MODEL_KCMycmGg ||
                       colorModel == MODEL_KCMycmk    )
                      printText("\t%-20s:",lang,"lcyan");
                  else
                      printText("\t%-20s:",lang,"red");
                  printf(" %2d %%\n",plc);
               break;
               case 5: plm = percent(buf+i);
                  if ( colorModel == MODEL_KCMycm ||
                       colorModel == MODEL_KCMycmY ||
                       colorModel == MODEL_KCMycmGg ||
                       colorModel == MODEL_KCMycmk    )
                      printText("\t%-20s:",lang,"lmagenta");
                  else
                      printText("\t%-20s:",lang,"blue");
                  printf(" %2d %%\n",plm);
               break;
               case 6: plb = percent(buf+i);
                  if ( colorModel == MODEL_KCMycmY )
                      printText("\t%-20s:",lang,"dyellow");
                  else if ( colorModel == MODEL_KCMycmk )
                      printText("\t%-20s:",lang,"grey");
                  else if ( colorModel == MODEL_KCMyRBkX )
                      printText("\t%-20s:",lang,"lblack");
                  else if ( colorModel == MODEL_KCMyRBX )
                      printText("\t%-20s:",lang,"gloss");
                  else if ( colorModel == MODEL_KCMycmGg )
                      printText("\t%-20s:",lang,"Lblack");
                  printf(" %2d %%\n",plb);
               break;
               case 7: pb  = percent(buf+i);
                  if ( colorModel == MODEL_KCMyRBkX )
                  {
                     printText("\t%-20s:",lang,"gloss");
                      printf(" %2d %%\n",pb);
                  }
                  else if ( colorModel == MODEL_KCMycmGg )
                  {
                     printText("\t%-20s:",lang,"llblack");
                      printf(" %2d %%\n",pb);
                  }
               break;
            }
            colIdx++;
            i += 2;
         }
      }
#endif
      else
      {
         i++;
      }
   }

   return infOk;
}

/*******************************************************************/
/* Function decodePrinterType                                      */
/*                                                                 */
/* decode the string returned from printer and print the           */
/* informations in an human readable way                           */
/*                                                                 */
/* Input: unsigned char *buf The String returned from printer      */
/*        int            len Size of string                        */
/*                                                                 */
/* Return: -                                                       */
/*                                                                 */
/*******************************************************************/

int decodePrinterType(unsigned char *buf, int len)
{
   char *s = (char*)buf;
   char *t = (char*)buf;
   int   i;

   if ( buf )
   {
      for (i=0; i < len; i++)
      {
         if ( strncmp(s, "DES:", 4) == 0 || strncmp(s, "MDL:", 4) == 0 )
         {
            s +=4;
            t = s;
            while(*t && *t != ';')
               t++;
            *t = '\0';
            printerName = strdup(s);
            *t = ';';
            return 1;
         }
         else
         {
            s++;
         }
      }
   }
   return 0;
}


/*******************************************************************/
/* Function cmpName                                                */
/*                                                                 */
/* Find the printer                                                */
/*                                                                 */
/*******************************************************************/

int cmpName(char *name, char *alias )
{
   name +=7;
   while ( *name || *alias )
   {
      if ( *name == ' ' )
      {
         if (  *alias != '_' )
            return 1;
      }
      else if ( *name != *alias )
         return 1;
      name++;
      alias++;
   }
   return 0;
}

/*******************************************************************/
/* Function setConfig                                              */
/*                                                                 */
/* Find the printer data and fill actConfig                        */
/*                                                                 */
/*******************************************************************/

int setConfig(char *lang)
{
   int retVal = False;
   int i = 0;

   /* if a number was given set name to the proper entry */

   if ( actConfig.name && isdigit(actConfig.name[0]) )
   {
      i = atoi(actConfig.name) - 1;
      if ( i < 0 || i >= defaultConfigDataSize - 1 )
         printSyntax(1, lang);
      actConfig.name = defaultConfigData[i].name;
   }

   /* copy all entries to our actConfig structure */

   if ( actConfig.name )
   {
      for ( ; i < defaultConfigDataSize; i++ )
      {
         if ( strcasecmp(defaultConfigData[i].name,actConfig.name)  == 0 
              || cmpName(defaultConfigData[i].name, actConfig.name) == 0 
            )
         {
            memcpy(&actConfig, &defaultConfigData[i], sizeof(actConfig));
            retVal = True;
            break;
         }
      }
   }

   if ( retVal == False )
   {
      /* set to unknow printer */
      i = defaultConfigDataSize - 1;
      memcpy(&actConfig, &defaultConfigData[i], sizeof(actConfig));
   }
   return retVal;
}

/*******************************************************************/
/* Function alignHeads                                             */
/*                                                                 */
/* align head stuff, depend on printer                             */
/*                                                                 */
/*******************************************************************/

int alignHeads(char *lang, configData_t actConfig)
{
   int   pass;
   int   passes;
   int   command;
   int   choices;
   int   prot;
   int   color;
   int   patternNo;
   char *function = NULL;
   char *blackColor[] = { "blackQ", "colorQ" };
   int   ret;

   /* print warning message */
   printText("%s\n\n", lang, "alignWarning");

   /* ask if this is to be continued */
   printText("%s",lang, "continue");

   if ( ! askYn(lang,"yesorno") )
      return 0;

   if ( actConfig.color_passes )
   {
      printText("\n\n%s\n",lang, "alignBlackOrColor");
      color = askForChoice(lang, blackColor, 2);
   }
   else
   {
      color = 0;
   }
   
   if ( color )
   {
      passes   = actConfig.color_passes;
      function = NULL;
      prot     = actConfig.align;
      choices  = actConfig.color_choices;
      command  = ALIGN_HEAD_C;
   }
   else
   {
      passes   = actConfig.passes;
      function = actConfig.alignFunction;
      prot     = actConfig.align;
      choices  = actConfig.choices;
      command  = ALIGN_HEAD;
   }

   if ( passes > 0 )
   {
      for ( pass = 1; pass <= passes; pass++ )
      {
         /* print message 1 */
         if ( pass == 1 )
         {
            printText("\n\n%s\n",lang, "firstHeadAlign");
         }
         else
         {
            printText("\n\n%s\n",lang, "nextHeadAlign");
         }
 
         for(;;)
         {
            printText("%s",lang, "continue");
            if ( askYn(lang,"yesorno") ) break;
         }
 
         /* and send query for pattern */
         ret = callPrg(command, actConfig.dev, actConfig.align, pass, 0, NULL, function);
         if ( ret == -1 )
         {
            fprintText(stderr,"%s\n",lang,"noOPen");
            return 0;
         }
         /* ask for pattern # */
         printText("\n%s\n",lang, color ? "chooseCPattern" : "choosePattern");
         patternNo = askNo(1,choices);
 
         /* save the pattern number */
         ret = callPrg(command, actConfig.dev, actConfig.align, pass, patternNo, NULL, function);
      }
      /* print pattern 1 to n again */
      printText("\n\n%s\n",lang, "nextHeadAlign");
      for(;;)
      {
         printText("%s",lang, "continue");
         if ( askYn(lang,"yesorno") ) break;
      }
      ret = callPrg(command, actConfig.dev, actConfig.align, actConfig.passes, -1, NULL, function);
 
      printText("\n%s",lang, "lastHeadAlign");
   }
   else if ( passes < 0 )
   {
      /* n passes printed all on the same time, choice = 0 -> print pattern */
      ret = callPrg(command, actConfig.dev, actConfig.align, passes, 0, NULL, function);
      if ( ret == -1 )
      {
         fprintText(stderr,"%s\n",lang,"noOPen");
         return 0;
      }
      patternNo = 0;
      passes    = -passes;
      for ( pass = 0; pass < passes; pass++ )
      {
         /* ask for pattern # */
         printText("\n\n%s", lang, "sampleNo");
         printf("%d\n",pass+1);
         printText("%s", lang, "choosePattern2");
         patternNo |= askNo(1,choices) << (8*pass);
         /* save the pattern number */
      }
      /* choice > 0 -> set correction */
      ret = callPrg(command, actConfig.dev, actConfig.align, -passes, patternNo, NULL, function);
      printText("\n%s",lang, "lastHeadAlign");
   }
   
   /* ask for saving into printer */
   if ( askYn(lang,"saveCancel") )
   {
      /* send save into printer if applicable, choice = 0  and pass > max pass */
      ret = callPrg(command,actConfig.dev, actConfig.align, 4 , 0 , NULL, function);
   }
   callPrg(RELEASE,actConfig.dev,0,0,0,NULL,NULL);
   
   return 1;
}


/*******************************************************************/
/* Function exchangeInk                                            */
/*                                                                 */
/* exchange cartridge for the stylus Color 480 / 580               */
/*                                                                 */
/*******************************************************************/

int exchangeInk(char *lang, configData_t actConfig)
{
   char *choices[] = { "blackQ", "colorQ" };
   int   command;
   char *cmdRet = NULL;
   int   ret;

   if ( actConfig.exchange == False )
   {
      fprintText(stderr,"%s\n", lang, "functionNA");
      return 0;
   }

   /* ask for confimation */
   printText("%s",lang, "askDoExchange");
   if ( ! askYn(lang,"yesorno") )
   {
      return 0;
   }

   /* choose black or color cartridge if applicable */
   if ( actConfig.exchangeSeparate )
   {
      printText("%s\n",lang, "exchangeBlackOrColor");
      if ( askForChoice(lang, choices, 2) )
         command = EXCHANGE_C; /* choice 1 -> color */
      else
         command = EXCHANGE_B; /* choice 0 -> black */
   }
   else
   {
      command = EXCHANGE_ALL;
   }


   /* send command 0  goto exhange position */
   ret = callPrg( command,actConfig.dev, actConfig.prot, 0, 0, &cmdRet, NULL);
   if ( ret == -1 )
   {
      fprintText(stderr,"%s\n",lang,"noOPen");
      callPrg(RELEASE,actConfig.dev,0,0,0,NULL,NULL);
      return 0;
   }

   /* check result */
   if ( cmdRet )
   {
      if ( !(cmdRet[0] == 'x' && cmdRet[1] == 'i' &&
             cmdRet[6] == 'O' && cmdRet[7] == 'K')   )
      {
         fprintText(stderr,"%s\n",lang,"exchangeError");
         callPrg(RELEASE,actConfig.dev,0,0,0,NULL,NULL);
         return 0;
      }
   }
   else
   {
      /* no communication ? */
      fprintText(stderr,"%s\n",lang,"communicationError");
      callPrg(RELEASE,actConfig.dev,0,0,0,NULL,NULL);
      return 0;
   }
 
   /* tell the user that the carrier will go to the desired position */
   printText("%s\n",lang,"adviseMoveCartridge");

   /* wait for exchange position */
   ret = callPrg(EXCHANGE_NEXT, actConfig.dev, actConfig.prot, 1, 0,(char**)&cmdRet, NULL);

   /* tell the user that the cartridge can be exchanged */
   printText("%s\n",lang,"adviseExchangeCartridge");

   /* and ask for continue */
   
   printText("%s",lang, "askExDone");

   if ( ! askYn(lang,"yesorno") )
   {
      /* end the exchange cartridge sequence */
      ret = callPrg(EXCHANGE_NEXT, actConfig.dev, actConfig.prot, 4, 0, NULL, NULL);
      callPrg(RELEASE,actConfig.dev,0,0,0,NULL,NULL);
      return 0;
   }
   
   /* tell that the start exchange ink is called and that this will require some time */
   printText("%s\n",lang,"adviseFillCartridge");

   /* send start exchange ink and wait for ready */
   ret = callPrg(EXCHANGE_NEXT, actConfig.dev, actConfig.prot, 3, 0, (char**)&cmdRet, NULL);

   /* last step send terminate exchange ink */
   ret = callPrg(EXCHANGE_NEXT, actConfig.dev, actConfig.prot, 4, 0, NULL, NULL);
   printText("%s\n",lang,"adviseExchangeDone");

      callPrg(RELEASE,actConfig.dev,0,0,0,NULL,NULL);
   return 1;
}
