/*

Copyright (C) 2000 - 2004 Christian Kreibich <christian@whoop.org>.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies of the Software and its documentation and acknowledgment shall be
given in the documentation and software packages that this Software was
used.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

*/
#ifndef __libnd_trace_h
#define __libnd_trace_h

#include <libnd_registry.h>
#include <libnd_filter.h>
#include <libnd_packet_iterator.h>
#include <libnd_types.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

typedef enum {  
  LND_TRACE_MODIFIED      = (1 << 0), /* Trace got modified */
  LND_TRACE_CLEANED       = (1 << 1), /* Trace dirty bit got cleared */
  LND_TRACE_JUMPED        = (1 << 2), /* Jump to other location occurred */
  LND_TRACE_RELOAD        = (1 << 3), /* New packets loaded into memory */
  LND_TRACE_CLEAR         = (1 << 4), /* Trace's current part got cleared */
  LND_TRACE_IT_AREA_SET   = (1 << 5)  /* Trace's iterator area got set to new value */
} LND_TraceObserverOp;


/* A structure to define trace areas, in both time and space.
 */
struct lnd_trace_area
{
  LND_TPM_NavMode         mode;

  union {
    struct { 
      double              space_start;
      double              space_end;
    } space;

    struct {
      struct bpf_timeval  time_start; 
      struct bpf_timeval  time_end;
   } time;
  } un; 
};

#define area_space_start un.space.space_start
#define area_space_end   un.space.space_end
#define area_time_start  un.time.time_start
#define area_time_end    un.time.time_end


struct lnd_trace
{
  char                     *filename;
  char                     *unnamed;

  /* This is where all the cool stuff happens -- the trace part manager.
   * One's just slapped into every trace file and manages the handling
   * of the currently swapped-in packets, overlays, etc.
   */
  LND_TPM                  *tpm;

  GList                    *filters; /* GList<LND_Filter *> */
  LND_FilterMode            filter_mode;

  /* Stuff needed for the tcpdump connection: */
  struct {
    struct pcap_file_header pfh; /* The file's header */
    int                     fd;  /* Socket to pump data into and read line from */
    int                     pid; /* Pid of the tcpdump process for this trace */
  } tcpdump;

  /* Registry to associate things with a trace */
  LND_Registry             *registry;            
  
  LND_PacketIteratorMode    iterator_mode;
  LND_TraceArea             area;

  /* Packet observer blocks active for this trace -- a one bit
   * indicates that events are not to be reported to the observers.
   */
  LND_PacketObserverOp      packet_observer_blocks;
  LND_TraceObserverOp       trace_observer_blocks;

  int                       dirty          : 1;
  int                       incomplete     : 1;
  int                       needs_nav      : 1;
};


typedef struct lnd_trace_observer
{
  void  (*trace_modified) (LND_Trace *trace);
  void  (*trace_cleaned) (LND_Trace *trace);
  void  (*trace_reload) (LND_Trace *trace);
  void  (*trace_jumped) (LND_Trace *trace);
  void  (*trace_clear) (LND_Trace *trace);
  void  (*trace_it_area_set) (LND_Trace *trace);

} LND_TraceObserver;




/**
 * libnd_trace_new - creates a new trace.
 * @filename: canonical name of the trace file in the filesystem
 *
 * This is the constructor function for new traces. The @filename
 * is the full name of a trace file. You can pass %NULL if you don't
 * want/can provide packet data yet (as in live capture, for example).
 * If a filename is given, the file is checked for existence
 * and readability, if these checks fail, %NULL is returned. Otherwise
 * the trace is read into memory and initialized.
 *
 * Returns: new trace.
 */
LND_Trace      *libnd_trace_new(const char *filename);


/**
 * libnd_trace_free - cleans up trace.
 * @trace: trace to free.
 *
 * This function closes the tcpdump connection for this trace
 * and releases the memory it occupies, together with all its
 * packets.
 */
void           libnd_trace_free(LND_Trace *trace);


/**
 * libnd_trace_init - initializes a trace to a given file.
 * @trace: trace to initialize.
 * @source_file: trace file to initialize to.
 *
 * You can initialize a trace to a different input file using this function.
 *
 * Returns: %TRUE when initializiation was successful, %FALSE otherwise.
 */
gboolean       libnd_trace_init(LND_Trace *trace, const char *source_file);

/**
 * libnd_trace_initialized - predicate for trace initialization state
 * @trace: trace to check
 *
 * The predicate checks whether a trace has been initialized, i.e.
 * libnd_trace_init_header() has been called on this trace and its
 * #pcap_file_header is thus initialized.
 *
 * Returns: %TRUE when the trace has been initialized,
 * %FALSE otherwise.
 */
gboolean       libnd_trace_initialized(const LND_Trace *trace);


/**
 * libnd_trace_set_iterator_mode - sets the new default iteration mode for a trace.
 * @trace: trace to update.
 * @mode: iterator mode to use.
 *
 * The function sets the default packet iteration mode of @trace
 * to @mode. The default mode is %LND_PACKET_IT_AREA_R.
 */
