/*
** xippkt.c for  in 
** 
** Made by 
** Login   <vianney@epita.fr>
** 
** Started on  Wed Sep  1 08:26:53 1999 
** Last update Thu Oct 28 20:24:03 1999 
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xmu/Converters.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/Scrollbar.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/SmeBSB.h>
#include <X11/Xaw/Tree.h>
#include <X11/Xaw/Viewport.h>
#include "XmgFancy.h"
#include "XmgFileGet.h"
#include "XmgMacro.h"
#include "xippkt.h"
#include "pat_pat.h"
#include "pat_data.h"
#include "pat_ether.h"
#include "pat_ip.h"
#include "pat_arp.h"
#include "pkt.h"
#include "pktsav.h"
#include "xipvar.h"
#include "xipres.h"
#include "xipimg.h"

extern XtAppContext		app_context;	
extern Widget			toplevel;
extern Widget			pktbox;
extern t_boolean		stop;
extern Pixmap			xipicon_pixmap;

t_boolean			xipdump_do_opts = TRUE;

#define SHELL_OR_TOPLEVEL(Xmd)	((Xmd)->xp->shell?(Xmd)->xp->shell:toplevel)

/* deletes a xip packet context (t_xip_pkt).
   It also destroy the widgets.
   Returns 0 if OK. ERR_XIP_IN_USE if packet is in use (e.g a set prompt
   is still popped up). */
t_status			xip_pkt_delete(xp)
t_xip_pkt			*xp;
{
  if (xp->in_delete)
    return (0);
  xp->in_delete = TRUE;
  if (VEC_COUNT(xp->users) == 0)
    {
      if (xp->own_pkt)
	pkt_delete(xp->pkt,
		   XIP_FREE_PROC);
      vec_delete(xp->users);
      if (xp->shell)
	XtDestroyWidget(xp->shell);
      XIP_FREE_PROC(xp,
		    "xippkt",
		    "xp");
      return (0);
    }
  else
    return (ERR_XIP_IN_USE);
}

/* is a t_xip_method_proc.
   Usage: "delete()".
   It deletes packet in using xip_pkt_delete(3). 
   Returns 0 if OK. Might return various errors. */
t_status			xip_method_proc_delete(xmd,args)
t_xip_method_data		*xmd;
t_vec				*args;
{
  return (xip_pkt_delete(xmd->xp));
}

/* is an XmgMacroMultiCallbackProc.
   It retrieves textfield widget value and sets it to packet. 
   It might recreate a packet if needed. 
   It also removes itself from packet users. */
VOID_FUNC			set_prompt_ok(w,vec,cbs)
Widget				w;
t_vec				*vec;
XtPointer			cbs;
{
  Widget			shell;			
  Widget			text;
  t_xip_method_data		*own_xmd;
  char				*value;
  t_status			status;
  t_pkt				*pkt;

  assert(VEC_COUNT(vec) == 3);
  shell = (Widget)VEC_AT(vec,0);
  text = (Widget)VEC_AT(vec,1);
  own_xmd = (t_xip_method_data *)VEC_AT(vec,2);
  XtVaGetValues(text,
		XtNstring,	&value,
		NULL);
  if (own_xmd->new_window)
    {
      if ((pkt = pkt_dup(own_xmd->xp->pkt,
			 XIP_ALLOC_PROC,
			 XIP_FREE_PROC,
			 &status)) == NULL)
	{
	  XmgErrPrint(SHELL_OR_TOPLEVEL(own_xmd),
		      status,
		      "pkt_dup");
	  goto end;
	}
    }
  else
    pkt = own_xmd->xp->pkt;
  if ((status = pkt_set_field_from_str(pkt,
				       own_xmd->data,
				       value)) != 0)
    {
      XmgErrPrint(SHELL_OR_TOPLEVEL(own_xmd),
		  status,
		  "pkt_set_field_from_str");
      if (own_xmd->new_window)
	{
	  pkt_delete(pkt,
		     XIP_FREE_PROC);
	}
      goto end;
    }
  if (own_xmd->new_window)
    {
      XipCreatePkt(toplevel,pkt,TRUE);
    }
  else
    {
      XmgFancyReset(own_xmd->xp->fancy);
      if ((status = xip_pkt_html(pkt,
				 own_xmd->xp->do_opts,
				 html_buf,
				 html_bufsiz)) != 0)
	{
	  XmgErrPrint(SHELL_OR_TOPLEVEL(own_xmd),
		      status,
		      "xip_pkt_html");
	  goto end;
	}
      XmgFancyParseBuf(own_xmd->xp->fancy,
		       html_buf,
		       strlen(html_buf));
    }
end:
  XtDestroyWidget(shell);
  VEC_RM_ELT(own_xmd->xp->users,own_xmd);
  XIP_FREE_PROC(own_xmd->data,
		"xippkt",
		"own_xmd->data");
  XIP_FREE_PROC(own_xmd,
		"xippkt",
		"own_xmd");
}

/* is an XmgMacroMultiCallbackProc.
   It retrieves pulldown widget value and sets it to packet. 
   It might recreate a packet if needed. 
   It also removes itself from packet users. */
VOID_FUNC			set_prompt_pulldown_ok(w,vec,cbs)
Widget				w;
t_vec				*vec;
XtPointer			cbs;
{
  Widget			shell;			
  Widget			pulldown;
  t_xip_method_data		*own_xmd;
  char				*value;
  t_status			status;
  t_pkt				*pkt;

  assert(VEC_COUNT(vec) == 3);
  shell = (Widget)VEC_AT(vec,0);
  pulldown = (Widget)VEC_AT(vec,1);
  own_xmd = (t_xip_method_data *)VEC_AT(vec,2);
  XtVaGetValues(pulldown,
		XtNlabel,	&value,
		NULL);
  if (own_xmd->new_window)
    {
      if ((pkt = pkt_dup(own_xmd->xp->pkt,
			 XIP_ALLOC_PROC,
			 XIP_FREE_PROC,
			 &status)) == NULL)
	{
	  XmgErrPrint(SHELL_OR_TOPLEVEL(own_xmd),
		      status,
		      "pkt_dup");
	  goto end;
	}
    }
  else
    pkt = own_xmd->xp->pkt;
  if ((status = pkt_set_field_from_str(pkt,
				       own_xmd->data,
				       value)) != 0)
    {
      XmgErrPrint(SHELL_OR_TOPLEVEL(own_xmd),
		  status,
		  "pkt_set_field_from_str");
      if (own_xmd->new_window)
	{
	  pkt_delete(pkt,
		     XIP_FREE_PROC);
	}
      goto end;
    }
  if (own_xmd->new_window)
    {
      XipCreatePkt(toplevel,pkt,TRUE);
    }
  else
    {
      XmgFancyReset(own_xmd->xp->fancy);
      if ((status = xip_pkt_html(pkt,
				 own_xmd->xp->do_opts,
				 html_buf,
				 html_bufsiz)) != 0)
	{
	  XmgErrPrint(SHELL_OR_TOPLEVEL(own_xmd),
		      status,
		      "xip_pkt_html");
	  goto end;
	}
      XmgFancyParseBuf(own_xmd->xp->fancy,
		       html_buf,
		       strlen(html_buf));
    }
end:
  XtDestroyWidget(shell);
  VEC_RM_ELT(own_xmd->xp->users,own_xmd);
  XIP_FREE_PROC(own_xmd->data,
		"xippkt",
		"own_xmd->data");
  XIP_FREE_PROC(own_xmd,
		"xippkt",
		"own_xmd");
}

