/*
 * TCPVIEW
 *
 * Author:	Martin Hunt
 *		Networks and Distributed Computing
 *		Computing & Communications
 *		University of Washington
 *		Administration Building, AG-44
 *		Seattle, WA  98195
 *		Internet: martinh@cac.washington.edu
 *
 *
 * Copyright 1992 by the University of Washington
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appears in all copies and that both the
 * above copyright notice and this permission notice appear in supporting
 * documentation, and that the name of the University of Washington not be
 * used in advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.  This software is made
 * available "as is", and
 * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
 * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
 * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
 * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#ifndef lint
static char rcsid[] =
    "@(#) $Header: /usr/staff/martinh/tcpview/RCS/callbacks.c,v 1.2 1993/04/22 20:14:10 martinh Exp martinh $ (UW)";
#endif

#include <stdio.h>

#ifdef __STDC__
#include <stdlib.h>
#endif

#include <stdarg.h>
#include <sys/types.h>
#include <sys/time.h>
#include <string.h>
#include <errno.h>
#include <net/bpf.h>
#include "interface.h"

#include  <X11/Intrinsic.h>
#include  <X11/StringDefs.h>
#include  <Xm/Xm.h>
#include  <Xm/FileSB.h>
#include  <Xm/MessageB.h>
#include  <Xm/List.h>
#include  <Xm/Text.h>
#include "tcpview.h"
#include "filter.h"
#include "motif.h"

extern Widget summary_list_widget;    /* summary (top) window */
extern Widget detail_list_widget;     /* detail (middle) window */
extern Widget hex_text_widget;        /* hex (bottom) window */
extern Widget packet_label;

extern __const char *__const sys_errlist[];

#ifdef __STDC__
void redisplay_current_list(void);
void print2hexwindow (char *);
static void setpackets (void);
void readfile(char *);
void xperror( char *);
int sniff_next_packet(struct packet_header *, u_char *, int);
void redisplay_entire_list(void);
struct bpf_program *parse(char *, int, int, u_long);  /* gencode.c */
void (*lookup_printer(int))();
static void do_detail( int );
u_int bpf_filter(register struct bpf_insn *, register u_char *, u_int, register u_int );
void hd(u_char *, u_char *, int);
#else
void redisplay_current_list();
void print2hexwindow ();
void setpackets ();
void readfile();
void xperror();
int sniff_next_packet();
void redisplay_entire_list();
struct bpf_program *parse();  /* gencode.c */
void (*lookup_printer())();
static void do_detail();
u_int bpf_filter();
void hd();
#endif /* __STDC__ */

int errno;

/* these are set when files are read in */
int Linktype;
long thiszone;
int snaplen=DEFAULT_SNAPLEN;
int Precision;

struct printer {
        void (*f)();
        int type;
};
static struct printer printers[] = {
        { ether_if_print, DLT_EN10MB },
        { sl_if_print, DLT_SLIP },
        { ppp_if_print, DLT_PPP },
        { fddi_if_print, DLT_FDDI },
        { null_if_print, DLT_NULL },
        { 0, 0 },
};

void (*PrintIt)();
struct bpf_insn *Fcode;

struct packet_list {
  struct packet_header hdr;
  u_char *buf;
  struct packet_list *next;
};

static struct packet_list *PacketList=NULL;   /* always points to start of the list */
static struct packet_list **PL=NULL;
u_long Packet_Count=0;           /* total number of packets */
u_long Current_Packets=0;        /* number of packets currently displayed */
static XmString *LList=NULL;     /* list for summary widget. size is Packet_Count */
static long CurrP = -1;                 /* number of the currently selected packet */
extern char FileName1[];                /* current file name */
static u_short DetailHeaders[10];	/* list of header line numbers in detail window */
static u_short Header = 0;		/* current header number in detail window */
static u_short NumHeaders = 0;		/* number of headers in detail window */
static u_short HeaderOffset = 0;	/* current offset in header window */

/* track highlighting in hex window */
static int highlight[64][2];
static int numhigh=0;

