  /***********************************************************************
   *              Down and Dirty MeSsyDOS IRC Client                     *
   *              Version 0.8 ALPHA                                      *
   *                                                                     *
   *              by zorgo <zorgo@gnu.ai.mit.edu>                        *
   *                                                                     *
   *  Written with Turbo C++ 1.00                                        *
   *                                                                     *
   *  Down and Dirty MeSsyDOS IRC Client is GNU Copylefted.              *
   *                                                                     *
   *  ASYNC Comm routines leeched from a Public Domain package by        *
   *  David Kessner <david@kessner.denver.co.us>                         *
   ***********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <process.h>
#include "ddm.h"
#include "async.h"

/*********************************************************************/
int	main( argc, argv)
int argc;
char *argv[];
{
    register int i;

	if( argc > 1 ) {
		for(i=0; i<argc; i++) {
			if( strcmp(argv[i], "-e")==0 )           { n81=0; }
			else if( strcmp(argv[i], "-n")==0 )      { n81=1; }
			else if( strcmp(argv[i], "-c1")==0 )     { comport=0; }
			else if( strcmp(argv[i], "-c2")==0 )     { comport=1; }
			else if( strcmp(argv[i], "-c3")==0 )     { comport=2; }
			else if( strcmp(argv[i], "-c4")==0 )     { comport=3; }
			else if( strcmp(argv[i], "-b57600")==0 ) { baudrate=57600; }
			else if( strcmp(argv[i], "-b38400")==0 ) { baudrate=38400; }
			else if( strcmp(argv[i], "-b19200")==0 ) { baudrate=19200; }
			else if( strcmp(argv[i], "-b9600" )==0 ) { baudrate=9600; }
			else if( strcmp(argv[i], "-b4800" )==0 ) { baudrate=4800; }
			else if( strcmp(argv[i], "-b2400" )==0 ) { baudrate=2400; }
			else if( strcmp(argv[i], "-b1200" )==0 ) { baudrate=1200; }
			else if( strcmp(argv[i], "-b300"  )==0 ) { baudrate=300; }
			else if( strcmp(argv[i], "-t")==0 )      { terminal=1; }
			else if( strcmp(argv[i], "-i")==0 )      { terminal=0; }
			else if( strcmp(argv[i], "-d")==0 )      { login=0; terminal=0; }
			else if( strcmp(argv[i], "-h")==0 || strcmp(argv[i], "-?")==0 ) {
				printf("\n\nDown and Dirty MeSsyDOS IRC Client\n");
				printf("by zorgo <zorgo@gnu.ai.mit.edu>\n\n");
				printf("USAGE: %s -option\n", argv[0]);
				printf("OPTIONS:\n");
				printf("  -n         Use N81 to connect (default)\n");
				printf("  -e         Use E71 to connect\n");
				printf("  -c#        What COM port to use (#= 1,2,3 or 4) -c2 is default\n");
				printf("  -b#        What BAUD to use: #= 57600 (default), 38400, 19200, 9600, etc\n");
				printf("  -t         Make DDM start as a terminal (default)\n");
				printf("  -i         Do not make DDM start as a terminal\n");
                printf("  -d         No terminal, no login info sent\n");
				printf("  -? or -h   This help display\n\n");
                exit(1);
			}
	    }
	}

  	intro();
	init();
	if(terminal) do_terminal();
	do_irc();
	clean_exit();
}

/*********************************************************************/
do_irc()
{

    do_status_line();

	if(login) login_irc();

    while(1) {
		get_from_modem();
		get_from_keyboard();
	   	check_buffer_overflow();
	}
}

/*********************************************************************/
get_from_keyboard()
{
	char d;
    register int i;

	if( kbhit() ) {								/*  If a key hit */
        d=getch();
        if( d==0 ) {
			check_Fkeys();
		} else if( d==8 ) {	  					/* Backspace Kluge */
			INPUT_WINDOW;
            dbuff[ strlen(dbuff)-1 ] = NULL;
			clrscr();
            cprintf("%s", dbuff);
		} else if( d == 13 ) {  				/* Luser hit CR */
			local_parse(dbuff);					/* Parse Luser stuff */
    	    for(i=0; i<MAX; i++)                /* Clear input buffer */
	        	dbuff[i]=NULL;
	        INPUT_WINDOW; clrscr();             /* Clear input window */
		} else {                    			/* Just another character */
			INPUT_WINDOW;
	       	dbuff[ strlen(dbuff) ] = d;         /* Add new to out buff */
			cprintf("%s", dbuff);
		}
    }
}