void           libnd_trace_set_iterator_mode(LND_Trace *trace,
					     LND_PacketIteratorMode mode);

/**
 * libnd_trace_get_iterator_mode - returns current default iteration mode of a trace.
 * @trace: trace to query.
 *
 * Returns: the currently active iterator mode of @trace.
 */
LND_PacketIteratorMode libnd_trace_get_iterator_mode(const LND_Trace *trace);


/**
 * libnd_trace_set_area - sets the active trace area for a trace.
 * @trace: trace to set active area for
 * @area: @trace's new active area.
 *
 * The function makes the boundaries defined by @area the new current
 * trace area of @trace. The memory pointed to by @area is not used
 * after the function returns -- all values are copied over. It's
 * therefore safe to pass a pointer to an instance sitting on the
 * local stack.
 *
 * Using a packet iterator on @area, in
 * %LND_PACKET_IT_AREA_R or %LND_PACKET_IT_AREA_RW modes will then
 * iterate over the packets within that region. If @area is a
 * timeframe and that timeframe falls outside the timeframe covered
 * by the packets of @trace, the boundaries for @trace's new active
 * area are adjusted to fall within the existing range.
 */
void           libnd_trace_set_area(LND_Trace *trace,
				    LND_TraceArea *area);


/**
 * libnd_trace_get_area - returns the currently active trace area of a trace.
 * @trace: trace to obtain area from.
 * @area: resulting area.
 *
 * The function reports @trace's current trace area in the area
 * structure pointed to by @area.
 */
void           libnd_trace_get_area(LND_Trace *trace,
				    LND_TraceArea *area);

/**
 * libnd_trace_get_name - returns tracefile name if available, or dummy name.
 * @trace: trace to query
 *
 * If the trace contains packets from a tracefile, its filename is
 * returned. Otherwise, a dummy name is generated and returned.
 * In both cases, pointers to local data are returned and should
 * be strdupped if you want to keep them around.
 *
 * Returns: trace name.
 */
const char    *libnd_trace_get_name(const LND_Trace *trace);


/**
 * libnd_trace_get_packets - returns first of currently loaded packets.
 * @trace: trace to look up packets in.
 *
 * For each loaded trace, Netdude only stores a certain number of
 * packets in memory at any one time. Use this function to get to
 * the beginning of the current list of packets.
 * This function returns it.
 *
 * Returns: first  or NULL if n/a.
 */
LND_Packet     *libnd_trace_get_packets(const LND_Trace *trace);


/** 
 * libnd_trace_save - saves given trace, using dialog if necessary.
 * @trace: trace to save.
 *
 * The trace is saved to disk. If it doesn't have a name yet,
 * libnd_trace_save_as_dialog is called. If saving was successful,
 * %TRUE is returned, %FALSE otherwise.
 *
 * Returns: success status.
 */
gboolean       libnd_trace_save(LND_Trace *trace);


/**
 * libnd_trace_save_as - saves trace under new name and updates GUI accordingly.
 * @trace: trace to save.
 * @filename: new name of the trace.
 *
 * The name of the trace is changed and the trace saved subsequentially.
 * If saving was successful, %TRUE is returned, %FALSE otherwise.
 *
 * Returns: success status.
 */
gboolean       libnd_trace_save_as(LND_Trace *trace, const char *filename);


/**
 * libnd_trace_delete_hidden_packets - deletes currently hidden packets from the trace.
 * @trace: trace to delete packets from.
 *
 * The function iterates over all packets of the trace in the current
 * iteration mode (ie selection only, all local, or entire trace) and
 * drops every hidden packet. See libnd_packet_hide() and the filter API.
 */
void           libnd_trace_delete_hidden_packets(LND_Trace *trace);


/**
 * libnd_trace_set_dirty - updates dirty state of trace.
 * @trace: trace to update.
 * @dirty: whether we're dirty or not.
 *
 * This function sets the dirty state of @trace and updates the
 * GUI accordingly. If the trace is marked dirty, you cannot close
 * it without confirmation.
 */
void           libnd_trace_set_dirty(LND_Trace *trace, gboolean dirty);


/**
 * libnd_trace_add_filter - adds a filter to a trace.
 * @trace: trace to add filter to.
 * @filter: filter added.
 *
 * The function adds @filter to @trace. The filter is hooked into a list
 * that stores the filters that should be applied to this trace -- the
 * filter is not duplicated. Also, no checks are made whether the filter
 * already is added.
 */
void          libnd_trace_add_filter(LND_Trace *trace, LND_Filter *filter);


/**
 * libnd_trace_remove_filter - removes a filter from a trace.
 * @trace: trace to remove filter from.
 * @filter: filter removed.
 * 
 * The function removes @filter from the list of filters registered for
 * @trace.
 */
void          libnd_trace_remove_filter(LND_Trace *trace, LND_Filter *filter);


/**
 * libnd_trace_clear_filters - removes all filters from a trace.
 * @trace: trace to remove filters from.
 *
 * The function removes all filters from @trace.
 */
void          libnd_trace_clear_filters(LND_Trace *trace);