void summary_list_callback( widget, client_data, list_data )
Widget                  widget;
caddr_t                 client_data;
XmListCallbackStruct    *list_data;
{
  struct packet_list *p;
  char *s, *t;
  static char str[8192], *buffer=NULL;
  int len, line_num, num;

  XmListDeleteAllItems( detail_list_widget );

  CurrP = list_data->item_position-1;
  p = PL[CurrP];
  StrPtr = str;
  Phdr = &(p->hdr);
  PrintIt(p->buf,&p->hdr.ts,p->hdr.len,p->hdr.caplen);
  StrPtr = str;
  detail_ether(p->buf); 

  num = 0;
  line_num = 1;
  s=t=str;
  len = strlen(str);
  while (*t) {
    if (*t=='\n') {
      *t++ = '\0';
      if( !strncmp( s, "-----", 5) )
	DetailHeaders[num++] = line_num;
      line_num++;
      AddToList( detail_list_widget, s, 0);
      s=t;
    } else
      t++;
  }
  NumHeaders = num;
  num = line_num-1;  /* number of lines */

  /* now update hex window */
  if (buffer==NULL)
    buffer = (char *)malloc(10000);
  hd(buffer,p->buf,p->hdr.caplen);
  print2hexwindow(buffer);

  /* now highlight proper section of detail window */
  if( Header && (Header <= NumHeaders) ) {
    line_num = DetailHeaders[Header-1]+HeaderOffset;
    if( line_num <= num ) {
      do_detail( line_num );
      XmListSelectPos(detail_list_widget,line_num,(Boolean)0);
      XmListSetPos(detail_list_widget,line_num);
    }
  }
}       /* summary_list_callback */

void detail_list_callback( widget, client_data, list_data )
Widget                  widget;
caddr_t                 client_data;
XmListCallbackStruct    *list_data;
{
  register int i, line;
  int header_line=0;

  line = list_data->item_position;

  /* new detail line, so reset the header and offset */
  for(i=0;i<NumHeaders;i++)
    if( DetailHeaders[i] <= line )
      header_line = DetailHeaders[i];
    else
      break;
  Header = i;
  HeaderOffset = line - header_line;

  do_detail(line);
}

static void do_detail( line )
     int line;
{
  register int i;
  int n, i1, j1, i2, j2;
  int left, right;    /* ASCII highlight */
  int hexl, hexr;           /* hex highlight */

  for (i=0;i<numhigh;i++)
    XmTextSetHighlight(hex_text_widget,highlight[i][0],
		       highlight[i][1],XmHIGHLIGHT_NORMAL);
  numhigh=0;

  n = hex_start(line - 1);
  if (n==-1) {
    return;
  }
  i1 = (int)(n/16);
  j1 = n%16;
  hexl = i1*76 + 6 + j1*3;
  left = i1*76 + 59 + j1;
  
  n = hex_stop(line - 1);
  i2 = (int)(n/16);
  j2 = n%16;
  hexr = i2*76 + 5 + (j2+1)*3;
  right = i2*76 + 60 + j2;
  
  if(i1==i2) {      /* same row */
    highlight[numhigh][0] = hexl;
    highlight[numhigh++][1] = hexr;
    highlight[numhigh][0] = left;
    highlight[numhigh++][1] = right;
  } else {
    highlight[numhigh][0] = hexl;
    highlight[numhigh++][1] = i1*76+53;
    highlight[numhigh][0] = left;
    highlight[numhigh++][1] = i1*76+75;
    highlight[numhigh][0] = i2*76+6;
    highlight[numhigh++][1] = hexr;
    highlight[numhigh][0] = i2*76+59;
    highlight[numhigh++][1] = right;
    for(i=i1+1;i<i2;i++) {
      highlight[numhigh][0] = i*76+6;
      highlight[numhigh++][1] = i*76+53;
      highlight[numhigh][0] = i*76+59;
      highlight[numhigh++][1] = i*76+75;
    }
  }
  
  for (i=0;i<numhigh;i++)
    XmTextSetHighlight(hex_text_widget,highlight[i][0],
		       highlight[i][1],XmHIGHLIGHT_SELECTED);
  
}       /* do_detail */


static void file_callback( widget, client_data, file_struct )
Widget widget;
caddr_t client_data;
XmFileSelectionBoxCallbackStruct  *file_struct;
{
  char    *string;
  
  XmStringGetLtoR( file_struct->value,
		  XmSTRING_DEFAULT_CHARSET,
		  &string );

  XtUnmanageChild(widget);
  readfile(string);
  strcpy(FileName1,string);
  XmListDeleteAllItems( detail_list_widget );
  XtFree(string); 
}       /* file_callback */

