/* cidread.c
   Copyright (C) 1999 Petter Cederqvist (petter.cederqvist@usa.net).
   Based on the work of Nicklas Björk 1999 (hermann@flashback.net).
   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 <stdio.h>
#include <unistd.h>
#include <asm/io.h>
#include <string.h>

#define BUFSIZE       50    /* Size of buffer holding incoming data               */
#define TIMEOUT       1800  /* Abort reading of number after this many millisecs  *
			     * have passed since recieving the last data.         *
			     * Spec. says 1800 millisecs.                         */
#define POLL_INTERVAL 45    /* Interval at which we poll for new data on the port *
			     * Spec says ~48 millisecs                            */
#define BOT           'A'   /* Data indicating beginning of transmission          */
#define EOT           'C'   /* Data indicating end of transmission                */

#define PORT_BASE     0x378 /* Base address for port. 0x3bc = /dev/lp0            *
			     *                        0x378 = /dev/lp1            *
                             *                        0x270 = /dev/lp2            */

int printNewLine = 0; /* If true (== 1), print a newline after the number */


/* Read one char from lpt */
static inline char readChar(short port)
{
  char* chars = "890*#ABCA1234567";
  int raw;
  
  raw = (inb(port) & 0xf0) >> 4 ;
  return chars[raw];
}

/* Check for data on port */
static inline int dataOnPort(short port)
{
  return( ~inb(port) & 0x08 );
}

/* Print phonenumber */
void printNumber(char* number) 
{
  char* rpos;
  char* wpos;
  char tmpbuf[BUFSIZE];
  
  /* Copy numerical chars to tmpbuf */
  rpos=number;
  wpos=tmpbuf;

  while(*rpos != '\0') {
    if(*rpos >= '0' && *rpos <= '9')
      *wpos++=*rpos;
    
    rpos++;
  }
  *wpos='\0';

  printf("%s", tmpbuf);
  if(printNewLine)
    printf("\n");
}
                
/* Read from port until the buffer is full, an EOT is recieved or   *
 * the timeout limit is reached.                                    *
 * NOTE: All characters, including controlcharacters will be put in *
 *       the buffer. It may be a good idea not to show those to the *
 *       user.                                                      */
int readNumber(char* numBuf, int buflen)
{
  int bufpos = 0;
  char data;
  int to_loops = TIMEOUT/POLL_INTERVAL;

  while(1) {
    if(dataOnPort(PORT_BASE+1)) {
      to_loops = TIMEOUT/POLL_INTERVAL;
      data = readChar(PORT_BASE+1);

      /* Only accept BeginningOfTransmission in position 0 *
       * NOTE: Protected numbers start with 'B' and will   *
       *       therefor not be detected. If you don't like *
       *       this behavior simply change the if-clause.  */
      if(bufpos || BOT == data) {
	
	numBuf[bufpos++] = data;
	numBuf[bufpos] = '\0';        
	
	if(EOT == data)          /* EOT recieved */
	  return bufpos;
	
	if(bufpos >= (buflen-1)) /* Buffer full  */
	  return bufpos;
      }

      /* Wait for data-indication to drop. This occurs while the next character *
       * is recieved. Return if the timeout is reached.                         */
      while(dataOnPort(PORT_BASE+1)) {
	if(bufpos) {             /* First character cannot timeout */
	  to_loops--;
	  if(0 > to_loops)
	    return bufpos;
	}
	usleep(POLL_INTERVAL);
      }
    }
    else
      usleep(POLL_INTERVAL);
  }
}

int main(int argc, char **argv)
{
  char number[BUFSIZE];

  /* Get permissions for the port */
  if(ioperm(PORT_BASE, 2, 1)) {
    fprintf(stderr,"Cannot open device, ioperm error.\n");
    exit(1);
  }
  
  /* Drop privileges */
  setuid(getuid());

  /* Print warning if still running as root */
  if(!geteuid())
    fprintf(stderr, "WARNING: Running as superuser\n");

  /* Initialize port */
  outb(0x26, PORT_BASE);

  if(argc > 1) 
    if(!strcmp(argv[1], "-n"))
      printNewLine = 1;

  while(!readNumber(number, BUFSIZE))
    /* Do nothing */;
  
  printNumber(number);
}

