/* tcpsee by Derek Callaway <super@innu.org> -- S@IRC 
 * $Id: tcpsee.c,v 1.1 2000/04/07 04:43:02 super Exp $ 
 */

#include<stdio.h>
#include<getopt.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>

/* Default tcpdump pathname for popen() 
 * extra flags may also be provided here */
#define TCPDUMP_PATH "/usr/sbin/tcpdump"
/* Maximum Transfer Unit (How many bytes to snarf)
 * Usually 1500 -- check ifconfig */
#define DEFAULT_MTU "1500"
#define HD(c) ((c>='A')?(toupper(c)-'A'+10):(c-'0'))
/* 1024 should be plenty. */
#define BUFSIZE 1024

void vexit (const char *);
void usage (char **);

static char counter;

char *ansc (void);

int
main (int argc, char **argv)
{
  char *cmd, *realpath = TCPDUMP_PATH, *mtu = DEFAULT_MTU;
  char buf[BUFSIZE], tcpflag, colflag, color = 1;
  register char *p;
  FILE *pipe;
  int c;
  while ((c = getopt (argc, argv, "t:m:n")) != EOF)
    {
      switch (c)
	{
	case 't':
	  realpath = optarg;
	  break;
	case 'm':
	  mtu = optarg;
	  p = mtu;
	  while (*p)
	    {
	      if (!(isdigit (*p)))
		usage (argv);
	      else
		p++;
	    }
	  break;
	case 'n':
	  color = 0;
	  break;
	case '?':
	  usage (argv);
	}
    }
  /* 7 = strlen(" -lxs ") plus null zero. */
  if (!(cmd = (char *) malloc (strlen (realpath) + strlen (mtu) + 7)))
    {
      vexit ("malloc");
    }
  sprintf (cmd, "%s -lxs %s", realpath, mtu);
  if (!(pipe = popen (cmd, "r")))
    vexit ("popen");
  setvbuf (stdout, (char *) NULL, _IONBF, 0);
  while (fgets (buf, BUFSIZE, pipe))
    {
      if (buf[BUFSIZE] == '\0' && buf[BUFSIZE - 1] != '\n')
	{
	  if (color)
	    printf ("\033[38m");
	  printf ("Line too long!");
	  if (color)
	    printf ("\033[m");
	  while ((c = fgetc (pipe)) != '\n')
	    {
	      if (c == EOF)
		break;
	    }
	  if (c == EOF)
	    continue;
	}
      if (*(p = buf) != '\t')
	{
	  counter = colflag = 1;
	  if (strstr (buf, " ack "))
	    {
	      tcpflag = 1;
	    }
	  if (color)
	    {
	      printf ("\n\n\033[39;7m");
	      while (*p != ' ')
		{
		  if (*p)
		    putchar (*p);
		  else
		    break;
		  p++;
		}
	      printf ("\033[33m");
	      while (*p)
		{
		  switch (*p)
		    {
		    case '<':
		      if (!isspace (*(p + 1)))
			{
			  printf ("\033[m\033[34m");
			  putchar ('<');
			  p++;
			  goto newcol;
			}
		    case '>':
		      if (!isspace (*(p - 1)))
			{
			  printf ("\033[m\033[34m");
			  putchar ('>');
			  p++;
			  goto newcol;
			}
		    case ' ':
		    newcol:
		      if (colflag)
			{
			  printf ("%s", ansc ());
			  colflag = 0;
			}
		    default:
		      colflag = 1;
		      putchar (*p);
		    }
		  p++;
		}
	      printf ("\033[m\n");
	    }
	  else
	    printf ("\n\n%s\n", buf);
	  continue;
	}
      if (tcpflag)
	{
	  tcpflag = 0;
	}
      while (*p)
	{
	  if (isxdigit (*p) && isxdigit (*p + 1))
	    {
	      c = HD (*p);
	      p++;
	      c = 16 * c + HD (*p);
	      p++;
	      if (isprint (c))
		putchar (c);
	    }
	  else
	    p++;
	}
    }
  exit (EXIT_SUCCESS);
}

void
vexit (const char *func)
{
  perror (func);
  exit (EXIT_FAILURE);
}

void
usage (char **argv)
{
  printf ("%s [-n] [-t /path/to/tcpdump] [-m MTU]\n\n", argv[0]);
  printf ("-n\tno color\n");
  printf ("-t\ttcpdump path (default: %s)\n", TCPDUMP_PATH);
  printf ("  \tNote: extra tcpdump options may be provided with this flag\n");
  printf ("-m\tMaximum Transfer Unit -- check ifconfig (default: %s)\n",
	  DEFAULT_MTU);
  exit (EXIT_SUCCESS);
}

char *
ansc (void)
{
  static char *codelist[] =
    { "\033[m\033[31m", "\033[m\033[32m", "\033[m\033[33m",
    "\033[m\033[34;1m", "\033[m\033[35m", "\033[m\033[36m",
    "\033[m\033[37m", "\033[m\033[38m"
  };
  if (counter == 8)
    counter = 0;
  return (codelist[counter++]);
}