/* is an XmgMacroMultiCallbackProc.
   It destroys prompt and removes itself from packet users. */
VOID_FUNC			set_prompt_cancel(w,vec,cbs)
Widget				w;
t_vec				*vec;
XtPointer			cbs;
{
  Widget			shell;
  t_xip_method_data		*own_xmd;
  
  assert(VEC_COUNT(vec) == 2);
  shell = (Widget)VEC_AT(vec,0);
  own_xmd = (t_xip_method_data *)VEC_AT(vec,1);
  XtDestroyWidget(shell);
  VEC_RM_ELT(own_xmd->xp->users,own_xmd);
  XIP_FREE_PROC(own_xmd->data,
		"xippkt",
		"own_xmd->data");
  XIP_FREE_PROC(own_xmd,
		"xippkt",
		"own_xmd");
}

t_status			xip_method_proc_set_args_eq_2(xmd,args)
t_xip_method_data		*xmd;
t_vec				*args;
{
  char				value[STR_BUFSIZ];
  t_xip_method_data		*own_xmd;
  t_vec				*choices;
  t_boolean			do_sort;
  t_status			status; 

  value[0] = 0;
  if ((status = pkt_get_field_to_str(xmd->xp->pkt,
				     VEC_AT(args,1),
				     value,
				     sizeof (value))) != 0)
    {
      return (status);
    }
  if ((own_xmd = XIP_ALLOC_PROC(sizeof (t_xip_method_data),
				"xippkt",
				"own_xmd",
				&status)) == NULL)
    return (status);
  bcopy((char *)xmd,(char *)own_xmd,sizeof (t_xip_method_data));
  if ((own_xmd->data = strdup_alloc(VEC_AT(args,1),
				    XIP_ALLOC_PROC,
				    "xippkt",
				    "own_xmd->data",
				    &status)) == NULL)
    {
      XIP_FREE_PROC(own_xmd,
		    "xippkt",
		    "own_xmd");
      return (status);
    }
  if ((status = vec_add(own_xmd->xp->users,own_xmd)) != 0)
    {
      XIP_FREE_PROC(own_xmd->data,
		    "xippkt",
		    "own_xmd->data");
      XIP_FREE_PROC(own_xmd,
		    "xippkt",
		    "own_xmd");
      return (status);
    }
  if ((choices = XIP_VEC_NEW(VEC_BASE,
			     &status)) == NULL)
    {
      VEC_RM_ELT(own_xmd->xp->users,own_xmd);
      XIP_FREE_PROC(own_xmd->data,
		    "xippkt",
		    "own_xmd->data");
      XIP_FREE_PROC(own_xmd,
		    "xippkt",
		    "own_xmd");
      return (status);
    }
  do_sort = TRUE;
  if ((status = pkt_get_choices(xmd->xp->pkt,
				VEC_AT(args,1),
				choices,
				&do_sort)) == 0)
    {
      if (VEC_COUNT(choices) > 0)
	{
	  if (do_sort)
	    vec_str_sort(choices);
	  XmgShowPromptComplexPulldownBox(SHELL_OR_TOPLEVEL(xmd),
					  VEC_AT(args,1),
					  choices,
					  value,
					  set_prompt_pulldown_ok,
					  set_prompt_cancel,
					  own_xmd,
					  XtGrabNone);
	}
      else
	{
	  vec_str_delete(choices);
	  VEC_RM_ELT(own_xmd->xp->users,own_xmd);
	  XIP_FREE_PROC(own_xmd->data,
			"xippkt",
			"own_xmd->data");
	  XIP_FREE_PROC(own_xmd,
			"xippkt",
			"own_xmd");
	  return (ERR_XIP_NO_CHOICES);
	}
    }
  else
    {
      XmgShowPromptBox(SHELL_OR_TOPLEVEL(xmd),
		       VEC_AT(args,1),
		       value,
		       set_prompt_ok,
		       set_prompt_cancel,
		       own_xmd,
		       XtGrabNone);
    }
  vec_str_delete(choices);
  return (0);
}

/* is a t_xip_method_proc.
   Usage: "set(layer[idx].field)|set(layer[idx].field,value)"
   e.g "set(ip[0].Src)".
   It needs one argument used as field name.
   It tries first to retrieve field value, then it tries to see if
   they are limited possible choices by using pkt_get_choices(3).
   If it is the case it calls XmgShowPromptComplexPulldownBox(3) instead of 
   XmgShowPromptBox(3). 
   Returns 0 if OK. Might return various errors. */
t_status			xip_method_proc_set(xmd,args)
t_xip_method_data		*xmd;
t_vec				*args;
{
  t_status			status;
  
  if (VEC_COUNT(args) != 2 && VEC_COUNT(args) != 3)
    return (ERR_XIP_SYNTAX);
  if (VEC_COUNT(args) == 3)
    {
      t_pkt			*pkt;

      if (xmd->new_window)
	  {
	    if ((pkt = pkt_dup(xmd->xp->pkt,
			       XIP_ALLOC_PROC,
			       XIP_FREE_PROC,
			       &status)) == NULL)
	      {
		return (status);
	      }
	  }
      else
	pkt = xmd->xp->pkt;
      if ((status = pkt_set_field_from_str(pkt,
					   VEC_AT(args,1),
					   VEC_AT(args,2))) != 0)
	{
	  if (xmd->new_window)
	    {
	      pkt_delete(pkt,
			 XIP_FREE_PROC);
	    }
	  return (status);
	}
      if (xmd->new_window)
	{
	  XipCreatePkt(toplevel,pkt,TRUE);
	}
      else
	{
	  XmgFancyReset(xmd->xp->fancy);
	  if ((status = xip_pkt_html(pkt,
				     xmd->xp->do_opts,
				     html_buf,
				     html_bufsiz)) != 0)
	    {
	      return (status);
	    }
	  XmgFancyParseBuf(xmd->xp->fancy,
			   html_buf,
			   strlen(html_buf));
	}
    }
  else
    return (xip_method_proc_set_args_eq_2(xmd,args));
}