/*********************************************************************/
get_from_modem()
{
	register int c, i;

	if( (c=AsyncIn()) !=0 ) {			/* Character received */
		if( c==10 ) {  					/* End of Line from Server */
			parse(mbuff);
            for(i=0; i<MAX; i++)
            	mbuff[i]=NULL;
		}
		else {
	        mbuff[ strlen(mbuff) ] = c;         /* Add new to out buff */
		}
	} 
}

/*********************************************************************/
ssend( out )
char *out;
{
	register int i=0;

	/* if(debug) {DEBUG_WINDOW; cprintf(">>>ssend out=%s|\r\n", out); } */

	while( out[i] != NULL ) AsyncOut( out[i++] );

    if ( out[ strlen(out)-1 ] != 13) AsyncOut( 13 );     /* "\n" */
}



/*********************************************************************/
local_parse( line )
char *line;
{
	char orig_line[MAX];

    if( line[0] == NULL )  return 0;

	/* if(debug) {DEBUG_WINDOW; cprintf(">>>LOCAL_PARSE=%s|\r\n",line);} */

	strcpy(orig_line, line);

	if( line[0]==47 ) {
		strcpy(buff, strtok(&line[1], " "));
		sprintf(type, "%s", toup(buff));

		/* if(debug) {	DEBUG_WINDOW; cprintf(">>> / type=%s|\r\n", type); } */

		if( strcmp( type, "JOIN")==0 || strcmp(type, "J")==0 ) {

			strcpy(current_channel, strtok(NULL, " "));
			sprintf(buff, "JOIN %s\n", current_channel);
			ssend(buff);
		    do_status_line();
			return 1;
		}
	    else if (strcmp( type, "PART")==0) {
			strcpy(buff2, strtok(NULL, " "));
			sprintf(buff, "PART %s\n", buff2);
			ssend(buff);
			return 1;
		}
		else if( strcmp( type, "NICK")==0 ) {
			 strcpy(current_nick, strtok(NULL, " "));
			 sprintf(buff, "NICK %s\n", current_nick);
			 ssend(buff);
             do_status_line();
             return 1;
		}
		else if( strcmp(type, "CLEAR")==0 ) {
			clear_all_windows();
            do_status_line();
            return 1;
		}
		else if( strcmp(type, "MSG")==0 || strcmp(type, "M")==0 ) {
			strcpy(to, strtok(NULL, " "));
			strcpy(message, strtok(NULL, NULL));
			if(lame) {
				lamerize(message, buff);
				sprintf(message, buff);
			}
			sprintf(buff, "PRIVMSG %s %s\n", to, message);
			ssend(buff);
			OUTPUT_WINDOW;
			cprintf("-> *%s* %s\r\n", to, message);
			return 1;
		}
		else if( strcmp(type, "QUOTE")==0 || strcmp(type, "Q")==0 ) {
			strcpy(buff, strtok(NULL, NULL));
			ssend(buff);
			return 1;
		}
		else if( strcmp(type, "WHO")==0 ) {
			sprintf(buff, "WHO %s", strtok(NULL, NULL));
			ssend(buff);
			return 1;
		}
		else if( strcmp(type, "LUSERS")==0 ) {
			ssend("LUSERS");
			return 1;
		}
		else if( strcmp(type, "MOTD")==0 ) {
			ssend("MOTD");
			return 1;
		}
		else if( strcmp(type, "WHOIS")==0 ) {
			sprintf(buff, "WHOIS %s", strtok(NULL, NULL));
			ssend(buff);
			return 1;
		}
		else if( strcmp(type, "LIST")==0 ) {
			sprintf(buff, "LIST %s", strtok(NULL, NULL));
			ssend(buff);
			return 1;
		}
		else if( strcmp(type, "STAT")==0 || strcmp(type, "STATUS")==0 || strcmp(type, "STATS")==0 ) {
			sprintf(buff, "STATS %s", strtok(NULL, NULL));
			ssend(buff);
			return 1;
		}
		else if( strcmp(type, "TIME")==0 ) {
			ssend("TIME");
		}
		else if( strcmp(type, "QUIT")==0 || strcmp(type, "SIGNOFF")==0 ) {
            /* ssend("QUIT");  huh? */
			clean_exit();
		}
		else {
			OUTPUT_WINDOW;
			cprintf("*** Unknown Command: %s\r\n", orig_line);
			return 0;
		}
	}
	else {   								/* no /, TO CHANNEL! */
		if( current_channel[0]==NULL ) {  /* bogus */
			OUTPUT_WINDOW;
			cprintf("*** You are not on a channel, nowhere to send!\r\n");
		}
		if(lame) {
			lamerize(orig_line, buff);
			strcpy(orig_line, buff);
		}
		sprintf(buff, "PRIVMSG %s %s\n", current_channel, orig_line);
		ssend(buff);
		OUTPUT_WINDOW;
		cprintf("> %s\r\n", orig_line);
	}
}