static Widget filesel;

static void cancel_callback( widget, client_data, file_struct )
Widget widget;
caddr_t client_data;
XmFileSelectionBoxCallbackStruct  *file_struct;
{
  XtUnmanageChild(filesel);
}       /* cancel_callback */


void open_callback( widget, name, call_data )
Widget  widget;
char    *name;
caddr_t call_data;
{
  Widget help;
  Arg args[5];
  int n=0;
  XmString xms;
  char temp[128];

  *temp=0;
  if( *FileName1 ) {
    strcpy(temp,FileName1);
    if( temp[strlen(FileName1)] == '/')
      strcat(temp,"..");
    else
      strcat(temp,"/..");
    xms = XmStringCreateSimple(temp);
    XtSetArg( args[n], XmNdirectory, xms); n++;
  }  
  XtSetArg( args[n], XmNtextColumns, 60); n++;
  XtSetArg( args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL ); n++; 
  filesel = XmCreateFileSelectionDialog( widget,"",args,n);
  XtAddCallback(filesel, XmNokCallback, file_callback, 0);
  XtAddCallback(filesel, XmNcancelCallback, cancel_callback, 0);
  help = XmFileSelectionBoxGetChild(filesel,XmDIALOG_HELP_BUTTON);
  XtUnmanageChild( help );
  XtManageChild( filesel );
  if( *temp ) XmStringFree(xms);
}       /* open_callback */


void generic_callback( widget, name, call_data )
Widget  widget;
char    *name;
caddr_t call_data;
{
        printf( "Menu choice was [%s]\n", name );

}       /* generic_callback */


void free_packet_list()
{
  struct packet_list *p;

  if( LList ) {
    free( LList );
    LList = NULL;
  }

  if (PacketList) {
    p=PacketList;
    do {
      free(p->buf);
      free(p);
    } while (p=p->next);
    free(PL);
    PacketList = NULL;
    PL = NULL;
    Packet_Count = 0;
  }
  Packet_Count=0;
  CurrP = -1;
}

void readfile(filename)
char *filename;
{
  struct packet_list *p, *prev;
  unsigned char *buf;
  int n;
  int sniff=0;
  int (*next_pack)();

  free_packet_list();

  n = sf_read_init(filename,&Linktype,&thiszone,&snaplen,&Precision);
  if( n == -1 )
    return;
  if( n>0 ) {
    sniff++;
    if (sniff_rinit(filename,&Linktype,&thiszone,&snaplen,&Precision)) {
      ErrorDialog(summary_list_widget,"error","Unrecognized file format");  
      return;
    }
  }

  buf = (u_char *)malloc(snaplen);
  if( sniff )
    next_pack = sniff_next_packet;
  else
    next_pack = sf_next_packet;

  prev = NULL;
  while(1) {
    p = (struct packet_list *)malloc(sizeof(struct packet_list));
    if (next_pack(&p->hdr,buf,snaplen)!=0) {
      free(p);
      break;
    }
    p->buf = (u_char *)malloc(p->hdr.caplen);
    bcopy(buf,p->buf,p->hdr.caplen);
    if (prev==NULL) 
      PacketList = p;
    else
      prev->next=p;
    p->next=NULL;
    prev = p;
    Packet_Count++;
  };

  if( Packet_Count==0 ) {
    ErrorDialog(summary_list_widget,"warn","No packets found in file");  
    return;
  }

  fprintf(stderr,"%d packets read\n",Packet_Count);

  PL = (struct packet_list **)malloc(Packet_Count*4);
  PrintIt = lookup_printer(Linktype);
  LList = (XmString *)malloc(Packet_Count*sizeof(XmString));
  redisplay_entire_list();
}


void redisplay_current_list()
{
  struct packet_list *p, **pl;
  char str[2048];
  register int i, n, cp;
  XmString *plist;

  if( PacketList == NULL )
    return;

  XtUnmanageChild(summary_list_widget);
  XmListDeleteAllItems( summary_list_widget );

  /* pl is the new packet list */
  pl = (struct packet_list **)malloc(Packet_Count*4);

  plist = LList;
  cp = -1;
  n = 0;
  HighlightPacket=0;
  ts_print(0);   /* reset */
  Fcode = parse(Fstr, 1, Linktype, 0)->bf_insns;
  for(i=0;i<Current_Packets;i++) {
    p = PL[i];
    StrPtr = str;
    Phdr = &(p->hdr);
    if( bpf_filter(Fcode,p->buf,p->hdr.len,p->hdr.caplen) ) {
      PrintIt(p->buf,&p->hdr.ts,p->hdr.len,p->hdr.caplen);
      *StrPtr=0;
      if( HighlightPacket ) {
	*plist++ = XmStringCreate( str, "chset2" );
	HighlightPacket = 0;
      } else
	*plist++ = XmStringCreate( str, "chset1" );
      if( i == CurrP)
	cp = n;
      pl[n++] = p;
    }
  }

  XmListAddItems( summary_list_widget, LList, n, 0 );
  Current_Packets = n;
  plist = LList;
  for(n=0;n<Current_Packets;n++)
    XmStringFree( *plist++ );

  free(PL);
  PL = pl;
  setpackets();
  XtManageChild(summary_list_widget);
  CurrP = cp;
  if( cp == -1) {
    print2hexwindow("");
    XmListDeleteAllItems( detail_list_widget );
  } else {
    XmListSelectPos( summary_list_widget, CurrP+1, False );
    XmListSetPos( summary_list_widget, CurrP+1 );
  }
}

void redisplay_entire_list()
{
  struct packet_list *p, *cp;
  char str[2048];
  int n;
  XmString *plist;

  if( PacketList == NULL )
    return;

  XtUnmanageChild(summary_list_widget);
  XmListDeleteAllItems( summary_list_widget );

  if( CurrP >= 0 )
    cp = PL[CurrP];
  else
    cp = (struct packet_list *)-1;

  CurrP = -1;
  n = 0;
  plist = LList;
  HighlightPacket=0;
  ts_print(0);   /* reset */
  Fcode = parse(Fstr, 1, Linktype, 0)->bf_insns;
  p = PacketList;
  do {
    StrPtr = str;
    Phdr = &(p->hdr);
    if( bpf_filter(Fcode,p->buf,p->hdr.len,p->hdr.caplen) ) {
      PrintIt(p->buf,&p->hdr.ts,p->hdr.len,p->hdr.caplen);
      *StrPtr=0;
      if( p == cp )
	CurrP = n;
      if( HighlightPacket ) {
	*plist++ = XmStringCreate( str, "chset2" );
	HighlightPacket = 0;
      } else
	*plist++ = XmStringCreate( str, "chset1" );
      PL[n++] = p;
    } 
  } while( p = p->next );

  XmListAddItems( summary_list_widget, LList, n, 0 );
  Current_Packets = n;

  plist = LList;
  for(n=0;n<Current_Packets;n++)
    XmStringFree( *plist++ );

  setpackets();
  XtManageChild(summary_list_widget);

  if( CurrP<0) {
    print2hexwindow("");
    XmListDeleteAllItems( detail_list_widget );
  } else {
    XmListSelectPos( summary_list_widget, CurrP+1, False );
    XmListSetPos( summary_list_widget, CurrP+1 );
  }
}

void save_entire_list(name, type)
     char *name;
     u_short type;
{
  struct packet_list *p;

  p = PacketList;
  do {
    if( type )
      sf_write( p->buf, &(p->hdr.ts), p->hdr.len, p->hdr.caplen); 
    else
      sniff_write( p->buf, &(p->hdr.ts), p->hdr.len, p->hdr.caplen); 
  } while( p = p->next );

  if( type )
    sf_write_end();
  else
    sniff_end("w");
}
  

void savefile( name, all, type )
     char *name;
     Boolean all;
     u_short type;
{
  struct packet_list *p;
  register int i;
  int sf_write_init();

  if( PacketList == NULL || ( all==False && Current_Packets==0 ))
    return;

  if( type ) {
    if( sf_write_init( name, Linktype, thiszone, snaplen, Precision) )
      return;
  } else {
    if( sniff_winit( name, Linktype, thiszone, snaplen, Precision) )
      return;
  }

  if( all==True ) {
    save_entire_list(name, type); 
    return;
  }

  /* save_current_list */
  for(i=0;i<Current_Packets;i++) {
    p = PL[i];
    if( type )
      sf_write( p->buf, &(p->hdr.ts), p->hdr.len, p->hdr.caplen); 
    else
      sniff_write( p->buf, &(p->hdr.ts), p->hdr.len, p->hdr.caplen); 
  }

  if( type )
    sf_write_end();
  else
    sniff_end("w");
}

void print_entire_list(fp, detail, str)
     FILE *fp;
     u_short detail;
     char *str;
{
  struct packet_list *p;

  if( PacketList == NULL )
    return;

  ts_print(0);   /* reset */
  p = PacketList;
  do {
    StrPtr = str;
    Phdr = &(p->hdr);
    if( detail )
      detail_ether(p->buf);
    else 
      PrintIt(p->buf,&p->hdr.ts,p->hdr.len,p->hdr.caplen);
    *StrPtr=0;
    fprintf(fp,"%s\n",str);
  } while( p = p->next );

  fclose(fp);
}
  

void printfile( name, all, detail )
     char *name;
     Boolean all;
     u_short detail;
{
  struct packet_list *p;
  register int i;
  char str[8192];
  FILE *fp;

  if( PacketList == NULL || (Current_Packets == 0 && all==False) ) {
    iprint("No packets to print");
    return;
  }

  if( name[0] == '-' && name[1] == '\0' )
    fp = stdout;
  else {
    fp = fopen(name,"w");
    if( !fp ) {
      xperror(name);
      return;
    }
  }

  if( all==True ) {
    print_entire_list(fp, detail, str); 
    return;
  }

  ts_print(0);   /* reset */
  for(i=0;i<Current_Packets;i++) {
    p = PL[i];
    StrPtr = str;
    Phdr = &(p->hdr);
    if( detail ) 
      detail_ether(p->buf);
    else 
      PrintIt(p->buf,&p->hdr.ts,p->hdr.len,p->hdr.caplen);
    *StrPtr=0;
    fprintf(fp,"%s\n",str);
  }
  fclose(fp);
}

void print2hexwindow(str)
char *str;
{
  static short end=0;

  /* turn off any highlighted text */
  XmTextSetHighlight(hex_text_widget,0,end,XmHIGHLIGHT_NORMAL);

  numhigh = 0;
  XmTextSetString( hex_text_widget,str);
  end = strlen(str);
}

static void setpackets()
{
  char buf[25];
  Arg args[3];
  XmString ms;

  sprintf(buf,"   %d/%d packets   ",Current_Packets,Packet_Count);
  ms = XmStringCreateSimple(buf);
  XtSetArg( args[0], XmNlabelString, ms );
  XtSetValues(packet_label,args,1);
  XmStringFree( ms );
}

void xperror(str)
     char *str;
{
  char *str2, buf[128];

  str2 = sys_errlist[errno];
  if(str[0]!='\0')
    sprintf(buf,"%s: %s\n",str,str2);
  else
    strcpy(buf,str2);
  ErrorDialog(summary_list_widget,"error",buf);
}


void eprintv(char *fmt, va_list ap)
{
  char str[128];

  (void)vsprintf(str, fmt, ap);
  ErrorDialog(summary_list_widget, "error", str);
}


void eprint(char *fmt, ...)
{
  va_list args;

  va_start(args, fmt);
  eprintv(fmt, args);
  va_end(args);
}


void iprint(char *fmt, ...)
{
  va_list args;
  char str[128];
  Widget widget;
  XmString ms;
  Arg a[2];
  int n;

  va_start(args, fmt);
  (void)vsprintf(str,fmt,args);
  va_end(args);

  ms = XmStringCreateSimple( str );
  n=0;
  XtSetArg( a[n], XmNmessageString, ms ); n++;
  widget = XmCreateInformationDialog(summary_list_widget, "info", a, n );
  RemoveDialButton( widget, XmDIALOG_CANCEL_BUTTON );
  RemoveDialButton( widget, XmDIALOG_HELP_BUTTON );
  XtManageChild(widget);
  XmStringFree(ms);
}


void
(*lookup_printer(type))()
        int type;
{
        struct printer *p;

        for (p = printers; p->f; ++p)
                if (type == p->type)
                        return p->f;

        eprint("unknown data link type 0x%x", type);
	return NULL;
}



















syntax highlighted by Code2HTML, v. 0.9.1