/* is a t_xip_method_proc.
   Usage: "extract(layer[idx])|extract()"
   Extracts the specified layer to a possible new frame.
   Returns 0 if OK. Might return various errors. */
t_status			xip_method_proc_extract(xmd,args)
t_xip_method_data		*xmd;
t_vec				*args;
{
  char				value[STR_BUFSIZ];
  t_status			status;
  t_pkt				*pkt;
  
  if (VEC_COUNT(args) != 2 && VEC_COUNT(args) != 1)
    return (ERR_XIP_SYNTAX);
  if (xmd->new_window)
    {
      if ((pkt = pkt_dup(xmd->xp->pkt,
			 XIP_ALLOC_PROC,
			 XIP_FREE_PROC,
			 &status)) == NULL)
	{
	  return (status);
	}
    }
  else
    pkt = xmd->xp->pkt;
  if (VEC_COUNT(args) == 2)
    {
      if ((status = pkt_extract(pkt,
				VEC_AT(args,1),
				XIP_ALLOC_PROC,
				XIP_FREE_PROC)) != 0)
	{
	  if (xmd->new_window)
	    pkt_delete(pkt,
		       XIP_FREE_PROC);
	  return (status);
	}
    }
  if (xmd->new_window)
    {
      XipCreatePkt(toplevel,pkt,TRUE);
    }
  else
    {
      XmgFancyReset(xmd->xp->fancy);
      if ((status = xip_pkt_html(pkt,
				 xmd->xp->do_opts,
				 html_buf,
				 html_bufsiz)) != 0)
	{
	  return (status);
	}
      XmgFancyParseBuf(xmd->xp->fancy,
		       html_buf,
		       strlen(html_buf));
    }
  return (0);
}

/* is a t_xip_method_proc.
   Usage: "extract_to_pkt_box(layer[idx])|extract_to_pkt_box()"
   e.g "extract_to_pkt_box()" 
   Extracts the specified layer to packet box.
   Currently it is called by XipActionMinimizePkt(3).
   Returns 0 if OK. Might return various errors. */
t_status			xip_method_proc_extract_to_pkt_box(xmd,args)
t_xip_method_data		*xmd;
t_vec				*args;
{
  char				value[STR_BUFSIZ];
  t_status			status;
  t_pkt				*pkt;
  
  if (VEC_COUNT(args) != 2 && VEC_COUNT(args) != 1)
    return (ERR_XIP_SYNTAX);
  if (xmd->new_window)
    {
      if ((pkt = pkt_dup(xmd->xp->pkt,
			 XIP_ALLOC_PROC,
			 XIP_FREE_PROC,
			 &status)) == NULL)
	{
	  return (status);
	}
    }
  else
    pkt = xmd->xp->pkt;
  if (VEC_COUNT(args) == 2)
    {
      if ((status = pkt_extract(pkt,
				VEC_AT(args,1),
				XIP_ALLOC_PROC,
				XIP_FREE_PROC)) != 0)
	{
	  if (xmd->new_window)
	    pkt_delete(pkt,
		       XIP_FREE_PROC);
	  return (status);
	}
    }
  if (xmd->new_window)
    {
      XipCreateSmallPkt(pkt,TRUE);
    }
  else
    {
      XmgFancyReset(xmd->xp->fancy);
      if ((status = xip_pkt_html(pkt,
				 xmd->xp->do_opts,
				 html_buf,
				 html_bufsiz)) != 0)
	{
	  return (status);
	}
      XmgFancyParseBuf(xmd->xp->fancy,
		       html_buf,
		       strlen(html_buf));
    }
  return (0);
}

/* is a t_xip_method_proc.
   Usage: "trunc(layer[idx])" e.g "trunc(udp[0])" 
   Truncates the specified layer to a possible new frame.
   Returns 0 if OK. Might return various errors. */
t_status			xip_method_proc_trunc(xmd,args)
t_xip_method_data		*xmd;
t_vec				*args;
{
  char				value[STR_BUFSIZ];
  t_status			status;
  t_pkt				*pkt;
  
  if (VEC_COUNT(args) != 2)
    return (ERR_XIP_SYNTAX);
  if (xmd->new_window)
    {
      if ((pkt = pkt_dup(xmd->xp->pkt,
			 XIP_ALLOC_PROC,
			 XIP_FREE_PROC,
			 &status)) == NULL)
	{
	  return (status);
	}
    }
  else
    pkt = xmd->xp->pkt;
  if ((status = pkt_trunc(pkt,
			  VEC_AT(args,1),
			  XIP_ALLOC_PROC,
			  XIP_FREE_PROC)) != 0)
    {
      if (xmd->new_window)
	pkt_delete(pkt,
		   XIP_FREE_PROC);
      return (status);
    }
  if (xmd->new_window)
    {
      XipCreatePkt(toplevel,pkt,TRUE);
    }
  else
    {
      XmgFancyReset(xmd->xp->fancy);
      if ((status = xip_pkt_html(pkt,
				 xmd->xp->do_opts,
				 html_buf,
				 html_bufsiz)) != 0)
	{
	  return (status);
	}
      XmgFancyParseBuf(xmd->xp->fancy,
		       html_buf,
		       strlen(html_buf));
    }
  return (0);
}

/* is a t_xip_method_proc.
   Usage: "save()|save(file)"
   Asks for a file name then saves the packet to a possible new frame.
   Returns 0 if OK. Might return various errors. */
t_status			xip_method_proc_save(xmd,args)
t_xip_method_data		*xmd;
t_vec				*args;
{
  t_status			status;
  char				*fname;

  if (VEC_COUNT(args) != 2 && VEC_COUNT(args) != 1)
    return (ERR_XIP_SYNTAX);
  if (VEC_COUNT(args) == 2)
    fname = VEC_AT(args,1);
  else
    fname = XmgFileGet("*.pkt",FALSE); /* Might return NULL */
  if (fname)
    {
      if ((status = pkt_save(xmd->xp->pkt,fname)) != 0)
	return (status);
    }
  return (0);
}

/* is a t_xip_method_proc.
   Usage: "load()|load(file)"
   Asks for a file name then loads the packet to a possible new frame.
   Returns 0 if OK. Might return various errors. */