/*********************************************************************/
parse( line )
char *line;
{
	int from_server=0;
	int type_check;
	char orig_line[MAX], user[10], host[50];

	strcpy(orig_line, line);

	from[0]=type[0]=to[0]=message[0]=nick[0]=NULL;

	/* if(debug) {DEBUG_WINDOW; cprintf(">>>PARSE=%s|\r\n",line);} */

	if( strnicmp(line, ":", 1)==0 ) {					/*  first is :  */
		strcpy(from, strtok(line, " "));
		strcpy(type, strtok(NULL, " "));
		strcpy(to, strtok(NULL, " "));
		strcpy(message, strtok(NULL, NULL));

	    /* if(debug){DEBUG_WINDOW;cprintf(">>> from   = %s|\r\n", from);cprintf(">>> type   = %s|\r\n", type);   cprintf(">>> to     = %s|\r\n", to);        cprintf(">>> message= %s|\r\n", message);}  */

		if( strstr( from, "!") == NULL ) {
			from_server = 1;
		} else {
			strcpy(nick, strtok(from, "!"));
			strcpy(user, strtok(NULL, "@"));
			strcpy(host, strtok(NULL, NULL));
		}

  		if( strcmp( type, "NOTICE") == 0 ) {
			if(from_server) {
				OUTPUT_WINDOW;
				cprintf("*** %s\r\n", &message[1]);
                return 1;
			}
			else {
				if( strcmp( &nick[1], "NickServ")==0) return 1; /* I FUCKING HATE NICKSERV!!!!!! */
				OUTPUT_WINDOW;
				cprintf("-%s:%s- %s\r\n", to, &nick[1], &message[1]);
                return 1;
            }
		}
		else if( strcmp( type, "PRIVMSG") ==0 ) {
			OUTPUT_WINDOW;
			if(strcmp(to, current_channel)==0)
				cprintf("<%s> %s\r\n", &from[1], &message[1]);
            else if(strcmp(to, current_nick)==0)
                cprintf("*%s* %s\r\n", &from[1], &message[1]);
            else
				cprintf("<%s:%s> %s\r\n", &from[1], to, &message[1]);
            return 1;
		}
		else if( strcmp( type, "JOIN")==0 ) {
			OUTPUT_WINDOW;
			cprintf("*** %s (%s@%s) has joined %s\r\n", &nick[1], user, host, to);
            return 1;
		}
		else if( strcmp( type, "PART")==0 ) {
			OUTPUT_WINDOW;
			cprintf("*** %s has left %s\r\n", &nick[1], to);
            return 1;
		}
		else if( strcmp( type, "NICK")==0 ) {
			OUTPUT_WINDOW;
			cprintf("*** %s changed nick to %s\r\n", &nick[1], to);
            return 1;
		}
		else if( strcmp( type, "MODE")==0 ) {
			OUTPUT_WINDOW;
			cprintf("*** Mode %s on %s by %s\r\n", message, to, &nick[1]);
            return 1;
		}
		else if( strcmp( type, "QUIT")==0 ) {
			OUTPUT_WINDOW;
			cprintf("*** signoff %s (%s %s)\r\n", &nick[1], &to[1], message);
            return 1;
		}
		else if( isdigit( type[0] ) ) {    /* Numerics */
			parse_numeric( type, to, message );
	        return 1;
		}
		else {
			OUTPUT_WINDOW;
			cprintf("?:? %s\r\n", orig_line);
            return 1;
		}
	}
	else {
		strcpy(type, strtok(line, " "));
		strcpy(to, strtok(NULL, " "));
		strcpy(message, strtok(NULL, NULL));

		if( strcmp( type, "PING")==0 ) {
            ssend("PONG DDM_CLIENT\n");
            return 1;
        }
		else if( strcmp( type, "NOTICE")==0 ) {
			OUTPUT_WINDOW;
			cprintf("*** %s\r\n", &message[1]);
            return 1;
		}
        else {
			if(debug) {
				DEBUG_WINDOW;
			    cprintf("?*? %s\r\n", orig_line);
			}
	   		return 1;
	    }
 	}
}

