/*	to make most:	gcc -o irc smallirc.c -ltermcap
                        or cc -o smallirc smallirc.c -ltermcap
	under aix:	bsdcc -o smallirc smallirc.c -lcurses
	under hpux:	cc -o smallirc smallirc.c -lcurses

	PLEASE CHANGE THE DEFAULT SERVER TO ONE NEAR YOU

  Smallirc 1.0 - based on tinyirc.c by Nathan Laredo
                                       (nathan@eas.gatech.edu)

  Developed by  Mandar Mirashi (mmmirash@mailhost.ecn.uoknor.edu) 
                13/2/1994
  
  This is a beta release.

  New features / bugs fixed:
  * all commands made compatible with the 2.8 ':' syntax
  * handles multiple channels
  * reverse video status line, made status line more ircII'ish
  * played around with termcap to better format backspacing on input line
  * intelligent handling of excessively long private/public messages
  * New commands added:
      /me        /leave      /away      /whowas     /ping  
      /signoff   /topic      /clear     /server     /query
      /say       /help       /version   
  * /ignore coded in
  * shorthands /w (whois)  /m (msg)  /si (signoff) /n (notice) /j (join)
    added
  * /msg .   and  /msg ,  support added
  * Beautified numeric replies for motd, whois,whowas,list,names

  To-do list:  /exec, /notify, /dcc
 
  
Tested and verified working under:  Ultrix 4.2, OSF/1

ALL 2.8 server commands (*=sent to client also):
ADMIN AWAY CONNECT DIE *ERROR HASH HELP INFO *INVITE ISON *JOIN *KICK KILL
LINKS LIST LUSERS *MODE MOTD NAMES *NICK NOTE *NOTICE OPER *PART PASS *PING
PONG *PRIVMSG *QUIT REHASH RESTART SERVER SQUIT STATS SUMMON TIME *TOPIC
TRACE USER USERHOST USERS VERSION WALLOPS WHO WHOIS WHOWAS

*/

#define DEFAULTPORT	6667
#define DEFAULTSERVER	"vinson.ecn.uoknor.edu"
#define COMMANDCHAR	'/'
#define TINYSIZE 12322
#define NOT_TELNET
/* the following are machines known to be POSIX compliant --
   if you have trouble and it works after adding yours, let me know */

#ifdef	linux
#define _POSIX_VERSION
#endif

#include <stdio.h>
#ifndef _POSIX_VERSION
#include <sgtty.h>
#define	USE_OLD_TTY
#include <sys/ioctl.h>
#undef	USE_OLD_TTY
#ifndef	CBREAK
#define CBREAK RAW
#endif
#if !defined(sun) && !defined(sequent) && !defined(hpux) && \
	!defined(_AIX) && !defined(aix)
#include <strings.h>
#define strchr index
#else
#include <string.h>
#endif
#else
#include <string.h>
#include <termios.h>
#endif
#include <errno.h>
#include <sys/types.h>
#include <pwd.h>
#include <sys/time.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <signal.h>

int	sockfd,sok=1,tty_des,CO,LI,_tty_ch,dumb=0;
int     iphead=0, imhead=0;
u_short	IRCPORT=DEFAULTPORT;
char hostname[64];
char	*ME,*MR,*CM,*CS,*CE,*CL;
char    bp[1024],*term,*ptr,buf[512],object[256],localhost[64];
char	sockbuf[512],inputbuf[512],IRCNAME[10],*token[256],*fromhost;
char	termcap[1024],curnick[10],gotnick[10],sentnick[10],*query,*ti;
char    *ipublic[20],*imsg[20];
char *chanlist = NULL;
fd_set	readfs;
struct	timeval timeout;
struct	passwd *userinfo;
#ifdef	_POSIX_VERSION
struct	termios _tty;
tcflag_t _res_iflg, _res_lflg;
#define cbreak() (_tty.c_lflag&=~ICANON, \
	tcsetattr(_tty_ch, TCSANOW, &_tty))
#define noecho() (_tty.c_lflag &= ~(ECHO|ICRNL), \
	tcsetattr(_tty_ch, TCSADRAIN, &_tty))
#define savetty() ((void) tcgetattr(_tty_ch, &_tty), \
	_res_iflg = _tty.c_iflag, _res_lflg = _tty.c_lflag)
#define resetty() (_tty.c_iflag = _res_iflg, _tty.c_lflag = _res_lflg,\
	(void) tcsetattr(_tty_ch, TCSADRAIN, &_tty))
#define erasechar()	(_tty.c_cc[VERASE])
#else
struct	sgttyb _tty;
int	_res_flg;
#define cbreak() (_tty.sg_flags|=CBREAK, ioctl(_tty_ch, TIOCSETP, &_tty))
#define noecho() (_tty.sg_flags &= ~(ECHO|CRMOD), \
	ioctl(_tty_ch, TIOCSETP, &_tty))
#define savetty() ((void) ioctl(_tty_ch, TIOCGETP, &_tty), \
	_res_flg = _tty.sg_flags)
#define resetty() (_tty.sg_flags = _res_flg, \
	(void) ioctl(_tty_ch, TIOCSETP, &_tty))
#define erasechar()	(_tty.sg_erase)
#endif