t_status			xip_method_proc_load(xmd,args)
t_xip_method_data		*xmd;
t_vec				*args;
{
  t_status			status;
  char				*fname;

  if (VEC_COUNT(args) != 2 && VEC_COUNT(args) != 1)
    return (ERR_XIP_SYNTAX);
  if (VEC_COUNT(args) == 2)
    fname = VEC_AT(args,1);
  else
    fname = XmgFileGet("*.pkt",FALSE); /* Might return NULL */
  if (fname)
    {
      t_pkt			*pkt;

      if (xmd->new_window)
	{
	  if ((pkt = pkt_dup(xmd->xp->pkt,
			     XIP_ALLOC_PROC,
			     XIP_FREE_PROC,
			     &status)) == NULL)
	    return (status);
	}
      else
	pkt = xmd->xp->pkt;
      if ((status = pkt_load(pkt,
			     fname,
			     XIP_ALLOC_PROC,
			     XIP_FREE_PROC)) != 0)
	{
	  if (xmd->new_window)
	    {
	      pkt_delete(pkt,
			 XIP_FREE_PROC);
	    }
	  return (status);
	}
        if (xmd->new_window)
	  {
	    XipCreatePkt(toplevel,pkt,TRUE);
	  }
	else
	  {
	    XmgFancyReset(xmd->xp->fancy);
	    if ((status = xip_pkt_html(pkt,
				       xmd->xp->do_opts,
				       html_buf,
				       html_bufsiz)) != 0)
	      return (status);
	    XmgFancyParseBuf(xmd->xp->fancy,
			     html_buf,
			     strlen(html_buf));
	  }
    }
  return (0);
}

/* is a t_xip_method_proc.
   Usage: "sum()"
   Checksums packet to a possible new frame.
   Returns 0 if OK. Might return various errors. */
t_status			xip_method_proc_sum(xmd,args)
t_xip_method_data		*xmd;
t_vec				*args;
{
  t_status			status;
  t_pkt				*pkt;
  
  if (xmd->new_window)
    {
      if ((pkt = pkt_dup(xmd->xp->pkt,
			 XIP_ALLOC_PROC,
			 XIP_FREE_PROC,
			 &status)) == NULL)
	return (status);
    }
  else
    pkt = xmd->xp->pkt;
  if ((status = pkt_sum(xmd->xp->pkt,NULL)) != 0)
    {
      if (xmd->new_window)
	{
	  pkt_delete(pkt,
		     XIP_FREE_PROC);
	}
      return (status);
    }
  if (xmd->new_window)
    {
      XipCreatePkt(toplevel,pkt,TRUE);
    }
  else
    {
      XmgFancyReset(xmd->xp->fancy);
      if ((status = xip_pkt_html(pkt,
				 xmd->xp->do_opts,
				 html_buf,
				 html_bufsiz)) != 0)
	return (status);
      XmgFancyParseBuf(xmd->xp->fancy,
		       html_buf,
		       strlen(html_buf));
    }
  return (0);
}

/* is a t_xip_method_proc.
   Usage: "adapt_len()"
   Adapts packet len to a possible new frame.
   Returns 0 if OK. Might return various errors. */
t_status			xip_method_proc_adapt_len(xmd,args)
t_xip_method_data		*xmd;
t_vec				*args;
{
  t_status			status;
  t_pkt				*pkt;
  
  if (xmd->new_window)
    {
      if ((pkt = pkt_dup(xmd->xp->pkt,
			 XIP_ALLOC_PROC,
			 XIP_FREE_PROC,
			 &status)) == NULL)
	return (status);
    }
  else
    pkt = xmd->xp->pkt;
  if ((status = pkt_adapt_len(xmd->xp->pkt)) != 0)
    {
      if (xmd->new_window)
	{
	  pkt_delete(pkt,
		     XIP_FREE_PROC);
	}
      return (status);
    }
  if (xmd->new_window)
    {
      XipCreatePkt(toplevel,pkt,TRUE);
    }
  else
    {
      XmgFancyReset(xmd->xp->fancy);
      if ((status = xip_pkt_html(pkt,
				 xmd->xp->do_opts,
				 html_buf,
				 html_bufsiz)) != 0)
	return (status);
      XmgFancyParseBuf(xmd->xp->fancy,
		       html_buf,
		       strlen(html_buf));
    }
  return (0);
}

t_pkt				*xip_cut_pkt = NULL;

/* initializes internal cut buffer to a one byte data packet.
   Returns 0 if OK. Might return various error messages. */
t_status			xip_pkt_cut_init(VOID_DECL)
{
  t_status			status;
  
  if ((xip_cut_pkt = pkt_new(1,
			     &data_pat,
			     XIP_ALLOC_PROC,
			     XIP_FREE_PROC,
			     &status)) == NULL)
    return (status);
  return (0);
}

/* destroys internal cut buffer */
VOID_FUNC			xip_pkt_cut_destroy(VOID_DECL)
{
  pkt_delete(xip_cut_pkt,XIP_FREE_PROC);
}

/* is a t_xip_method_proc.
   Usage: "cut(fine)|cut(fine,layer[index])"
   Cuts packet to an internal cut buffer.
   Returns 0 if OK. Might return various errors. */
t_status			xip_method_proc_cut(xmd,args)
t_xip_method_data		*xmd;
t_vec				*args;
{
  t_pkt				sub_pkt;
  t_status			status;
  char				*layer;
  t_boolean			fine;

  if (VEC_COUNT(args) != 2 && VEC_COUNT(args) != 3)
    return (ERR_XIP_SYNTAX);
  if ((status = atobooleanstrict(VEC_AT(args,1),&fine)) != 0)
    return (status);
  if (VEC_COUNT(args) == 3)
    layer = VEC_AT(args,2);
  else
    layer = NULL;
  return (pkt_cut(xmd->xp->pkt,
		  layer,
		  xip_cut_pkt,
		  fine,
		  XIP_ALLOC_PROC,
		  XIP_FREE_PROC));
}

/* is a t_xip_method_proc.
   Usage: "paste(fine)|paste(fine,layer[index])"
   Pastes packet from an internal cut buffer. See xip_method_cut(3).
   Returns 0 if OK. Might return various errors. */