/*********************************************************************/
parse_numeric( c_numeric, c_to, c_message )
char *c_numeric, *c_to, *c_message;
{
	int numeric;
	char channel[MAX], user[10], host[50], server[50], nick[10],
		 status[5], ticks[5], name[MAX];

	numeric = atoi( c_numeric );
	/* if(debug) { DEBUG_WINDOW; cprintf(">>> NUMERIC %i\r\n", numeric); } */

	OUTPUT_WINDOW;
	switch( numeric ) {
		case 315:	cprintf("*** End of /who list\r\n");
					break;
		case 352:   /* WHO output */
					strcpy(channel, strtok(c_message, " "));
					strcpy(user, strtok(NULL, " "));
					strcpy(host, strtok(NULL, " "));
					strcpy(server, strtok(NULL, " "));
					strcpy(nick, strtok(NULL, " "));
					strcpy(status, strtok(NULL, " "));
					strcpy(ticks, strtok(NULL, " "));
					strcpy(name, strtok(NULL, NULL));
					cprintf("%10s %8s %s %s@%s (%s)\r\n",
						channel, nick, status, user, host, name);
					break;
		case 401:   /* No such Nick */
					strcpy(channel, strtok(c_message, " "));
					strcpy(name, strtok(NULL, NULL));
					cprintf("*** `%s' %s\r\n", channel, name);
					break;
		case 421:	/* Unkown command */
					strcpy(channel, strtok(c_message, ":"));
					strcpy(name, strtok(NULL, NULL));
					cprintf("*** `%s' %s\r\n", channel, name);
					break;
		default:	cprintf(":N? %i %s %s\r\n", numeric, c_to, c_message );
					break;
	}
}

/*********************************************************************/
do_status_line()
{
  	STATUS_LINE; clrscr();
	if(lame) {
		lamerize("Down and Dirty MeSsyDOS IRC Client", buff);
		sprintf(buff2, "*** c=%s n=%s     %s",
		current_channel, current_nick, buff);
		cprintf(buff2);
	} else {
	    sprintf(buff, "*** c=%s n=%s     Down and Dirty MeSsyDOS IRC Client", current_channel, current_nick);
	    cprintf(buff);
	}
}

/*********************************************************************/
check_Fkeys()
{
	register int k;

	k = getch();

	if( k==0x3b ) {						 	/* F1 Macro */
		debug_info();
		return 1;
	}	
	if( k==0x3c ) {							/* F2, toggle debug */
		if(debug)
		  {	debug=0; DEBUG_WINDOW; cprintf("DEBUG is now OFF\r\n"); }
		else
		  {	debug=1; DEBUG_WINDOW; cprintf("DEBUG is now ON\r\n"); }
		return 1;
	}
	if( k==0x3d ) {							/* F3, Go back to Terminal */
		do_terminal();
        do_status_line();
		return 1;
	}
	if( k==0x3e ) {							/* F4, Toggle LAME */
		if(lame) {
			lame=0;
			if(debug) { DEBUG_WINDOW; cprintf("LAME is now OFF\r\n"); }
		} else {
			lame=1;
			if(debug) { DEBUG_WINDOW; cprintf("LAME is now ON\r\n"); }
		}
		do_status_line();
		return 1;
	}
	if( k==0x44 ) clean_exit(); 	    	/* Exit if it is F10 */

}


/*********************************************************************/
login_irc()
{
	char *ircname, *ircnick, *ircuser;

    ircname=getenv("IRCNAME");
	ircnick=getenv("IRCNICK");
	ircuser=getenv("IRCUSER");

	if( ircuser == NULL && ircname == NULL )
	    sprintf(buff, "user %s 0 0 %s\n", DDM_IRCUSER, DDM_IRCNAME);
	else if( ircuser == NULL && ircname != NULL)
		sprintf(buff, "user %s 0 0 %s\n", DDM_IRCUSER, ircname);
	else
		sprintf(buff, "user %s 0 0 %s\n", ircuser, ircname);
	ssend(buff);

	if( ircnick == NULL ) {
		sprintf(buff, "nick %s\n", DDM_IRCNICK);
		strcpy(current_nick, DDM_IRCNICK);
	}
	else {
		sprintf(buff, "nick %s\n", ircnick);
		strcpy(current_nick, ircnick);
	}
    ssend(buff);

    do_status_line();
}


/*********************************************************************/
init()
{

	if( AsyncInit( comport ) )	{
    	FULL_SCREEN; clrscr();
		printf("Error initalizing COM Port %i\n", comport);
		exit(-1);
	}
	if(n81) {
		AsyncSet( baudrate, N81_COM_SETTINGS );
	} else {
		AsyncSet( baudrate, E71_COM_SETTINGS );
    }
	AsyncHand( DTR | RTS );
	AsyncClear();
}