static	int current=0; /* current position in input buffer */
static	int pos=0; /* position on input line */
static	int poslc=0; /* current "page" of 70 columns */
static	time_t idletimer; /* idle time for user */
int	putchar_x(c) int c; { putchar(c); }
#define	tputs_x(s) (tputs(s,0,putchar_x))

int call_socket(hostname)
  char *hostname;
{ struct sockaddr_in sa;
  struct hostent     *hp;
  int    a, s;
  if((hp=gethostbyname(hostname))==NULL) {
	errno=ECONNREFUSED; 
	return(-1); }
  bzero(&sa, sizeof(sa));
  bcopy(hp->h_addr, (char *)&sa.sin_addr, hp->h_length);
  sa.sin_family = hp->h_addrtype;
  sa.sin_port = htons((u_short)IRCPORT);
  if((s=socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) return(-1);
  if(connect(s,(struct sockaddr *) &sa, sizeof(sa)) < 0) {
	close(s); 
	return(-1); }
  return(s);
}

char *left(st, n)
char *st;
int n;
{ char *s;int i;

s = (char *)malloc(n + 1);
for (i=0;i<n; i++)
   s[i] = st[i];
s[n] = '\0';
return(s);
}

/* upper() could cause memory leaks if you leave dangling pointers
   Not tried it extensively.... - Mmmm   */

char *upper(st)
char *st;
{ char *s; int i = 0,k;

k= strlen(st);
s = (char *)malloc(k+1);
while (i<k)
 { s[i] = toupper(st[i]); i++;}
s[i] = '\0';
return(s);
}

int readln()
{ int i=0,valid=1; char c;
while(valid) {
	if(read(sockfd,&c,1)<1) return(0);
	if(i<511 && c != '\n') sockbuf[i++]=c; else valid=0; }
sockbuf[i]='\0'; return(1);
}

updatestatus()
{ time_t now;
  char st[200];
  char *s;
  int i;

if(!dumb) {
  tputs_x(tgoto(CM, 0, LI-2)); tputs_x(MR);
   now=time(NULL);
  *((strchr(ti=ctime(&now),'\n')))='\0';
  strtok(ti," ");
  for (i=0;i<3;i++) s = strtok(NULL," ");
  s[strlen(s)-3] = '\0';
  if (!query)
    { char *s1;
      s1 = left(object,10);
      sprintf(st,"%s  %s on %s : Smallirc 1.0.beta.Mmmm",s,
	curnick,s1);
      free(s1);
    } 
  else
   { char *s1, *s2;
      s1 = left(object,10);
      s2 = left(query,10);
    sprintf(st,"%s  %s [Query: %s] on %s : Smallirc 1.0.beta.Mmmm",s,
	curnick,s2,s1);
     free(s1);free(s2);
   }
  printf("%s",st);
  tputs_x(CE);
  for (i=0;i<(CO-strlen(st));i++) printf(" ");
  tputs_x(ME); }
}

int writeln(outbuf)
char *outbuf;
{ int to=0;
if(write(sockfd, outbuf, strlen(outbuf)) < to )
	return(0);
return(1);
}

finishline(start)
int start; 
{ int i,ii; 
i=start; ii=0;
while (token[i]) 
  { ii += strlen(token[i]);
    if (ii > CO-10) {printf("\r\n");ii = 0;}
    printf(" %s",token[i++]); 
  }
}

fline(o,start)
int o,start; 
{ int i,ii; 
i=start; ii=0;
while (token[i]) 
  { ii += strlen(token[i]);
    if (ii > CO-o) {printf("\r\n");ii = 0;o = 20;}
    printf(" %s",token[i++]); 
  }
}

sline(o,s)
int o;
char *s;
{ int i=0,ii=0;
while (s[i])
 { ii++;
   if (ii > CO-o) {printf("\r\n");ii = 0; o = 5;}
   printf("%c", s[i]);
   i++;
 }
}


dojoin()
{ char *c; int i,k;
  char *s;

   if(strcmp(token[0],IRCNAME)==0) 
     {
	strcpy(object,&token[2][1]);
        if (chanlist)
         { 
            s = (char *)malloc(strlen(chanlist)+strlen(&token[2][1])+1);
            strcpy(s, chanlist);
            strcat(s,&token[2][1]); 
            free(chanlist);
            chanlist = s;
          }
        else 
         { chanlist = (char *) malloc (strlen(&token[2][1])+1);
           strcpy(chanlist, &token[2][1]);
         }
     printf("*** %s (%s) has joined channel %s\n",token[0],fromhost,&token[2][1]);
	updatestatus();
     }
  else printf("*** %s (%s) has joined channel %s",token[0],fromhost,&token[2][1]);
}

dopart()
{ char *c,*s;
  int i=0;

  if(strcmp(token[0],IRCNAME)==0) 
   { 
    
    s = (char *)malloc(strlen(chanlist)-strlen(token[2])+1);
    c=strtok(chanlist,"#");
    if (strcmp(c,&token[2][1]) !=0)
     { strcpy(s,"#"); strcat(s,c); i=1;}
    while(c=strtok(NULL, "#"))
      { 
        if (strcmp(c,&token[2][1]) !=0)
          { strcat(s,"#"); strcat(s,c); i = 1;}
       }
    free(chanlist); 
    chanlist = s;
    if (i)
      strcpy(object, strrchr(chanlist,'#'));
    else { chanlist = NULL; strcpy(object,"*"); }
    printf("*** You have left channel %s\n",token[2]);
    updatestatus();
   }
  else printf("*** %s has left channel %s",token[0],
	token[2]);
}

donick()
{ if(strcmp(token[0],IRCNAME)==0) { strcpy(IRCNAME,&token[2][1]);
	printf("*** You are now known as %s\n", &token[2][1]);
        strcpy(curnick,&token[2][1]);
	updatestatus();
	}
  else printf("*** %s is now known as %s",token[0],&token[2][1]);
}


match(s1, s2)
char *s1, *s2;
{
char *i, *j;

if (!strcmp(s2,"*")) return(1);
i = upper(s1); j = s2;
while ((*i) && (*j))
{ if ((*j) == '?')
   { i++; j++;}
  else if ((*j) == '*')
   { char ss[512], *s3, *s4;
 
     j++;
     strcpy(ss, j);
     s3 = strtok(ss, "*?");
     s4 = strstr(i, s3);
     if (!s4) return(0); 
     else i = s4;
   }
  else if (toupper(*i) != toupper(*j))
      return(0);
  else {i++; j++;}
}
if (!(*i) && !(*j)) return(1);
else return(0);
}


isignored(n, h,  a, ix)
char *n, *h;
char *a[];
int ix;
{
int i;
char *s1, *s2, *s3, *s4, *s5;
char ss[512], st[512];

if (!ix) return(0);
strcpy(ss,h);
s1 = strtok(ss,"@");
s2 = strtok(NULL,"@");
for (i=0; i<ix; i++)
 { strcpy(st,a[i]);
   s3 = strtok(st, "!");
   s4 = strtok(NULL,"@");
   s5 = strtok(NULL,"@");
   if (match(n,s3) && match(s1,s4) && match(s2,s5)) 
      return(1);
 }
return(0);
}

doprivmsg()
{ int i=4,noctcp=0;
if(*(++token[3])=='\01') {
     if (!isignored(token[0],fromhost,imsg,imhead))
        {
	if(*(token[3]+1)=='A') {
	printf("*** ACTION: %s",token[0]); noctcp=1; }
	else printf("*** CTCP %s from %s",++token[3], token[0]); 
	}
     else return(0);
                       }
else {
	if(*token[2] != '#') 
          {if (!isignored(token[0],fromhost,imsg,imhead))
             {
            tputs_x(MR);printf("*%s*",token[0]); 
            strcpy(gotnick,token[0]);tputs_x(ME);i=3; noctcp=1; 
               }
            else return(0);
          }
	else {
        if (!isignored(token[0],fromhost,ipublic,iphead))
          {char *s1, *s2;
           s1 = upper(object); s2 = upper(token[2]);
	if(strcmp(s1,s2)!=0) 
          printf("<%s:%s>",token[0],token[2]);
	else 
           printf("<%s>",token[0]); 
        free(s1); free(s2);
	i=3; noctcp=1; 
           }
        else return(0);
                }
      }
fline(27,i); if(noctcp) return(1);
/* CTCP requests */
if(*token[3]=='V') {
	sprintf(buf,"NOTICE %s :\01VERSION Smallirc 1.0.beta.Mmmm *IX \01\n",
	token[0]); writeln(buf); }
else if(*token[3]=='P') {
         
	sprintf(buf,"NOTICE %s :\01PING %s\n",token[0],token[4]);
	writeln(buf); 
               }
else if(*token[3]=='F') {
	sprintf(buf,"NOTICE %s :\01FINGER %s (%s@%s) Idle %d seconds\01\n",
	token[0],userinfo->pw_gecos,userinfo->pw_name,localhost,
	time(NULL)-idletimer); writeln(buf); }
else if(*token[3]=='C') { sprintf(buf,"NOTICE %s :\01CLIENTINFO %s\01\n",
	token[0],"VERSION FINGER CLIENTINFO PID ERRMSG"); writeln(buf); }
else if(*token[3]=='E') { sprintf(buf,"NOTICE %s :\01%s %s %s %s\n", token[0],
	token[3],token[4],token[5],token[6]); writeln(buf); }
else if(*token[3]=='D') { sprintf(buf,"NOTICE %s :\01DCC not supported\01\n",
	token[0]); writeln(buf); }
else { sprintf(buf,"NOTICE %s :\01ERRMSG %s\01\n",token[0],
	"I'm sorry dave, I'm afraid I can't do that"); writeln(buf); }
return(1);
}

donotice()
{ int j=3;
if(token[3][1]=='\01') /* ctcp reply */
{ if (strcmp(token[3],":\01PING") == 0)
     {
          long timediff, currenttime;
         currenttime = time(NULL);
         if ((token[4]) && (*(token[4])))
            { *(strchr(token[4],'')) = '\0'; 
              timediff = currenttime-atol(token[4]); 
            }
         else
             timediff = (long) 0;  
         free(token[4]);
         token[4] = (char *)malloc(20);
	 sprintf(token[4],"%d second%s\01\n",timediff,
                         (timediff == 1) ? "" : "s"); 
    }
	printf("*** CTCP %s reply from %s:",++token[j++],token[0]);
}
else if (strchr(token[0],'.')==0) 
    {printf("-%s- %s",token[0],&token[3][1]);j++;}
finishline(j);
}

spitout()
{ int i,num,newline;
  char *temp,*s,*c;

if(strncmp(sockbuf,"PI",2)==0) { strncpy(sockbuf,"PONG :",5);
           strcat(sockbuf, DEFAULTSERVER);
	return(writeln(strcat(sockbuf,"\n"))); } /* ping - pong */
/* parse lines from server for output to terminal */
if(!dumb) tputs_x(tgoto(CM,0,LI-3));
token[i=0]=strtok(sockbuf," ");
while(token[++i]=strtok(NULL, " ")); token[i]=NULL;
if(*token[0] != ':') { finishline(2); putchar('\n'); return(0); }
	else token[0]++;
if(temp=strchr(token[0],'!')) { *temp='\0'; fromhost=temp+1; }
if(num=atoi(token[1])) /* this is quite extensible, ya know... */
	switch(num) { /* server-numerics */
	case 352: /* rpl_whoreply */
	  printf("%-15s %-10s %3s %s@%s",token[3],token[7],
		token[8],token[4],token[5]); finishline(9);
	  break;
         case 311:  /* whois reply */
            printf("*** %s is %s@%s (%s",token[3], token[4], token[5],
                                                           &token[7][1]);
             fline(60,8);printf(")");
            break;
         case 314:  /* whowas reply */
            printf("*** %s was %s@%s (%s",token[3], token[4], token[5],
                                                           &token[7][1]);
             fline(60,8);printf(")");
            break;
         case 319: printf("*** on channels %s", &token[4][1] );
                    fline(60,5);
            break;
         case 312: printf("*** on irc via server %s (%s", 
                                        token[4],&token[5][1]);
                   fline(70,6); printf(")");
             break;
         case 313: printf("*** %s is an IRC operator", token[3]);
              break;
         case 317: printf("*** %s has been idle for %s seconds", token[3],
								token[4]);
             break;
         case 301: printf("*** %s is away: %s", token[3], &token[4][1]);
                   fline(40,5);
             break;
         case 332: printf("*** Topic for %s is %s", token[3], &token[4][1]);
                   fline(40,5);
             break;
         case 353: { char *sss;
                     sss = left(token[4],10);
                    if (strcmp(token[3],"=")==0)
                       printf("Pub:\t%s", sss);
                   else  
                       printf("Prv:\t%s", sss);
                    free(sss);
                   if (strlen(token[4]) > 10) printf(">");
                   else  
                     for (i=0;i< 10-strlen(token[4]);i++) printf(" ");
                   printf("\t%s",&token[5][1]);
                   fline(40,6);
                   }
                   break;
         case 321: printf("Channel \t Users \t Topic");
             break;
         case 322: {char *sss;
                   sss = left(token[3],10); 
                   printf("%s", sss);free(sss);
                   if (strlen(token[3]) > 10) printf(">");
                   else  
                     for (i=0;i< 10-strlen(token[3]);i++) printf(" ");
                   printf("\t %s \t %s", token[4], &token[5][1]);
                   fline(40,6);
                  }
             break;
         case 372: printf("*** %s", &token[3][1]);   /* motd reply */
                   finishline(4);
              break;
         case 315:   /* end of who */
         case 318:   /* end of whois */
         case 365:   /*end of links */
         case 366:   /*end of names */
         case 368:   /*end of bans */
         case 369:   /* end of whowas */
         case 323:   /* end of list */
         case 376:   /* end of motd */
         case 219:   /* end of stats */
             break; 
                   
	default:
	  /* printf("%s",token[1]); finishline(3);  */
          printf("*** ");
          if (*token[3] == ':') 
            printf("%s", &token[3][1]);
          else printf("%s", token[3]);
          fline(35,4); 
	  break;
	}
else if(*token[1]=='P') 
       if(*(token[1]+1)=='R') 
             newline = doprivmsg(); 
       else dopart();
else if(*token[1]=='N') if(*(token[1]+1)=='O') donotice(); else donick();
else if(*token[1]=='J') dojoin();
else if(*token[1]=='Q') { printf("*** Signoff: %s (%s",token[0],&token[2][1]); 
                          fline(40,3); 
                          printf(")");}
else if(*token[1]=='T') {
	printf("*** %s has changed the topic on channel %s to %s",token[0],
                                                     token[2], &token[3][1]);
	fline(70,4); }
else if(*token[1]=='I') printf("*** %s invites you to channel %s",token[0],
                                                                &token[3][1]);
else if(*token[1]=='M') {
        if (strcmp(token[2],token[0]) != 0)
        {
        if (token[4])
	printf("*** Mode change \"%s %s\" on channel %s by %s",token[3],token[4],
                                                     token[2], token[0]);
        else 
	printf("*** Mode change \"%s\" on channel %s by %s",token[3],
                                                     token[2], token[0]);
         }
        else
	printf("*** Mode change \"%s\" for user %s by %s",&token[3][1],
                                                     token[2], token[0]);
         
	 }
else if(*token[1]=='K') {
        if (strcmp(IRCNAME,token[3]) != 0)
	  printf("*** %s has been kicked off channel %s by %s (%s",token[3],
                                              token[2],token[0],&token[4][1]);
        else
	  {printf("*** You have been kicked off channel %s by %s (%s",
                                              token[2],token[0],&token[4][1]);
           i = 0; 
           s = (char *)malloc(strlen(chanlist)-strlen(token[2])+1);
           c=strtok(chanlist,"#");
           if (strcmp(c,&token[2][1]) !=0)
               { strcpy(s,"#"); strcat(s,c); i=1;}
           while(c=strtok(NULL, "#"))
             { 
              if (strcmp(c,&token[2][1]) !=0)
                { strcat(s,"#"); strcat(s,c); i = 1;}
             }
           free(chanlist); 
           chanlist = s;
           if (i)
             strcpy(object, strrchr(chanlist,'#'));
           else {chanlist = NULL; strcpy(object, "*"); }
           fline(60,5); printf(")\n"); updatestatus();
           }
      }
else if(*token[1]=='E') { printf("*** ERROR:"); finishline(2); }
else { printf("*** odd server stuff:"); finishline(0); }
if (newline) putchar('\n'); if(!dumb) fflush(stdout);
}


connectclient(new)
int new;
{ char *s, *t;
printf("*** trying port %d of %s\n\n\n",IRCPORT,hostname);
if ((sockfd=call_socket(hostname))==-1) {
	fprintf(stderr, "*** connection refused, aborting\n", hostname);
	exit(0); }
if (!new)
{ sprintf(buf,"NICK %s\n",IRCNAME); strcpy(curnick,left(IRCNAME,9));}
else 
sprintf(buf, "NICK %s\n",curnick);
writeln(buf); gethostname(localhost, 64);
if (!getenv("IRCNAME")) sprintf(buf, "USER %s %s %s :%s\n", userinfo->pw_name,
	localhost,hostname,userinfo->pw_gecos);
else sprintf(buf, "USER %s %s %s :%s\n", userinfo->pw_name,localhost,
	hostname,getenv("IRCNAME"));
writeln(buf); 
if (!new)
strcpy(object,"*"); 
else
{ 
  if (chanlist)
    { s = (char *)malloc(strlen(chanlist) + 1);
      strcpy(s,chanlist);free(chanlist);
      t = strtok(s,"#");
      writeln("JOIN #");writeln(t);writeln("\n");
      while (t=strtok(NULL,"#")) 
         { writeln("JOIN #");writeln(t);writeln("\n"); }
    }
}
idletimer=time(NULL);
}

ignoreadd(s, a, ix)
char *s;
char *a[];
int *ix;
{ int ii;
if (*ix ==19)
   {printf("*** Ignore list full! Discarding %s\n",a[0]);
    ii=0;free(a[ii]);
    }
else {ii=*ix; (*ix)++;}
a[ii] = (char *) malloc (strlen(s) + 1);
strcpy(a[ii],upper(s));
}
      

ignoredel(s, a, ix)
char *s;
char *a[];
int *ix;
{ int ii, k = 0;
char *s1;

if (*ix == 0)
   {printf("*** Ignore list empty!\n");
    }
else {
s1 = upper(s);
for (ii = 0; ii < *ix; ii++)
{ if (!strcmp(a[ii],s1))
    { int j;
      k = 1;
      for (j=ii; j< (*ix)-1; j++)
       { free(a[j]);
         a[j] = (char *) malloc(strlen(a[j+1])+1);
         strcpy(a[j], a[j+1]); 
       }
      free(a[(*ix)-1]);
      a[(*ix)-1] = NULL;
      break;
    }
}
if (k) --(*ix);
else printf("%s not in ignorance list!\r\n",s);
free(s1);
}
}


int parseinput()
{ int ii=1, i, k,kk,t;
  char st[2], *qq, *s, *c, *s1;

if(!dumb) 
{
 tputs_x(tgoto(CM,0,LI-1)); tputs_x(CE); tputs_x(tgoto(CM,0,LI-3));
 inputbuf[current]='\0'; current=0; 
}
if ((query)&& (inputbuf[0] != COMMANDCHAR))
  { qq = (char *)malloc(strlen(inputbuf) + strlen(query) + 7);
    sprintf(qq,"/MSG %s %s",query,inputbuf);
    strcpy(inputbuf,qq);
    free(qq);
  }
s1 = upper(inputbuf);
if (strncmp(s1,"/SAY ",5) ==0)
 { qq = &inputbuf[5];
   strcpy(inputbuf,qq);
 }
if(inputbuf[0]==COMMANDCHAR) 
 {
  switch(toupper(inputbuf[1])) 
    {
	case 'Q': if (strncmp(s1,"/QUERY", 6) == 0)
                    { if ((inputbuf[6] != ' ')&&(query))
                        { printf("*** Ending conversation with %s\n",query);
                          free(query); query = (char *)NULL; 
                          updatestatus();
                         }
                      else 
                        { query = (char *)malloc(strlen(&inputbuf[7])+1);
                          strcpy(query,&inputbuf[7]);
                          *(strchr(query,'\n')) = '\0'; 
                          printf("*** Starting conversation with %s\n",query);
                          updatestatus();
                        } 
                      ii=0;
                    }
                  else
                   {
                   if(strlen(inputbuf) < 7) {
		        strcat(inputbuf,":Smallirc 1.0.beta.Mmmm Wuz Hea\n");
		         *(strchr(inputbuf,'\n'))=' '; }
                   }
		break;
        case 'S': if (toupper(inputbuf[2]) == 'I') 
                    writeln("QUIT :Smallirc 1.0.beta.Mmmm Wuz Hea\n");
#ifdef NOT_TELNET
                  else if (strncmp(s1,"/SERVER ",8) ==0)
                    { writeln("QUIT :changing servers");      
                      strcpy(hostname, &inputbuf[8]); 
                      *(strchr(hostname,'\n')) = '\0';
                      close(sockfd);
                      connectclient(1);ii=0;
                    }
                      
#endif
                break;
        case 'L': if (strncmp(s1,"/LEAVE ",7) == 0)
                    { writeln("PART ");writeln(&inputbuf[7]); ii = 0;}
                  break;
        case 'A': if (strncmp(s1,"/AWAY ",6) == 0)
                     { writeln("AWAY :");writeln(&inputbuf[6]); ii=0;}
                  break;
        case 'V': if (strncmp(s1,"/VERSION",8) == 0)
                    { printf("*** Client version: Smallirc 1.0.beta.Mmmm\r\n");
                      printf("*** Server version:\r\n");
                    }
                  break;
        case 'H': if (strncmp(s1,"/HELP",5) == 0)
                    {
                printf("*** SmallIRC -> Not all commands are supported\r\n");
                printf("*** Sending help request to service ircIIhelp...\r\n");
                      writeln("PRIVMSG ircIIhelp :");
                      writeln(&inputbuf[1]);
                      ii=0;
                   }
                  break;
        case 'I': if (strncmp(s1,"/IGNORE",7) == 0)
                    { ii = 0;
                      if (strlen(inputbuf) < 10)
                        { printf("*** MSGS ignorance list:\r\n");
                          if (imhead) 
                            for (i=0;i<imhead;i++) printf("%s\r\n",imsg[i]);
               else printf("Empty! Not ignoring public replies from anyone\r\n");
                          printf("*** PUBLIC ignorance list:\r\n");
                          if (imhead) 
                          for (i=0;i<iphead;i++) printf("%s\r\n",ipublic[i]);
               else printf("Empty! Not ignoring messages from anyone\r\n");
                        }
                    else { char s[512],ss[512];
                           strcpy(ss,&inputbuf[8]);
                           if (ss[strlen(ss)-1] == '\n') 
                              ss[strlen(ss)-1] = '\0';
                           if (inputbuf[8] != '-')
                            { strcpy(s,strtok(ss," \n"));
                              if (!strchr(s,'!')&& (!strchr(s,'@'))) 
                                  strcat(s,"!*@*");
                              else if (!strchr(s,'!')&& (strchr(s,'@'))) 
                                 { strcpy(ss,"*!");
                                   strcat(ss,s);strcpy(s,ss);
                                 }
                             if (strstr(s1," MSG"))
                              { printf("*** Now ignoring messages from %s\r\n",s);
                                ignoreadd(s,imsg,&imhead);
                              }
                            else if (strstr(s1," PUBLIC"))
                              { ignoreadd(s,ipublic,&iphead); 
                                printf("*** Now ignoring publics from %s\r\n",s);
                              }
                            else /* if (strstr(s1," ALL")) */
                           { printf("*** Now ignoring ALL messages from %s\r\n",s);
                             ignoreadd(s,imsg,&imhead);
                             ignoreadd(s,ipublic,&iphead); 
                            }
                           }
                           else  /* removing */
                            { strcpy(s,strtok(ss," \n"));
                              if (!strchr(s,'!')&& (!strchr(s,'@'))) 
                                  strcat(s,"!*@*");
                              else if (!strchr(s,'!')&& (strchr(s,'@'))) 
                                 { strcpy(ss,"*!");
                                   strcat(ss,&s[1]);strcpy(s,ss);
                                 }
                             if (strstr(s1," MSG"))
                          { printf("*** Not ignoring messages from %s\r\n",&s[1]);
                                ignoredel(&s[1],imsg,&imhead);
                              }
                            else if (strstr(s1," PUBLIC"))
                              { ignoredel(&s[1],ipublic,&iphead); 
                             printf("*** Not ignoring publics from %s\r\n",&s[1]);
                              }
                            else /* if (strstr(s1," ALL")) */
                     { printf("*** Not ignoring ALL messages from %s\r\n",&s[1]);
                              ignoredel(&s[1],imsg,&imhead);
                              ignoredel(&s[1],ipublic,&iphead); 
                            }
                           }
                        }         

                   }
                       break;   

        case 'T': if (strncmp(s1,"/TOPIC ",7) == 0)
                  { writeln("TOPIC "); ii=0; t=7;
                  while ((inputbuf[t] != ' ') && (inputbuf[t] != '\0'))
                  { st[0] = inputbuf[t++]; 
                    st[1] = '\0';
                    writeln(st);
                  }
                  if (inputbuf[t])
                  {
                    writeln(" :");t++;
		    writeln(&inputbuf[t]); 
                  }
                  }
                  break;
	case 'N': if(inputbuf[2]==' ') 
                    t = 3;
                  else if (strncmp(s1,"/NOTICE ",8) == 0)
                     t = 8;
                  else break; 
                  writeln("NOTICE ");
                  printf("-> -");
                  while ((inputbuf[t] != ' ') && (inputbuf[t] != '\0'))
                  { st[0] = inputbuf[t++]; 
                    st[1] = '\0';
                    writeln(st);printf("%s",st);
                  }
                  writeln(" :");t++;
		  writeln(&inputbuf[t]);
                  printf("- %s",&inputbuf[t]); 
                  ii=0; 
             break;
        case 'W': if (inputbuf[2] == ' ') 
                    {writeln("WHOIS ");writeln(&inputbuf[3]);ii = 0; }
             break;
	case 'J': if(inputbuf[2]==' ') 
                    { kk = 3;ii = 0;}
                  else if (strncmp(s1,"/JOIN ",6) == 0)
                     { kk = 6; ii=0;}
                   else break;
                   writeln("JOIN ");writeln(&inputbuf[kk]);
                   *(strchr(&inputbuf[kk],'\n')) = '\0';
                   if ((chanlist) && (strstr(chanlist,&inputbuf[kk])))
                      { 
                        i = 0; 
                        s = (char *)malloc(strlen(chanlist)+1);
                        c=strtok(chanlist,"#");
                        if (strcmp(c,&inputbuf[kk+1]) !=0)
                        { strcpy(s,"#"); strcat(s,c); i=1;}
                        while(c=strtok(NULL, "#"))
                            { if (strcmp(c,&inputbuf[kk+1]) !=0)
                                { strcat(s,"#"); strcat(s,c); i = 1;}
                             }
                         free(chanlist); 
                         chanlist = s;
                         strcat(chanlist,&inputbuf[kk]);
                         printf ("*** You are now talking to channel %s\n",
                                                                 &inputbuf[kk]);
                         strcpy(object, strrchr(chanlist,'#'));
                         updatestatus();
                      }
                  break;
	case 'M': if(inputbuf[2]==' ') 
                     t = 3;
                  else if (strncmp(s1,"/MSG ",5) == 0)
                     t = 5;
                  else if (strncmp(s1,"/ME ",4) == 0)
                    { writeln("PRIVMSG ");writeln(object);
                      writeln(" :ACTION ");
                      printf("*** Action: %s ",IRCNAME);
                      sline(20,&inputbuf[4]);
		      *(strchr(inputbuf,'\n'))= '';
                      strcat(inputbuf,"\n");
                      writeln(&inputbuf[4]);
                      ii=0;
                      break;
                    }
                  else
                     break; 
                  writeln("PRIVMSG ");
                  printf("-> *");
                  if ((inputbuf[t] != '.')&&(inputbuf[t] != ','))
                  { int doit = 1;
                   if (inputbuf[t] != '#') strcpy(sentnick,"");
                   else doit = 0;
                   while ((inputbuf[t] != ' ') && (inputbuf[t] != '\0'))
                    { st[0] = inputbuf[t++];
                      st[1] = '\0';
                      if (doit) strcat(sentnick,st);
                      writeln(st);printf("%s",st);
                    }
                  }
                  else
                  { if ((inputbuf[t] == '.'))
                        {writeln(sentnick);printf("%s",sentnick);t++;}
                    else  
                        {writeln(gotnick);printf("%s",gotnick);t++;}
                  }
                  writeln(" :");t++;
		  writeln(&inputbuf[t]);
                  printf("* "); sline(15,&inputbuf[t]);
                  ii=0; 
		break;
        case 'C': if (strncmp(s1,"/CTCP ",6) == 0)
                   {  char *s2;
                      writeln("PRIVMSG ");
                      t=6;
                      while ((inputbuf[t] != ' ') && (inputbuf[t] != '\0'))
                       { st[0] = inputbuf[t++]; 
                         st[1] = '\0';
                         writeln(st);
                       }
                      writeln(" :");
		      *(strchr(inputbuf,'\n'))= '\0';
                      s2 = upper(&inputbuf[t+1]);
                      if (strcmp(s2,"PING")==0)
                        sprintf(inputbuf, "%s %d", inputbuf, time(NULL));
                      strcat(inputbuf,"\01");
                      strcat(inputbuf,"\n");
                      writeln(s2);free(s2);
                      ii=0;
                   }
                   else if (strncmp(s1,"/CLEAR",6) == 0)
                       { tputs_x(CL); updatestatus(); ii = 0; }
                  break; 
        case 'P' : if (strncmp(s1, "/PING ",6) == 0)
                     { char s[80];
		       *(strchr(inputbuf,'\n'))= '\0';
                       writeln("PRIVMSG "); writeln(&inputbuf[6]);
                       writeln(" :PING ");
                       sprintf(s, "%d\01\n", time(NULL));
                       writeln(s); 
                       ii=0;
                     }
                  break;
	case '?': *(strchr(inputbuf,'\n'))='\0';
		printf("*** Default object set to %s\n",
		strcpy(object,&inputbuf[2])); updatestatus(); i=0;
		break;
	default: break; /* this is where you'd match commands */ 
     }
  /* pass command unfiltered to the server */
  if(ii) 
     { 
       writeln(&inputbuf[1]); 
       /* printf("= %s",inputbuf); */
     } 
  }
else {
      if ((inputbuf[0] != '\n') && (strcmp(object,"*") != 0))
       {
	sprintf(buf,"PRIVMSG %s :%s",object,inputbuf);
	writeln(buf); 
        if (strlen(inputbuf)%(CO-5) == 0) ii = strlen(inputbuf)/(CO-5);
              else ii = strlen(inputbuf)/(CO-5) + 1;
        for (i=0; i < ii; i++)
          { char *sss; 
            sss = left(&inputbuf[i*(CO-5)],CO-5); 
              if (i == 0)
                printf("> %s",sss);
             else
                printf("\r\n+%s",sss);
            free(sss);
          }
            
       }
      else 
        { strcpy(inputbuf,"");
          if (strcmp(object,"*") == 0) 
              printf ("*** You haven't joined any channel!\n");
        }
     }
idletimer=time(NULL); 
if (!dumb) fflush(stdout);
}

takeinchar()
{ char ch; int kpos;

kpos = pos;
if(dumb) 
  {
    fgets(inputbuf,511,stdin); 
    parseinput(); 
   }
else {
  ch=getchar();
  if(current<500) 
      inputbuf[current++]=ch;
  if(ch=='\10' || ch=='\177' || ch==erasechar()) 
     {
	if (pos) { inputbuf[current-=2]='\0'; --pos; --kpos;}
        else {current--;kpos = -1;}
	if (kpos>=0) printf("%c %c",ch,ch); 
        if (ch == erasechar())
          { tputs_x(tgoto(CM, pos, LI-1)); 
            tputs_x(CE);
            if (!pos) {strcpy(inputbuf,"");}
          } 
	if(!pos && poslc) 
          { char *sss;
            tputs_x(tgoto(CM, pos, LI-1)); 
            tputs_x(CE);
            sss = left(&inputbuf[(--poslc)*(pos=71)],71);
            printf("%s",sss);
            free(sss);
            tputs_x(tgoto(CM, pos=71, LI-1)); 
            tputs_x(CE);
          }
      }
  else if (ch != '\r' && ch != '\n') 
     {
	putchar(ch);kpos++;
	if((++pos)>71) 
          { tputs_x(tgoto(CM, pos=0, LI-1)); 
            tputs_x(CE); putchar(ch); pos=1; poslc++; 
          }
      }
  else 
    { pos=0; poslc=0; kpos = 0;
      inputbuf[current-1]='\n'; 
      if (current>1)
	parseinput(); 
     }
  } /* not dumb mode */
}

void cleanup()
{ tputs_x(tgoto(CS,-1,-1)); tputs_x(tgoto(CM,0,LI-1)); resetty(); exit(128); }


main(argc, argv)
	int argc;
	char **argv;
{ 
  int i, errflag;

for (i=0;i<20;i++) ipublic[i]=imsg[i]=NULL;
imhead = iphead = 0;
userinfo = getpwuid(getuid()); strcpy(hostname,DEFAULTSERVER);
if (!getenv("IRCNICK")) strncpy(IRCNAME,userinfo->pw_name,sizeof(IRCNAME));
	else strncpy(IRCNAME,(char *) getenv("IRCNICK"), sizeof(IRCNAME));
if(argc>1)
for (i=1; i<argc; i++) if(argv[i][0]=='-') { if(argv[i][1]=='d') dumb=1;
	 	else { fprintf(stderr,"usage: %s [nick] [server] [port] [-d]\n",
			argv[0]); exit(1); } }
	else if(strchr(argv[i],'.')) strcpy(hostname,argv[i]);
		else if(atoi(argv[i])) IRCPORT=atoi(argv[i]);
			else strcpy(IRCNAME,argv[i]);
connectclient(0);
if(!dumb) {
ptr=termcap;
if((term=(char *)getenv("TERM"))==NULL) {
	fprintf(stderr, "Smallirc: TERM not set\n");
	exit(1);
	}
if(tgetent(bp, term) < 1) {
	fprintf(stderr, "Smallirc: no termcap entry for %s\n",term);
	exit(1);
	}
if((CO=tgetnum("co")) == -1) CO=80; if((LI=tgetnum("li")) == -1) LI=24;
if((CM=(char *)tgetstr("cm", &ptr))==NULL)
	CM=(char *)tgetstr("cl", &ptr);
if((MR=(char *)tgetstr("mr", &ptr))==NULL)
	MR=(char *)tgetstr("md", &ptr);
ME=(char *)tgetstr("me", &ptr);
CL=(char *)tgetstr("cl", &ptr);
if(!CM || !(CS=(char *)tgetstr("cs", &ptr)) ||
	!(CE=(char *)tgetstr("ce", &ptr))) {
	printf("Smallirc: sorry, no termcap cm/cl,cs,ce: dumb mode set\n");
	dumb=1; }
if(!dumb) {
if ((_tty_ch = open("/dev/tty", O_RDWR, 0)) == -1) _tty_ch = 0;
signal(SIGINT,cleanup); signal(SIGHUP,cleanup); signal(SIGKILL,cleanup);
savetty(); cbreak(); noecho(); tputs_x(tgoto(CS,LI-3,0)); updatestatus(); }
}
while(sok) 
{
	FD_ZERO(&readfs); FD_SET(sockfd,&readfs);
	FD_SET(fileno(stdin),&readfs);
  	if(!dumb) 
   	{ tputs_x(tgoto(CM,pos,LI-1)); fflush(stdout);
	  timeout.tv_sec=15; timeout.tv_usec=0; 
	}
	if(select(FD_SETSIZE, &readfs, NULL, NULL,(dumb ? NULL : &timeout))) 
	{
	 if(FD_ISSET(fileno(stdin),&readfs)) takeinchar();
	 if(FD_ISSET(sockfd,&readfs)) 
  		{  sok = readln(); 
	 	   if (sok) spitout(); 
 		}
	} 
	else  updatestatus(); 
}
if(!dumb) { tputs_x(tgoto(CS,-1,-1)); tputs_x(tgoto(CM,0,LI-1)); resetty(); }
}
/* EOF */