t_status			xip_method_proc_paste(xmd,args)
t_xip_method_data		*xmd;
t_vec				*args;
{
  t_status			status;
  t_pkt				*pkt;
  char				*layer;
  t_boolean			fine;

  if (VEC_COUNT(args) != 2 && VEC_COUNT(args) != 3)
    return (ERR_XIP_SYNTAX);
  if ((status = atobooleanstrict(VEC_AT(args,1),&fine)) != 0)
    return (status);
  if (VEC_COUNT(args) == 3)
    layer = VEC_AT(args,2);
  else
    layer = NULL;
  if (xmd->new_window)
    {
      if ((pkt = pkt_dup(xmd->xp->pkt,
			 XIP_ALLOC_PROC,
			 XIP_FREE_PROC,
			 &status)) == NULL)
	return (status);
    }
  else
    pkt = xmd->xp->pkt;
  if ((status = pkt_paste(pkt,
			  layer,
			  xip_cut_pkt,
			  fine,
			  XIP_ALLOC_PROC,
			  XIP_FREE_PROC)) != 0)
    {
      if (xmd->new_window)
	{
	  pkt_delete(pkt,
		     XIP_FREE_PROC);
	}
      return (status);
    }
  if (xmd->new_window)
    {
      XipCreatePkt(toplevel,pkt,TRUE);
    }
  else
    {
      XmgFancyReset(xmd->xp->fancy);
      if ((status = xip_pkt_html(pkt,
				 xmd->xp->do_opts,
				 html_buf,html_bufsiz)) != 0)
	{
	  return (status);
	}
      XmgFancyParseBuf(xmd->xp->fancy,
		       html_buf,
		       strlen(html_buf));
    }
  return (0);
}

/* is a t_xip_method_proc.
   Usage: "edit()"
   Calls an external binary editor such as emacs(1) or beav(1). It saves
   packet to a file using pkt_save_raw(3).
   Returns 0 if OK. Might return various errors. */
t_status			xip_method_proc_edit(xmd,args)
t_xip_method_data		*xmd;
t_vec				*args;
{
  t_status			status;
  char				fnamebuf[MAXPATHLEN];
  char				*fname;
  pid_t				pid;
  t_pkt				*pkt;

#define TMP_TEMPLATE		"/tmp/xipXXXXXX"

  strcpy(fnamebuf,TMP_TEMPLATE);
  if ((fname = mktemp(fnamebuf)) == NULL)
    return (ERR_XIP_SUBROUTINE);
  if ((status = pkt_save_raw(xmd->xp->pkt,
			     fname)) != 0)
    return (status);
  if ((pid = fork()) < 0)
    {
      status = ERR_XIP_SYSCALL;
      goto end;
    }
  if (pid == 0)
    {
      execlp(xip_resources.binEditorPath,
	     xip_resources.binEditorPath,
	     fname,
	     NULL);
      err_print(ERR_XIP_SYSCALL,"execl");
      exit(1);
    }
  waitpid(pid,&status,0);
  if (xmd->new_window)
    {
      if ((pkt = pkt_dup(xmd->xp->pkt,
			 XIP_ALLOC_PROC,
			 XIP_FREE_PROC,
			 &status)) == NULL)
	goto end;
    }
  else
    pkt = xmd->xp->pkt;
  if ((status = pkt_load_raw(pkt,
			     fname,
			     XIP_ALLOC_PROC,
			     XIP_FREE_PROC)) != 0)
    {
      if (xmd->new_window)
	{
	  pkt_delete(pkt,
		     XIP_FREE_PROC);
	}
      goto end;
    }
  if (xmd->new_window)
    {
      XipCreatePkt(toplevel,pkt,TRUE);
    }
  else
    {
      XmgFancyReset(xmd->xp->fancy);
      if ((status = xip_pkt_html(pkt,
				 xmd->xp->do_opts,
				 html_buf,
				 html_bufsiz)) != 0)
	goto end;
      XmgFancyParseBuf(xmd->xp->fancy,
		       html_buf,
		       strlen(html_buf));
    }
  status = 0;
end:
  unlink(fname);
  return (status);
}

/* is a t_xip_method_proc.
   Usage: "reply()"
   Returns 0 if OK. Might return various errors. */
t_status			xip_method_proc_reply(xmd,args)
t_xip_method_data		*xmd;
t_vec				*args;
{
  t_status			status;
  t_pkt				*pkt;
  
  if (xmd->new_window)
    {
      if ((pkt = pkt_dup(xmd->xp->pkt,
			 XIP_ALLOC_PROC,
			 XIP_FREE_PROC,
			 &status)) == NULL)
	return (status);
    }
  else
    pkt = xmd->xp->pkt;
  if ((status = xip_pkt_reply(pkt)) != 0)
    {
      if (xmd->new_window)
	{
	  pkt_delete(pkt,
		     XIP_FREE_PROC);
	}
      return (status);
    }
  if (xmd->new_window)
    {
      XipCreatePkt(toplevel,pkt,TRUE);
    }
  else
    {
      XmgFancyReset(xmd->xp->fancy);
      if ((status = xip_pkt_html(pkt,
				 xmd->xp->do_opts,
				 html_buf,
				 html_bufsiz)) != 0)
	return (status);
      XmgFancyParseBuf(xmd->xp->fancy,
		       html_buf,
		       strlen(html_buf));
    }
  return (0);
}

/* is a t_xip_method_proc.
   Usage: "custom(path,arg0,...,argn)"
   Returns 0 if OK. Might return various errors. */
t_status			xip_method_proc_custom(xmd,args)
t_xip_method_data		*xmd;
t_vec				*args;
{
  t_status			status;
  t_pkt				*pkt;
  
  if (xmd->new_window)
    {
      if ((pkt = pkt_dup(xmd->xp->pkt,
			 XIP_ALLOC_PROC,
			 XIP_FREE_PROC,
			 &status)) == NULL)
	return (status);
    }
  else
    pkt = xmd->xp->pkt;
  if ((status = xip_pkt_custom(pkt,args)) != 0)
    {
      if (xmd->new_window)
	{
	  pkt_delete(pkt,
		     XIP_FREE_PROC);
	}
      return (status);
    }
  if (xmd->new_window)
    {
      XipCreatePkt(toplevel,pkt,TRUE);
    }
  else
    {
      XmgFancyReset(xmd->xp->fancy);
      if ((status = xip_pkt_html(pkt,
				 xmd->xp->do_opts,
				 html_buf,
				 html_bufsiz)) != 0)
	return (status);
      XmgFancyParseBuf(xmd->xp->fancy,
		       html_buf,
		       strlen(html_buf));
    }
  return (0);
}

/* is a t_xip_method_proc.
   Usage: "opts()|opts(True|False)"
   Show packet options.
   Returns 0 if OK. Might return various errors. */
t_status			xip_method_proc_opts(xmd,args)
t_xip_method_data		*xmd;
t_vec				*args;
{
  t_status			status;
  
  if (VEC_COUNT(args) == 2)
    {
      if ((status = atobooleanstrict(VEC_AT(args,1),
				     &xmd->xp->do_opts)) != 0)
	return (status);
    }
  else
    {
      xmd->xp->do_opts = !xmd->xp->do_opts;
    }
  XmgFancyReset(xmd->xp->fancy);
  if ((status = xip_pkt_html(xmd->xp->pkt,
			     xmd->xp->do_opts,
			     html_buf,
			     html_bufsiz)) != 0)
    return (status);
  XmgFancyParseBuf(xmd->xp->fancy,
		   html_buf,
		   strlen(html_buf));
  return (0);
}