/**
 * libnd_trace_has_filter - checks whether a trace is using a given filter.
 * @trace: trace to query.
 * @filter: filter to check for.
 *
 * The function scans the filters registered for @trace and sees whether
 * @filter is among them. This is a pure pointer comparison, no semantic
 * equality check. However, there should be no need to duplicate instantiated
 * filters.
 *
 * Returns: %TRUE when @trace is using @filter, %FALSE otherwise.
 */
gboolean      libnd_trace_has_filter(LND_Trace *trace, LND_Filter *filter);


/**
 * libnd_trace_apply_filters -- applies current filter settings to trace.
 * @trace: trace to filter.
 *
 * The filter applies the filters set for @trace using the filtering mode
 * currently specified for @trace. The filters are applied to packets based
 * on the current packet iteration mode of @trace (i.e., selection, part,
 * or entire trace).
 *
 * Returns: the number of packets the filters were applied to.
 */
guint64       libnd_trace_apply_filters(LND_Trace *trace);



/**
 * libnd_trace_sync - saves a trace to the current output basename.
 * @trace: trace to sync.
 *
 * The function saves the entire trace to the current output basename,
 * flattening out all currently existing trace parts. The result is
 * a "clean" version of the trace in that file.
 *
 * Returns: %TRUE if all went well, %FALSE on error.
 */
gboolean      libnd_trace_sync(LND_Trace *trace);



/* ---------------------------- Trace Observers ----------------------------- */


/**
 * libnd_trace_observer_new - creates new trace observer.
 *
 * The function allocates a new, empty trace observer. You should
 * then fill in callbacks for the events you're interested in,
 * and register the thing using libnd_trace_add_observer().
 *
 * Returns: new observer.
 */
LND_TraceObserver *libnd_trace_observer_new(void);

/**
 * libnd_trace_observer_free - deleted trace observer.
 * @ob: observer to delete.
 * 
 * The function releases all memory associated with @ob.
 */
void            libnd_trace_observer_free(LND_TraceObserver *ob);


/**
 * libnd_trace_add_observer - registers a new trace observer.
 * @ob: new observer to register.
 *
 * The function registers the new observer for notifications about
 * future changes to traces.
 */
void           libnd_trace_add_observer(LND_TraceObserver *ob);

/**
 * libnd_trace_del_observer - deletes a trace observer.
 * @ob: observer to drop.
 *
 * The function stops trace operations from being reported to
 * @ob. It does not release @ob's memory, use libnd_trace_observer_free()
 * for that. 
 */
void           libnd_trace_del_observer(LND_TraceObserver *ob);

/**
 * libnd_trace_tell_observer - push operations to registered observers.
 * @trace: trace to report operation on.
 * @op: operation type.
 *
 * The function reports the given operation on the given trace to all
 * registered observers.
 */
void           libnd_trace_tell_observers(LND_Trace *trace, LND_TraceObserverOp op);


/**
 * libnd_trace_block_packet_observer_op - prevents an event type from being reported.
 * @trace: trace to block event reporting for.
 * @op: operation to block from being reported.
 *
 * This function prevents packet modification events of type @op from
 * being reported to registered observers.
 */
void           libnd_trace_block_packet_observer_op(LND_Trace *trace,
						    LND_PacketObserverOp op);

/**
 * libnd_trace_unblock_packet_observer_op - allows an event type to be reported.
 * @trace: trace for which to allow event reporting.
 * @op: operation to allow being reported.
 *
 * This function allows packet modification events of type @op to
 * be reported to registered observers.
 */
void           libnd_trace_unblock_packet_observer_op(LND_Trace *trace,
						      LND_PacketObserverOp op);

/**
 * libnd_trace_block_trace_observer_op - prevents an event type from being reported.
 * @trace: trace to block event reporting for.
 * @op: operation to block from being reported.
 *
 * This function prevents trace modification events of type @op from
 * being reported to registered observers.
 */
void           libnd_trace_block_trace_observer_op(LND_Trace *trace,
						   LND_TraceObserverOp op);

/**
 * libnd_trace_unblock_trace_observer_op - allows an event type to be reported.
 * @trace: trace for which to allow event reporting.
 * @op: operation to allow being reported.
 *
 * This function allows trace modification events of type @op to
 * be reported to registered observers.
 */
void           libnd_trace_unblock_trace_observer_op(LND_Trace *trace,
						     LND_TraceObserverOp op);

/**
 * libnd_trace_area_init_time - initializes a trace area to a time interval.
 * @area: area to initialize.
 * @tv_start: start time
 * @tv_end: end time
 *
 * The function initializes the trace area pointed to by @area to the
 * timeframe bounded by @tv_start and @tv_end.
 */
void           libnd_trace_area_init_time(LND_TraceArea *area,
					  struct bpf_timeval *tv_start,
					  struct bpf_timeval *tv_end);

/**
 * libnd_trace_area_init_space - initializes a trace area to a space interval.
 * @area: area to initialize.
 * @start: start point
 * @end: end point
 *
 * The function initializes the trace area pointed to by @area to the
 * region of packets between the @start and @end fractions of the trace.
 */
void           libnd_trace_area_init_space(LND_TraceArea *area,
					   double start, double end);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif
