/**************************************************************************/
/* TScan (Telenet/Sprintnet Scaner)                                       */
/* Version 0.1 (Very Beta.  Release number #1!                            */
/* By The Beave (beave@vistech.net)                                       */
/* 2000(c)                                                                */
/*                                                                        */
/* For information on "Tscans" use, check the README.TXT that came with   */
/* this,  or check the -h and -e flags                                    */
/*                                                                        */
/* The ideas of this scanner are based on the QBASIC version of TSCAN     */
/* I wrote oh, so many years ago.  There is still much more to do, check  */
/* out the TODO file.                                                     */
/*                                                                        */
/* Any ideas,  or bug you find please e-mail me (beave@vistech.net) or    */
/* telnet/ssh to "bbs.vistech.net" and post them there.                   */
/*                                                                        */
/* This is beta code,  so you're playing with fire.                       */
/**************************************************************************/


#include "tserial.h"	// This was taken from Minicom,  and makes
			// serial programming so much less painful. 
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
 
#define		MAXPATH		255

int portfd;				// Serial port file desc.
FILE *outfd;				// Output file desc.

void closetty(int sig); 
void usage(void);
void version(void);
void examples(void);
void sendmodem(const char *); 



int main(int argc, char **argv)
{
	int c,i,a=0;
	int waitin=0; 			// INT for waiting for input.
	int typedis=0;			// What type of dis d\r, or hangup.
	int connectflag=0;		// our "CONNECT" flag.
	char tty[MAXPATH];
	char baudrate[10];
	int ibaudrate;			// atoi for baudrate
	char parity[10];
	char bits[10];
	int hwhandshake=1;
	int swhandshake=0;
	int ss; 			// for atoi converstion of startscan 
	int es; 			// for atoi converstion of endscan
	char fileout[MAXPATH]="";
	char tmpscanrange[25]="" ;	// Tmp area before out atoi
	char dialup[25]="";		// Our local dialup number
	char startscan[10]="";		// Start Scan
	char endscan[10]="";		// End Scan

	fd_set fds;
	struct timeval tv;
	int buflen;
	char buf[128];
	char scanbuf[128]="";
        char tmpscanbuf[128]="";
	char sendstring[128];		// Commands to be sent to the modem
	

	strcpy(bits		,	"7"	      );
	strcpy(parity		,	"E"	      );
	strcpy(baudrate		,	"38400"	      );
	strcpy(tty		,	"ttyS1"	      );

	/* parse command line  x:x:x - needed xxxx - not need */
	while ((c = getopt (argc, argv, "r:n:t:s:d:p:f:ecvh")) != EOF) 
	  {
	  switch (c)
		{
		case 'h':			// Bah! Help!
			usage(); 
			exit(0);
			break;
		case 'e':
			examples();
			exit(0);
			break;
		case 'v':
			version();		// Get version
			exit(0); 
			break;
		case 't': 
			if (strlen(optarg) > (MAXPATH-1))
			{
			fprintf(stderr, "The tty path is to long!!\n");
			exit(0);
			}
			strcpy(tty, optarg);
			break;
		case 's':
			if (strlen(optarg)>9) 		// Speed
			{
			fprintf(stderr, "What! That baud rate is too long!\n");
			exit(0);
			}
			strcpy(baudrate, optarg);
			break;
		case 'd':				// Data bits
			if (strlen(optarg)>9)
			{
			fprintf(stderr, "Databit too long!\n");
			exit(0);
			}
			strcpy(bits, optarg);
			break;
		case 'p':				// Parity
			if (strlen(optarg)>9)
			{
			fprintf(stderr, "Parity too long! \n");
			exit(0);
			}
			strcpy(parity, optarg);
			break; 
		case 'r':
			if (strlen(optarg)>20)
			{
			fprintf(stderr, "Scan range to large! \n");
			exit(0);
			}
			strcpy(tmpscanrange, optarg);
		case 'c':			// Flow control/Handshaking
			swhandshake=1;
			hwhandshake=0;
			break;
		case 'f': 			// Tscan output file
		      	if (strlen(optarg)>(MAXPATH-1))
			{
			fprintf(stderr, "Tscan Output file path too long!\n");
			exit(0);
			} 
			strcpy(fileout, optarg);
			break;
		case 'n':
			if (strlen(optarg)>25) 
			{
			fprintf(stderr, "Dialup number is to long!\n");
			exit(0);
			}
			strcpy(dialup, optarg); 
			break;
		default:
			usage();
			exit(0);
			break;
			
		}			// End Switch/case
    	}				// End While


if (strcmp(tmpscanrange, "")==0) {
  fprintf(stderr, "Scan range not supplied! Use the -h flag for help.\n");
  exit(0);
  }

if (strcmp(dialup, "")==0) {
  fprintf(stderr, "No dialup number specified! Use the -h flag for help.\n");
  exit(0);
  }

if (strcmp(fileout, "")==0) {
  fprintf(stderr, "No NUA output file specified! Use the -h flag for help.\n");
  exit(0);
  }

sprintf(startscan, "%s", strtok(tmpscanrange, "-")); 
sprintf(endscan, "%s", strtok(NULL, "-")); 

if (strcmp(endscan, "")==0) {
  fprintf(stderr, "Invalid scan range.  For example, \"-r 212000-212999\"\n");
  exit(0);
  }
es=atoi(endscan); ss=atoi(startscan); 

// Test to make sure our starting range is less then our ending range. 
// If not,  assume the user screwed up,  and reverse the two. 

if ( ss > es) 
   {
   fprintf(stderr, "Warning:  Starting range (%d) is less then ending range (%d)!\n", ss, es);
   fprintf(stderr, "          I'm going to assume you want start at %d and end at %d.\n\n", es, ss); 
   ss = atoi(endscan); es = atoi(startscan); 
   }

if ( ss == es) 
  { 
  fprintf(stderr, "Error:  Starting address cannot equal ending address! (%d-%d)\n", ss, es); 
  exit(0); 
  }

// Okay.. Lets open our output file.. Append if it exists,  create it if
// if don't. 

	outfd = fopen(fileout, "a"); 

	if (outfd == NULL)
		{
		fprintf(stderr, "Can't open %s!\n", fileout);
		exit(1);
		}

// Make a nice header for our output file... 

fprintf(outfd, "------------------------------------------------------------------------------\n"); 
fprintf(outfd, "Tscan [%s] - By The Beave (beave@vistech.net)\n", VERSION); 
fprintf(outfd, "Starting Telenet Scan [Range : %d-%d]\n", ss, es); 
fprintf(outfd, "------------------------------------------------------------------------------\n");

   printf("------------------------------------------------------------------------------\n"); 
   printf("Tscan [%s] - By The Beave (beave@vistech.net)\n", VERSION); 
   printf("Starting Telenet/Sprintnet Scan [Range : %d-%d]\n", ss, es);
   printf("------------------------------------------------------------------------------\n");

// Lets open the serial port... 
	
	portfd = open(tty, O_RDWR); 

	if (portfd == -1) 
		{
		fprintf(stderr, "Can't open %s.\n", tty); 
		fprintf(outfd, "Can't open %s.\n", tty); 
		fclose(outfd); 
		exit(1); 
		}

	m_savestate(portfd); 		// Save state. 
	m_setparms(portfd,baudrate,parity,bits,hwhandshake,swhandshake); 
	m_nohang(portfd); 		// ?? Need this 
	m_hupcl(portfd, 1);
	m_flush(portfd); 

	signal (SIGHUP, &closetty); 
	signal (SIGINT, &closetty);
	signal (SIGQUIT, &closetty); 
	signal (SIGTERM, &closetty); 
	signal (SIGABRT, &closetty); 
	
	// Dial the modem.  I give the modem 1 second to adjust to being
	// abruptly opened before I start throwing data at it.
	// Probaby not needed,  but hey.. It gives me a warm fuzzy. 

	sprintf(sendstring, "ATDT%s\r", dialup); 
	sleep(1); 			// Zzzzzzzzz
	sendmodem(sendstring); 
	printf("[Dialing %s/Connecting/Waiting for PAD]\n", dialup); 

// .. And we enter our terminal mode loop... 

while(1)
	{
	tv.tv_sec=1;			// 1 second
	tv.tv_usec=0;

	FD_ZERO(&fds ); 
	FD_SET(portfd, &fds); 
	
	if (select(portfd+1, &fds, NULL, NULL, &tv) > 0)
	    {
	    buflen = read(portfd, buf, 1);  
  	    if (buflen == -1) closetty(-1); 
	    waitin=0;			    // Got data, reset out nodata
					    // counter. 
	    printf("%s", buf); 
		for (i=0; i<strlen(buf); i++)
		  {
		  sprintf(tmpscanbuf, "%c", buf[i]); 

  		    if (iscntrl(buf[i])!=0)		// Control Char
		      {  
		      sprintf(tmpscanbuf, " "); 
		      }
		  

		  if (strcmp(tmpscanbuf, " ")==0)
 		    { 
		    strcpy(scanbuf, ""); 
		    } else {
			strcat(scanbuf, tmpscanbuf); 
			   }

//            Now we start to look for the goodies... 


		if (strcmp(scanbuf, "DIALTONE")==0)
			{
			closetty(-3); 
			}

		if (strcmp(scanbuf, "CONNECT")==0)
		{
                if (connectflag==0)  // If where not already connected.
                  {
		  strcpy(scanbuf, ""); strcpy(buf,"");

		  // We need to know if the user is connecting 
  		  // at high or low speed.  Highspeed requires a 
		  // @/r@/r@/r,  whereas lowspeed is just a couple 
		  // or /r/r/r's. 
		
		  ibaudrate=atoi(baudrate);   
		  sleep(1);		// Let out connection stablize.
					// Probably not needed. 
		      if (ibaudrate >= 2400) 
		      {
		      strcpy(sendstring, "@\r"); 
	              sendmodem(sendstring); 
		      } else { 
		      strcpy(sendstring, "\r"); 
		      sendmodem(sendstring); 
		}
                      connectflag=1;   // We're connect, scan no more. 
                }			// End if connectflag
		}			// End "CONNECT"

		if (strcmp(scanbuf, "CARRIER")==0)
 		   {
		   strcpy(scanbuf, ""); strcpy(buf, ""); 
		   printf("\n[Redialing...]\n"); 
		   sleep(1); 
		   sprintf(sendstring, "ATDT%s\r", dialup); 
		   sendmodem(sendstring); 
                   connectflag=0;
		   }

		if (strcmp(scanbuf, "TERMINAL=")==0)
		   {
		   strcpy(scanbuf, ""); strcpy(buf, "");
		   sprintf(sendstring, "\r"); 
		   sendmodem(sendstring); 
		   }

		if (strcmp(scanbuf, "REFUSED")==0)
		   {
		   strcpy(scanbuf, ""); strcpy(buf, ""); 
		   printf("***REFUSED LOGGED***\n"); 
		   fprintf(outfd, "%d - REFUSED COLLECT CALLS\n", ss-1); 
		   }

		if (strcmp(scanbuf, "REVERSE")==0) 
		   {
		   strcpy(scanbuf, ""); strcpy(buf, ""); 
		   printf("***REVERSE LOGGED***\n"); 
		   fprintf(outfd, "%d - REVERSE CHARGES NOT SUBSCRIBED\n", ss-1);
		   }

                if (strcmp(scanbuf, "BARRED")==0)
                   {
                   strcpy(scanbuf,""); strcpy(buf, ""); 
                   printf("\n***ACCESS BARRED LOGGED***\n"); 
                   fprintf(outfd, "%d - ACCESS BARRED\n", ss-1); 
                   }

		if (strcmp(scanbuf, "@")==0)
		   {
		   if (a==0) {		// If we're disconnecting, ignore
				  	// the next @ from the PAD. 
		      typedis=0; 	// In case we where trying to dis.
		      strcpy(scanbuf, ""); strcpy(buf,"");
		      sprintf(sendstring, "%d\r", ss); 
		      sendmodem(sendstring); 
		      ss++;
		        if (ss == es)
                        {
                        closetty(-4); 
	                }
	             } 
                   a=0;
		   }

		if (strcmp(scanbuf, "CONNECTED")==0)
		   {
		   a=1;  // Flag,  so we avoid the next @ from PAD
		   strcpy(scanbuf, ""); strcpy(buf, ""); 
		   printf("\n***CONNECTED LOGGED ***\n"); 
		   fprintf(outfd, "%d - CONNECTED\n", ss); 
		   sprintf(sendstring, "@\r"); 	
		   sendmodem(sendstring); 
		   sleep(1);		// Wait for PAD
		   sprintf(sendstring, "d\r");  
		   sendmodem(sendstring); 
		   }



		}
		
            }

//  If we see not data for 1 minutes,  and we're still connected, send 
//  a @\r then a d\r (to the PAD) to request disconnect.  If that doesn't
//  work,  hangup the modem and redialin. 

	waitin++;
	if (waitin == 60)
        {
        if (typedis == 0)    // Send the @\r, d\r.
           {
           printf("\n[Timeout wait on PAD prompt, sending disconnect to PAD]\n");
	   typedis=1; 			// Incase this don't work
	   sprintf(sendstring, "@\r");
           sendmodem(sendstring); 
	   sleep(1);			// wait for the PAD
	   sprintf(sendstring, "d\r");  // Issue disconnect
           sendmodem(sendstring); 
           waitin=0; 
           } else {                     // Must not have work, redial. 
             printf("[PAD disconnect fail,  hangup/redialing]\n"); 
	     m_dtrtoggle(portfd); 	// DTR hangup.
             strcpy(sendstring, "+++");   
             sendmodem(sendstring); 
             sleep(5);			// just to be safe. 
             strcpy(sendstring, "ATH\r"); 
             sendmodem(sendstring);
	     sleep(1);
             sprintf(sendstring, "ATDT%s\r", dialup); 
             connectflag=0;
             sendmodem(sendstring); 
             waitin=0; typedis=0; connectflag=0; 
           }
        }
   }
exit(0);				// Should never make it this far. 
}					// End Main

void closetty(int sig)
{
	switch(sig) {
	case -1:
	fprintf(stderr, "Error reading tty. Closing serial port!\n");
	fprintf(outfd, "Error reading tty. Closing serial port!\n"); 
	break;
	case -2:
	fprintf(stderr, "Write error on output. Closing serial port!\n");
	fprintf(outfd, "Write error on output.  Closing serial port!\n");
	m_dtrtoggle(portfd);
	break;
  	case -3: 
	fprintf(stderr, "[No Dialtone! Closing serial/output!]\n"); 
	fprintf(outfd,  "[No Dialtone! Closing serial/output!]\n"); 
        break;
	case -4: 
	printf("\n---[Scanning Complete]--------------------------------------------------------\n"); 
	fprintf(outfd, "---[Scanning Complete]--------------------------------------------------------\n"); 
	break;
	default:
	m_dtrtoggle(portfd); 
	fprintf(stderr, "Got signal %d. Hanging up and closing serial port!\n", sig);
	fprintf(outfd, "Got signal %d.  Hanging up and closing serial port!\n", sig);
 	// Make sure we hangup.. 
	break;
        }

	m_restorestate(portfd);
	fclose(outfd); 
	close(portfd);
	exit(0);
}

void version(void)
{
	fprintf(stdout, "\nTScan [Telenet Scanner] [%s] by Beave (beave@vistech.net)\n\n", VERSION);
}


void usage(void)
{
	fprintf(stderr, "\nTscan [Telenet Scanner] Version %s  - By The Beave (beave@vistech.net)\n\n", VERSION); 
	fprintf(stderr, " usage: tscan [parameters] -r [NUA Range] -n [Dialup #] -f [Output File]\n");
	fprintf(stderr, "\tOptional parametters:\n");
	fprintf(stderr, "\t\t -h  :  Prints this screen\n");
	fprintf(stderr, "\t\t -e  :  Prints some example usages\n");
	fprintf(stderr, "\t\t -v  :  Prints version of Tscan\n");
	fprintf(stderr, "\t\t -s  :  Speed/Baud rate [default 38400]\n");
	fprintf(stderr, "\t\t -p  :  Parity (None/Even/Odd) [default 'E'ven]\n");
	fprintf(stderr, "\t\t -d  :  Data bits [default 7]\n"); 
	fprintf(stderr, "\t\t -t  :  tty to use (modem) [default /dev/ttyS1]\n");
	fprintf(stderr, "\t\t -c  :  Use software handshaking (XON/XOFF)\n\t\t\t[default is hardware flow control]\n");
	fprintf(stderr, "\t\t -f  :  File to store \"CONNECTED\" systems.\n");
	fprintf(stderr, "\t\t -r  :  Range to scan (ie - 212000-212999)\n");
	fprintf(stderr, "\t\t -n  :  Local Sprintnet/Telenet dialup number.\n\n");
	
}

void examples(void) 
{
	fprintf(stderr, "Tscan [Telenet Scanner] [%s] - By The Beave [beave@vistech.net]\n\n", VERSION);

	fprintf(stderr, "\t These options are required!\n");

	fprintf(stderr, "\t\t -r Range.  This tells the scanner what range of\n\t\t    NUA's you wish to scan. For example,
\t\t    -r212000-212999\n");

	fprintf(stderr, "\t\t -n Local dialup number.  To get this,  read the\n\t\t    the documenation that came with this program.\n");

	fprintf(stderr, "\t\t -f Output/Log file.  This stores systems NUA's that\n\t\t    where found (ie - \"-f /tmp/212-NUA.txt\"\n");

	fprintf(stderr, "\n\n\tSome brief command line examples:\n\n");
	fprintf(stderr, "\ttscan -r 212000-212500 -n 5551212 -f 212NPA.txt\n");
	fprintf(stderr, "\ttscan -r 909000-909100 -n 5551212 -f 909.txt -t /dev/ttyS0\n"); 
	fprintf(stderr, "\ttscan -r 90400-90499 -n 5551212 -f 90400.txt -s 2400\n\n"); 
	fprintf(stderr, "See the README file that came with this program for more info\n\n"); 

}

void sendmodem(const char *sendstring)
{
write(portfd, sendstring, strlen(sendstring)); 
}