/* is a t_xip_method_proc.
   Usage: "view_tmpl()"
   Show packet options.
   Returns 0 if OK. Might return various errors. */
t_status			xip_method_proc_view_tmpl(xmd,args)
t_xip_method_data		*xmd;
t_vec				*args;
{
  t_status			status;
  Widget			shell;
  
  if ((status = xip_pkt_tmpl(xmd->xp->pkt,
			     xmd->xp->do_opts,
			     tmpl_buf,
			     tmpl_bufsiz)) != 0)
    return (status);
  INTERFACE(xmd->xp->fancy,
	    GETCHILDSHELL(shell)
	    ("xipPktViewTmpl",transientShellWidgetClass,
	     XtNmappedWhenManaged,	False,
	     XtNtransientFor,		xmd->xp->fancy,
	     XtNallowShellResize,	True,
	     CHILD("xmgFancyViewSource",asciiTextWidgetClass,
		   XtNscrollHorizontal, XawtextScrollWhenNeeded,
		   XtNscrollVertical,   XawtextScrollWhenNeeded,
		   XtNstring,		tmpl_buf,
		   END),
	     MANAGE,
	     END),
	    ENDINTERFACE);
  XmgSetDestroyOnDelete(shell);
  XtPopup(shell,XtGrabNone);
  return (0);
}

t_status		xip_method_proc_view_tree_walk(pkt,level,id,data)
t_pkt			*pkt;
int			level;
t_id			*id;
VOID_PTR		data;
{
  int			i;
  char			buf[STR_BUFSIZ];
  t_status		status;

  i = 0;
  while (i < level)
    {
      fprintf(stderr," ");
      i++;
    }
  if (!pkt->pat->name_proc)
    fprintf(stderr,"?\n");
  else
    {
      buf[0] = 0;
      if ((status = pkt->pat->name_proc(NULL,
					id,
					buf,
					sizeof (buf))) != 0)
	return (status);
      fprintf(stderr,"%s\n",buf);
    }
  return (0);
}

/* is a t_xip_method_proc.
   Usage: "view_tree()"
   Show packet tree.
   Returns 0 if OK. Might return various errors. */
t_status			xip_method_proc_view_tree(xmd,args)
t_xip_method_data		*xmd;
t_vec				*args;
{
  t_status			status;
  
  return (pkt_walk(xmd->xp->pkt,
		   xmd->xp->do_opts,
		   0,
		   (t_pkt_walk_proc)xip_method_proc_view_tree_walk,
		   xmd));
}

t_xip_method			xip_methods[] =
{
  {"delete",			xip_method_proc_delete},
  {"set",			xip_method_proc_set},
  {"extract",			xip_method_proc_extract},
  {"extract_to_pkt_box",	xip_method_proc_extract_to_pkt_box},
  {"trunc",			xip_method_proc_trunc},
  {"save",			xip_method_proc_save},
  {"load",			xip_method_proc_load},
  {"sum",			xip_method_proc_sum},
  {"adapt_len",			xip_method_proc_adapt_len},
  {"cut",			xip_method_proc_cut},
  {"paste",			xip_method_proc_paste},
  {"edit",			xip_method_proc_edit},
  {"reply",			xip_method_proc_reply},
  {"custom",			xip_method_proc_custom},
  {"opts",			xip_method_proc_opts},
  {"view_tmpl",			xip_method_proc_view_tmpl},
  {"view_tree",			xip_method_proc_view_tree},
  {NULL,			NULL},
};

t_vec				*xip_methods_vec = NULL;

/* adds a method to methods vector.
   It is intended to use by plugins which adds new methods dynamically.
   Returns 0 if OK. Might return various errors */
t_status			xip_method_add(xm)
t_xip_method			*xm;
{
  t_status			status;
  t_xip_method			*own_xm;
  
  if ((own_xm = XIP_ALLOC_PROC(sizeof (t_xip_method),
			       "xip",
			       "xip_method_add:ptr",
			       &status)) == NULL)
    return (status);
  own_xm->name = xm->name;
  own_xm->proc = xm->proc;
  if ((status = vec_add(xip_methods_vec,
			own_xm)) != 0)
    {
      XIP_FREE_PROC(own_xm,
		    "xip",
		    "*:ptr");
      return (status);
    }
  return (0);
}

/* initializes dynamical methods context.
   Returns 0 if OK. Might return various errors */
t_status			xip_methods_init(VOID_DECL)
{
  t_status			status;
  t_xip_method			*xm;

  if ((xip_methods_vec = XIP_VEC_NEW(VEC_ONE_BASE,
				     &status)) == NULL)
    return (status);
  xm = xip_methods;
  while (xm->name)
    {
      if ((status = xip_method_add(xm)) != 0)
	return (status);
      xm++;
    }
  return (0);
}

/* destroys dynamical methods context */
VOID_FUNC			xip_methods_destroy(VOID_DECL)
{
  vec_ptr_delete(xip_methods_vec);
}

/* applies a method.
   If method fails, it shows an error popup. */
VOID_FUNC			xip_method_do(xmd,args)
t_xip_method_data		*xmd;
t_vec				*args;
{
  t_status			status;
  char				buf[STR_BUFSIZ];

  status = ERR_XIP_NO_METHOD;
  VEC_FOR(xip_methods_vec,t_xip_method *xm)
    {
      if (!strcmp(xm->name,VEC_AT(args,0)))
	{
	  if ((status = xm->proc(xmd,args)) != 0)
	    {
	      break ;
	    }
	  return ;
	}
    }
  VEC_ENDFOR;
  buf[0] = 0;
  VEC_FOR_FROM(args,1,char *str)
    {
      t_status			lstatus;

      if ((lstatus = str_cat_str(buf,
				 sizeof (buf),
				 str)) != 0)
	break ;
      if (VEC_IDX != (VEC_COUNT(args) - 1))
	if ((lstatus = str_cat_char(buf,
				    sizeof (buf),
				    ',')) != 0)
	  break ;
    }
  VEC_ENDFOR;
  XmgErrPrint(SHELL_OR_TOPLEVEL(xmd),
	      status,
	      "%s(%s)",
	      VEC_AT(args,0),
	      buf);
  return ;
}

/* parses a method.
   Might show an error popup if there is a syntax error. If OK,
   it calls xip_method_do(3). */