/*********************************************************************/
void cls( int lines )
{
	register int i;
	for(i=0; i<lines; i++)
		cprintf("\r\n");
}

/*********************************************************************/
intro()
{
	FULL_SCREEN;
	clrscr();
	window(5,5,75,20);
	textbackground(CYAN);
	clrscr();
	window(10,10,70,15);
	textbackground(BLACK); 	textcolor(GREEN);
	clrscr();
    highvideo();
	cprintf("\r\n\r\n");
	cprintf("            Down and Dirty MeSsyDOS IRC Client\r\n\r\n");
	cprintf("                        by zorgo\r\n");
	normvideo();
	beep();
	FULL_SCREEN;
	gotoxy(5,24);
	cprintf("At anytime press F10 to quit\r\n");
	cprintf("    Press any key to begin...");
	getch();
	clear_all_windows();
}

/*********************************************************************/
beep()
{
	sound(140);  delay(10);  sound(340);   delay(20);
	sound(440);  delay(10);  sound(660);   delay(20);
	sound(860);  delay(10);  sound(1060);  delay(20);
	sound(70);   delay(50);  sound(1090);  delay(10);
	nosound();
}


/*********************************************************************/
do_terminal()
{
	register int c;
	STATUS_LINE;
	cprintf("*** You are in Terminal Mode, F1 to start parsing IRC or F10 to exit");

	DEBUG_WINDOW;
    cls(3);
	cprintf("You have been dropped to Terminal Mode.\r\n");
	cprintf("Connect to a Server By Any Means Necessary!!\r\n");
	cprintf("Press F1 after connection achieved.\r\n");
	cprintf("Press F10 to quit.\r\n");

	OUTPUT_WINDOW;
	while(1) {
	
		/*	If a character was recieved, print it to the console */
		if( (c=AsyncIn())!=0)
			putch(c);

		if( kbhit() ) {                 /*	If a key has been pressed	*/
			c=getch();
			if( c==0) {					/* Check for 'extended characters */
				c=getch();				/* Get the extended code */
				if( c==0x3b) {			/* Exit Terminal if F1 */
                	beep();
					break;
				}
				if( c==0x44) { clean_exit(); }	 /* Quit if F10 */	
			}
			else AsyncOut(c);
		}
		check_buffer_overflow();
	}
	clear_all_windows();
}

/*********************************************************************/
clear_all_windows()
{
	OUTPUT_WINDOW;  clrscr();
    if(debug) { DEBUG_WINDOW;  clrscr(); }
	INPUT_WINDOW;	clrscr();
	STATUS_LINE;	clrscr();
}

/*********************************************************************/
check_buffer_overflow()
{
	/*	If the buffer has a lot in it, drop RTS and empty the buffer */
		if( AsyncInStat()>4096)	{
			DEBUG_WINDOW; puts("ERROR: Buffer overflow, dumping\r\n");
			AsyncHand(DTR);					/* Drop RTS */
			while( AsyncInStat()>0)
				putch( AsyncIn() );
			AsyncHand( DTR | RTS);
		} 
}

/*********************************************************************/
debug_info()
{
	DEBUG_WINDOW;
	cprintf(">>> debug=%i, lame=%i AsyncInStat=%i, _channel=%s| _nick=%s|\r\n",
	    debug, lame, AsyncInStat(), current_channel, current_nick);
  	cprintf(">>> dbuff=%s| strlen=%i\r\n", dbuff, strlen(dbuff));
}

/*********************************************************************/
/* char *   */  toup(str)                     /* convert a string to uppercase */
char *str;
{
   char *start;
   start = str;
   while (*str) {
      if (islower(*str))
         *str = toupper(*str);
      str++; }
   return(start);
}

/*********************************************************************/
int any2dec(str,radix)           /* convert string to integer, not used yet*/
char *str;
unsigned int radix;
{
   unsigned int digit, number = 0;
   while (*str) {
      if (isdigit(*str)) digit = *str - '0';
      else if (islower(digit)) digit = *str - 'a' + 10;
      else digit = *str - 'A' + 10;
      number = number * radix + digit;
      str++; }
   return(number);
}

/*********************************************************************/
clean_exit()
{
	beep();
	FULL_SCREEN;
	textbackground(BLACK); textcolor(GREEN);
	clrscr();
	cprintf("Thanks for using DDM IRC Client\r\n\r\n\r\n");
	AsyncStop();
	exit(1);
}

/****  END OF DDM   ****/