VOID_FUNC			xip_method_parse(xmd,str)
t_xip_method_data		*xmd;
char				*str;
{
  char				safe_str[BUFSIZ];
  t_status			status;
  char				*ptr;
  char				*arg;
  t_vec				*args;
  t_boolean			found_lp;

  safe_str[0] = 0;
  if ((status = str_cat_str(safe_str,
			    sizeof (safe_str),
			    str)) != 0)
    {
      XmgErrPrint(SHELL_OR_TOPLEVEL(xmd),
		  status,
		  "str_cat_str");
      return ;
    }
  if ((ptr = index(safe_str,'(')) == NULL)
    {
      XmgErrPrint(SHELL_OR_TOPLEVEL(xmd),
		  ERR_XIP_SYNTAX,
		  "missing '(' in %s",
		  str);
      return ;
    }
  if ((args = XIP_VEC_NEW(VEC_BASE,
			  &status)) == NULL)
    {
      XmgErrPrint(SHELL_OR_TOPLEVEL(xmd),
		  status,
		  "XIP_VEC_NEW");
      return ;
    }
  *ptr++ = 0;
  if ((status = vec_str_add(args,safe_str)) != 0)
    {
      XmgErrPrint(SHELL_OR_TOPLEVEL(xmd),
		  status,
		  "vec_str_add");
      vec_str_delete(args);
      return ;
    }
  found_lp = FALSE;
  arg = ptr;
  while (*ptr)
    {
      if (isspace(*ptr))
	{
	  ptr++;
	  continue ;
	}
      if ((*ptr) == ',' || (*ptr) == ')')
	{
	  if ((*ptr) == ')')
	    found_lp = TRUE;
	  *ptr++ = 0;
	  if (strcmp(arg,""))
	    if ((status = vec_str_add(args,arg)) != 0)
	      {
		XmgErrPrint(SHELL_OR_TOPLEVEL(xmd),
			    status,
			    "vec_str_add");
		vec_str_delete(args);
		return ;
	      }
	  arg = ptr;
	}
      if (found_lp)
	break ;
      ptr++;
    }
  if (found_lp)
    xip_method_do(xmd,args);
  else
    XmgErrPrint(SHELL_OR_TOPLEVEL(xmd),
		ERR_XIP_SYNTAX,
		"missing ')' in %s",
		str);
  vec_str_delete(args);
}

/* is an XtCallbackProc.
   It parses method pointed by link. */
VOID_FUNC			XipPktFancyLink(w,xp,cbs)
Widget				w;
t_xip_pkt			*xp;
XmgFancyLinkCallbackStruct	*cbs;
{
  t_xip_method_data		xmd;

  xmd.xp = xp;
  xmd.new_window = cbs->new_window;
  xip_method_parse(&xmd,cbs->href);
}

VOID_FUNC			bsb_table(w,closure,cbs)
Widget				w;
VOID_PTR			closure;
VOID_PTR			cbs;
{
  printf("ok\n");
}

/* is an XtCallbackProc.
   It sets shell title if packet is "big" */
VOID_FUNC			XipPktFancyTitle(w,xp,cbs)
Widget				w;
t_xip_pkt			*xp;
XmgFancyTitleCallbackStruct	*cbs;
{
  if (xp->shell)
    {
      XtVaSetValues(xp->shell,
		    XtNtitle,	cbs->title,
		    XtNiconName,cbs->title,
		    NULL);
    }
}

/* is an XtCallbackProc.
   Destroys packet in using xip_pkt_delete(3) */
VOID_FUNC			XipPktDestroy(w,xp,cbs)
Widget				w;
t_xip_pkt			*xp;
VOID_PTR			cbs;
{
  t_status			status;
  
  if ((status = xip_pkt_delete(xp)) != 0)
    {
      XmgErrPrint(toplevel,
		  status,
		  "xip_pkt_delete");
    }
}

char				*top_tmpl = "\
<html>\n\
<head>\n\
<title>%Pat% %Timestamp%</title>\n\
</head>\n\
<body link=black bgcolor=%bodyColorName% background=%bodyBackgroundName%>\n\
<table width=100%% bgcolor=%controlsColorName%>\n\
<tr>\n\
<td align=center>\n\
<b><a href=\"set(Pat)\">%Pat%</a></b>\n\
</td>\n\
<td align=center>\n\
<b>%Timestamp%</b> (%timestamp%)\n\
</td>\n\
<td align=center>\n\
%Len% (was %Netlen%)\n\
</td>\n\
<td align=center>\n\
<b>%Do_opts%</b>\n\
</td>\n\
</tr>\n\
<tr>\n\
<td>\n\
<small>\n\
";

char				*xip_pkt_bar_after_tmpl = "\
</small>\n\
</td>\n\
</tr>\n\
</table>\n\
<br>\n\
";

t_xip_pkt_bar			xip_pkt_bars[] = 
{
  {"Delete",			"delete()"},
  {"Load",			"load()"},
  {"Save",			"save()"},
  {"Ad.len",			"adapt_len()"},
  {"Sum",			"sum()"},
  {"Cut",			"cut(False)"},
  {"Paste",			"paste(False)"},
  {"Edit",			"edit()"},
  {"Reply",			"reply()"},
  {NULL,			NULL},
};

t_vec				*xip_pkt_bars_vec = NULL;

/* adds a title and a method to packet bar.
   It is intended to use by plugins which adds new methods dynamically.
   Returns 0 if OK. Might return various errors */
t_status			xip_pkt_bar_add(xpb)
t_xip_pkt_bar			*xpb;
{
  t_status			status;
  t_xip_pkt_bar			*own_xpb;
  
  if ((own_xpb = XIP_ALLOC_PROC(sizeof (t_xip_pkt_bar),
			   "xip",
			   "xip_pkt_bar_add:ptr",
			   &status)) == NULL)
    return (status);
  own_xpb->label = xpb->label;
  own_xpb->methodstr = xpb->methodstr;
  if ((status = vec_add(xip_pkt_bars_vec,
			own_xpb)) != 0)
    {
      XIP_FREE_PROC(own_xpb,
		    "xip",
		    "*:ptr");
      return (status);
    }
  return (0);
}

/* initializes dynamical packet bar context.
   Returns 0 if OK. Might return various errors */
t_status			xip_pkt_bar_init(VOID_DECL)
{
  t_status			status;
  t_xip_pkt_bar			*xpb;

  if ((xip_pkt_bars_vec = XIP_VEC_NEW(VEC_ONE_BASE,
				     &status)) == NULL)
    return (status);
  xpb = xip_pkt_bars;
  while (xpb->label)
    {
      if ((status = xip_pkt_bar_add(xpb)) != 0)
	return (status);
      xpb++;
    }
  return (0);
}

/* destroys dynamical packet bar context. */
VOID_FUNC			xip_pkt_bar_destroy(VOID_DECL)
{
  vec_ptr_delete(xip_pkt_bars_vec);
}

char				*bottom_tmpl = "\n\
</body>\n\
</html>\n\
";

t_status			xip_pkt_tmpl(pkt,do_opts,str,max_len)
t_pkt				*pkt;
t_boolean			do_opts;	/* Do options */
char				*str;
int				max_len;
{
  t_status			status;

  str[0] = 0;
  if ((status = str_cat_str(str,
			    max_len,
			    top_tmpl)) != 0)
    return (status);
  VEC_FOR(xip_pkt_bars_vec,t_xip_pkt_bar *xpb)
    {
      if ((status = str_cat_fmt_va(str,
				   max_len,
				   "<a href=\"%s\">[%s]</a>\n",
				   xpb->methodstr,
				   xpb->label)) != 0)
	return (status);
    }
  VEC_ENDFOR;
  if ((status = str_cat_str(str,
			    max_len,
			    xip_pkt_bar_after_tmpl)) != 0)
    return (status);
  if ((status = pkt_get_tmpl_to_str(pkt,
				    str,
				    max_len,
				    do_opts)) != 0)
    {
      t_status			lstatus;
      
      if (status == ERR_MG_BO)
	return (status);
      if ((lstatus = str_cat_str(str,
				 max_len,
			 "<table width=100%% bgcolor=%controlsColorName%>\n\
<tr>\n\
<td>\n")) != 0)
	return (lstatus);
      if ((lstatus = str_cat_fmt_va(str,
				    max_len,
				    "%s (%d)\n",
				    err_msg(status),
				    status)) != 0)
	return (lstatus);
      if ((lstatus = str_cat_str(str,
				 max_len,
				 "</td>\n\
</tr>\n\
</table>\n")) != 0)
	return (lstatus);
    }
  if ((status = str_cat_str(str,
			    max_len,
			    bottom_tmpl)) != 0)
    return (status);
  return (0);
}

/* generate an html page from a packet.
   Force str[0] to zero.
   Returns 0 if OK. Might return various errors. */
t_status			xip_pkt_html(pkt,do_opts,str,max_len)
t_pkt				*pkt;
t_boolean			do_opts;	/* Do options */
char				*str;
int				max_len;
{
  t_status			status;

  if ((status = xip_pkt_tmpl(pkt,
			     do_opts,
			     tmpl_buf,
			     tmpl_bufsiz)) != 0)
    return (status);
  html_buf[0] = 0;
  if ((status = pkt_format_html(pkt,
				do_opts,
				tmpl_buf,
				NULL,
				xip_extra_vars,
				str,
				max_len,
				htmlize_buf,
				htmlize_bufsiz)) != 0)
    return (status);
  return (0);
}

/* creates a graphical packet.
   If parent is toplevel then it creates a shell widget (it becomes
   then a "big" packet). If parent is not toplevel, it becomes 
   a "small" packet.
   It also defines specific action for "big" and "small" packets. 
   It might popup various error messages. */
Widget				XipCreatePkt(parent,pkt,own_pkt)
Widget				parent;
t_pkt				*pkt;
t_boolean			own_pkt;	/* If TRUE, considers
						   that t_pkt is
						   deletable */
{
  t_status			status;
  t_xip_pkt			*xp;
  Atom				atom;

  if ((status = xip_pkt_html(pkt,
			     xipdump_do_opts,
			     html_buf,
			     html_bufsiz)) != 0)
    {
      if (parent == toplevel)
	XmgErrPrint(toplevel,
		    status,
		    "xip_pkt_html");
      return (NULL);
    }
  if ((xp = XIP_ALLOC_PROC(sizeof (t_xip_pkt),
			   "xippkt",
			   "xp",
			   &status)) == NULL)
    {
      XmgErrPrint(toplevel,
		  status,
		  "XIP_ALLOC_PROC");
      return (NULL);
    }
  if ((xp->users = XIP_VEC_NEW(VEC_BASE,
			       &status)) == NULL)
    {
      XmgErrPrint(toplevel,
		  status,
		  "XIP_VEC_NEW");
      XIP_FREE_PROC(xp,
		    "xippkt",
		    "xp");
      return (NULL);
    }
  xp->pkt = pkt;
  xp->do_opts = xipdump_do_opts;
  xp->own_pkt = own_pkt;
  xp->in_delete = FALSE;
  if (parent == toplevel)
    {
      INTERFACE(toplevel,
		GETCHILDSHELL(xp->shell)
		("pktShell",wmShellWidgetClass,
		 XtNmappedWhenManaged,	False,
		 XtNallowShellResize,	True,
		 XtNiconPixmap,		xipicon_pixmap,
		 GETCHILD(xp->fancy)
		 ("bigPktFancy",xmgFancyWidgetClass,
		  XtNdoCutAndPaste,	True,
		  XtNuserData,		xp,
		  CALLBACK(XtNlinkCallback,
			   (XtCallbackProc)XipPktFancyLink,
			   xp),
		  CALLBACK(XtNtitleCallback,
			   (XtCallbackProc)XipPktFancyTitle,
			   xp),
		  CALLBACK(XtNimgCallback,
			   (XtCallbackProc)XipFancyImg,
			   xp),
		  CALLBACK(XtNdestroyCallback,
			   (XtCallbackProc)XipPktDestroy,
			   xp),
		  END),
		 MANAGE,
		 END),
		ENDINTERFACE);
      XtOverrideTranslations(xp->fancy,
			     XtParseTranslationTable(
				    "<Btn3Down>: XipPopupPktMenu()"));
    }
  else
    {
      xp->shell = NULL;
      INTERFACE(parent,
		GETCHILD(xp->fancy)
		 ("smallPktFancy",xmgFancyWidgetClass,
		  XtNuserData,		xp,
		  CALLBACK(XtNimgCallback,
			   (XtCallbackProc)XipFancyImg,
			   xp),
		  CALLBACK(XtNdestroyCallback,
			   (XtCallbackProc)XipPktDestroy,
			   xp),
		  END),
		ENDINTERFACE);
      XtOverrideTranslations(xp->fancy,
			     XtParseTranslationTable(
		    "<Btn3Down>: XipApplyMethodToPkt(True,\"extract()\")"));
    }
  XmgFancyParseBuf(xp->fancy,
		   html_buf,
		   strlen(html_buf));
  if (xp->shell)
    {
      XmgSetDestroyOnDelete(xp->shell);
      XtPopup(xp->shell,XtGrabNone);
    }
  return (xp->fancy);
}

