Store pointers to previously displayed and captured packet, not nstime_t deltas.
[metze/wireshark/wip.git] / epan / column-utils.c
index 95d6cf11de505bc56e8ea93a8d937f5c615e6a0c..7737ec99dc13fc8900604768a994e62c409b57f8 100644 (file)
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
+#include "config.h"
 
 #include <string.h>
 #include <time.h>
@@ -59,6 +57,7 @@ col_setup(column_info *cinfo, const gint num_cols)
   cinfo->col_last   = g_new(int, NUM_COL_FMTS);
   cinfo->col_title  = g_new(gchar*, num_cols);
   cinfo->col_custom_field = g_new(gchar*, num_cols);
+  cinfo->col_custom_occurrence = g_new(gint, num_cols);
   cinfo->col_custom_field_id = g_new(int, num_cols);
   cinfo->col_custom_dfilter = g_new(dfilter_t*, num_cols);
   cinfo->col_data   = (const gchar **)g_new(gchar*, num_cols);
@@ -222,6 +221,7 @@ void col_custom_set_edt(epan_dissect_t *edt, column_info *cinfo)
         cinfo->col_custom_field_id[i] != -1) {
        cinfo->col_data[i] = cinfo->col_buf[i];
        cinfo->col_expr.col_expr[i] = epan_custom_set(edt, cinfo->col_custom_field_id[i],
+                                     cinfo->col_custom_occurrence[i],
                                      cinfo->col_buf[i],
                                      cinfo->col_expr.col_expr_val[i],
                                      COL_MAX_LEN);
@@ -246,29 +246,32 @@ col_custom_prime_edt(epan_dissect_t *edt, column_info *cinfo)
         epan_dissect_prime_dfilter(edt, cinfo->col_custom_dfilter[i]);
         if (cinfo->col_custom_field) {
             header_field_info* hfinfo = proto_registrar_get_byname(cinfo->col_custom_field[i]);
-            g_assert(hfinfo);
-            cinfo->col_custom_field_id[i] = hfinfo->id;
+            cinfo->col_custom_field_id[i] = hfinfo ? hfinfo->id : -1;
         }
     }
   }
 }
 
-static void
-col_do_append_sep_va_fstr(column_info *cinfo, const gint el, const gchar *separator,
-              const gchar *format, va_list ap)
+/*  Appends a vararg list to a packet info string.
+ *  This function's code is duplicated in col_append_sep_fstr() below because
+ *  the for() loop below requires us to call va_start/va_end so intermediate
+ *  functions are a problem.
+ */
+void
+col_append_fstr(column_info *cinfo, const gint el, const gchar *format, ...)
 {
   int  i;
-  int  len, max_len, sep_len;
+  int  len, max_len;
+  va_list ap;
+
+  if (!CHECK_COL(cinfo, el))
+    return;
 
   if (el == COL_INFO)
     max_len = COL_MAX_INFO_LEN;
   else
     max_len = COL_MAX_LEN;
 
-  if (separator == NULL)
-    sep_len = 0;
-  else
-    sep_len = (int) strlen(separator);
   for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) {
     if (cinfo->fmt_matx[i][el]) {
       /*
@@ -278,40 +281,24 @@ col_do_append_sep_va_fstr(column_info *cinfo, const gint el, const gchar *separa
 
       len = (int) strlen(cinfo->col_buf[i]);
 
-      /*
-       * If we have a separator, append it if the column isn't empty.
-       */
-      if (separator != NULL) {
-        if (len != 0) {
-          g_strlcat(cinfo->col_buf[i], separator, max_len);
-          len += sep_len;
-        }
-      }
+      va_start(ap, format);
       g_vsnprintf(&cinfo->col_buf[i][len], max_len - len, format, ap);
+      va_end(ap);
     }
   }
-}
 
-/* Appends a vararg list to a packet info string. */
-void
-col_append_fstr(column_info *cinfo, const gint el, const gchar *format, ...)
-{
-  va_list ap;
-
-  if (!CHECK_COL(cinfo, el))
-    return;
-
-  va_start(ap, format);
-  col_do_append_sep_va_fstr(cinfo, el, NULL, format, ap);
-  va_end(ap);
 }
 
-/* Appends a vararg list to a packet info string.
- * Prefixes it with the given separator if the column is not empty. */
+/*  Appends a vararg list to a packet info string.
+ *  Prefixes it with the given separator if the column is not empty.
+ *  Code is duplicated from col_append_fstr above().
+ */
 void
 col_append_sep_fstr(column_info *cinfo, const gint el, const gchar *separator,
-        const gchar *format, ...)
+                   const gchar *format, ...)
 {
+  int  i;
+  int  len, max_len, sep_len;
   va_list ap;
 
   if (!CHECK_COL(cinfo, el))
@@ -319,12 +306,38 @@ col_append_sep_fstr(column_info *cinfo, const gint el, const gchar *separator,
 
   if (separator == NULL)
     separator = ", ";    /* default */
-  va_start(ap, format);
-  col_do_append_sep_va_fstr(cinfo, el, separator, format, ap);
-  va_end(ap);
-}
 
+  sep_len = (int) strlen(separator);
 
+  if (el == COL_INFO)
+    max_len = COL_MAX_INFO_LEN;
+  else
+    max_len = COL_MAX_LEN;
+
+  for (i = cinfo->col_first[el]; i <= cinfo->col_last[el]; i++) {
+    if (cinfo->fmt_matx[i][el]) {
+      /*
+       * First arrange that we can append, if necessary.
+       */
+      COL_CHECK_APPEND(cinfo, i, max_len);
+
+      len = (int) strlen(cinfo->col_buf[i]);
+
+      /*
+       * If we have a separator, append it if the column isn't empty.
+       */
+      if (sep_len != 0) {
+        if (len != 0) {
+          g_strlcat(cinfo->col_buf[i], separator, max_len);
+          len += sep_len;
+        }
+      }
+      va_start(ap, format);
+      g_vsnprintf(&cinfo->col_buf[i][len], max_len - len, format, ap);
+      va_end(ap);
+    }
+  }
+}
 
 /* Prepends a vararg list to a packet info string. */
 #define COL_BUF_MAX_LEN (((COL_MAX_INFO_LEN) > (COL_MAX_LEN)) ? \
@@ -598,19 +611,27 @@ col_has_time_fmt(column_info *cinfo, const gint col)
   return ((cinfo->fmt_matx[col][COL_CLS_TIME]) ||
           (cinfo->fmt_matx[col][COL_ABS_TIME]) ||
           (cinfo->fmt_matx[col][COL_ABS_DATE_TIME]) ||
+          (cinfo->fmt_matx[col][COL_UTC_TIME]) ||
+          (cinfo->fmt_matx[col][COL_UTC_DATE_TIME]) ||
           (cinfo->fmt_matx[col][COL_REL_TIME]) ||
           (cinfo->fmt_matx[col][COL_DELTA_TIME]) ||
           (cinfo->fmt_matx[col][COL_DELTA_TIME_DIS]));
 }
 
-static gint
-set_abs_date_time(const frame_data *fd, gchar *buf)
+static void
+set_abs_date_time(const frame_data *fd, gchar *buf, gboolean local)
 {
   struct tm *tmp;
   time_t then;
 
-  then = fd->abs_ts.secs;
-  tmp = localtime(&then);
+  if (fd->flags.has_ts) {
+    then = fd->abs_ts.secs;
+    if (local)
+       tmp = localtime(&then);
+    else
+       tmp = gmtime(&then);
+  } else
+    tmp = NULL;
   if (tmp != NULL) {
       switch(timestamp_get_precision()) {
       case TS_PREC_FIXED_SEC:
@@ -684,20 +705,29 @@ set_abs_date_time(const frame_data *fd, gchar *buf)
   } else {
     buf[0] = '\0';
   }
-  return 1;
 }
 
 static void
 col_set_abs_date_time(const frame_data *fd, column_info *cinfo, const int col)
 {
-  if (set_abs_date_time(fd, cinfo->col_buf[col])) {
-      cinfo->col_expr.col_expr[col] = "frame.time";
-      g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
-  }
+  set_abs_date_time(fd, cinfo->col_buf[col], TRUE);
+  cinfo->col_expr.col_expr[col] = "frame.time";
+  g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
+
   cinfo->col_data[col] = cinfo->col_buf[col];
 }
 
-static gint
+static void
+col_set_utc_date_time(const frame_data *fd, column_info *cinfo, const int col)
+{
+  set_abs_date_time(fd, cinfo->col_buf[col], FALSE);
+  cinfo->col_expr.col_expr[col] = "frame.time";
+  g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
+
+  cinfo->col_data[col] = cinfo->col_buf[col];
+}
+
+static void
 set_time_seconds(const nstime_t *ts, gchar *buf)
 {
   switch(timestamp_get_precision()) {
@@ -734,146 +764,176 @@ set_time_seconds(const nstime_t *ts, gchar *buf)
       default:
           g_assert_not_reached();
   }
-  return 1;
 }
 
-static gint
+static void
 set_time_hour_min_sec(const nstime_t *ts, gchar *buf)
 {
+  time_t secs = ts->secs;
+  long nsecs = (long) ts->nsecs;
+  gboolean negative = FALSE;
+
+  if (secs < 0) {
+    secs = -secs;
+    negative = TRUE;
+  }
+  if (nsecs < 0) {
+    nsecs = -nsecs;
+    negative = TRUE;
+  }
+
   switch(timestamp_get_precision()) {
   case TS_PREC_FIXED_SEC:
   case TS_PREC_AUTO_SEC:
-    if (ts->secs >= (60*60)) {
-      g_snprintf(buf, COL_MAX_LEN,"%dh %dm %ds",
-                (gint32) ts->secs / (60 * 60),
-                (gint32) (ts->secs / 60) % 60,
-                (gint32) ts->secs % 60);
-    } else if (ts->secs >= 60) {
-      g_snprintf(buf, COL_MAX_LEN,"%dh %ds",
-                (gint32) ts->secs / 60,
-                (gint32) ts->secs % 60);
+    if (secs >= (60*60)) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dh %2dm %2ds",
+                negative ? "- " : "",
+                (gint32) secs / (60 * 60),
+                (gint32) (secs / 60) % 60,
+                (gint32) secs % 60);
+    } else if (secs >= 60) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dm %2ds",
+                negative ? "- " : "",
+                (gint32) secs / 60,
+                (gint32) secs % 60);
     } else {
-      g_snprintf(buf, COL_MAX_LEN,"%ds",
-                (gint32) ts->secs);
+      g_snprintf(buf, COL_MAX_LEN, "%s%ds",
+                negative ? "- " : "",
+                (gint32) secs);
     }
     break;
   case TS_PREC_FIXED_DSEC:
   case TS_PREC_AUTO_DSEC:
-    if (ts->secs >= (60*60)) {
-      g_snprintf(buf, COL_MAX_LEN,"%dh %dm %d.%01lds",
-                (gint32) ts->secs / (60 * 60),
-                (gint32) (ts->secs / 60) % 60,
-                (gint32) ts->secs % 60,
-                (long)ts->nsecs / 100000000);
-    } else if (ts->secs >= 60) {
-      g_snprintf(buf, COL_MAX_LEN,"%dm %d.%01lds",
-                (gint32) ts->secs / 60,
-                (gint32) ts->secs % 60,
-                (long)ts->nsecs / 100000000);
+    if (secs >= (60*60)) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dh %2dm %2d.%01lds",
+                negative ? "- " : "",
+                (gint32) secs / (60 * 60),
+                (gint32) (secs / 60) % 60,
+                (gint32) secs % 60,
+                nsecs / 100000000);
+    } else if (secs >= 60) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dm %2d.%01lds",
+                negative ? "- " : "",
+                (gint32) secs / 60,
+                (gint32) secs % 60,
+                nsecs / 100000000);
     } else {
-      g_snprintf(buf, COL_MAX_LEN,"%d.%01lds",
-                (gint32) ts->secs,
-                (long)ts->nsecs / 100000000);
+      g_snprintf(buf, COL_MAX_LEN, "%s%d.%01lds",
+                negative ? "- " : "",
+                (gint32) secs,
+                nsecs / 100000000);
     }
     break;
   case TS_PREC_FIXED_CSEC:
   case TS_PREC_AUTO_CSEC:
-    if (ts->secs >= (60*60)) {
-      g_snprintf(buf, COL_MAX_LEN,"%dh %dm %d.%02lds",
-                (gint32) ts->secs / (60 * 60),
-                (gint32) (ts->secs / 60) % 60,
-                (gint32) ts->secs % 60,
-                (long)ts->nsecs / 10000000);
-    } else if (ts->secs >= 60) {
-      g_snprintf(buf, COL_MAX_LEN,"%dm %d.%02lds",
-                (gint32) ts->secs / 60,
-                (gint32) ts->secs % 60,
-                (long)ts->nsecs / 10000000);
+    if (secs >= (60*60)) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dh %2dm %2d.%02lds",
+                negative ? "- " : "",
+                (gint32) secs / (60 * 60),
+                (gint32) (secs / 60) % 60,
+                (gint32) secs % 60,
+                nsecs / 10000000);
+    } else if (secs >= 60) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dm %2d.%02lds",
+                negative ? "- " : "",
+                (gint32) secs / 60,
+                (gint32) secs % 60,
+                nsecs / 10000000);
     } else {
-      g_snprintf(buf, COL_MAX_LEN,"%d.%02lds",
-                (gint32) ts->secs,
-                (long)ts->nsecs / 10000000);
+      g_snprintf(buf, COL_MAX_LEN, "%s%d.%02lds",
+                negative ? "- " : "",
+                (gint32) secs,
+                nsecs / 10000000);
     }
     break;
   case TS_PREC_FIXED_MSEC:
   case TS_PREC_AUTO_MSEC:
-    if (ts->secs >= (60*60)) {
-      g_snprintf(buf, COL_MAX_LEN,"%dh %dm %d.%03lds",
-                (gint32) ts->secs / (60 * 60),
-                (gint32) (ts->secs / 60) % 60,
-                (gint32) ts->secs % 60,
-                (long)ts->nsecs / 1000000);
-    } else if (ts->secs >= 60) {
-      g_snprintf(buf, COL_MAX_LEN,"%dm %d.%03lds",
-                (gint32) ts->secs / 60,
-                (gint32) ts->secs % 60,
-                (long)ts->nsecs / 1000000);
+    if (secs >= (60*60)) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dh %2dm %2d.%03lds",
+                negative ? "- " : "",
+                (gint32) secs / (60 * 60),
+                (gint32) (secs / 60) % 60,
+                (gint32) secs % 60,
+                nsecs / 1000000);
+    } else if (secs >= 60) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dm %2d.%03lds",
+                negative ? "- " : "",
+                (gint32) secs / 60,
+                (gint32) secs % 60,
+                nsecs / 1000000);
     } else {
-      g_snprintf(buf, COL_MAX_LEN,"%d.%03lds",
-                (gint32) ts->secs,
-                (long)ts->nsecs / 1000000);
+      g_snprintf(buf, COL_MAX_LEN, "%s%d.%03lds",
+                negative ? "- " : "",
+                (gint32) secs,
+                nsecs / 1000000);
     }
     break;
   case TS_PREC_FIXED_USEC:
   case TS_PREC_AUTO_USEC:
-    if (ts->secs >= (60*60)) {
-      g_snprintf(buf, COL_MAX_LEN,"%dh %dm %d.%06lds",
-                (gint32) ts->secs / (60 * 60),
-                (gint32) (ts->secs / 60) % 60,
-                (gint32) ts->secs % 60,
-                (long)ts->nsecs / 1000);
-    } else if (ts->secs >= 60) {
-      g_snprintf(buf, COL_MAX_LEN,"%dm %d.%06lds",
-                (gint32) ts->secs / 60,
-                (gint32) ts->secs % 60,
-                (long)ts->nsecs / 1000);
+    if (secs >= (60*60)) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dh %2dm %2d.%06lds",
+                negative ? "- " : "",
+                (gint32) secs / (60 * 60),
+                (gint32) (secs / 60) % 60,
+                (gint32) secs % 60,
+                nsecs / 1000);
+    } else if (secs >= 60) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dm %2d.%06lds",
+                negative ? "- " : "",
+                (gint32) secs / 60,
+                (gint32) secs % 60,
+                nsecs / 1000);
     } else {
-      g_snprintf(buf, COL_MAX_LEN,"%d.%06lds",
-                (gint32) ts->secs,
-                (long)ts->nsecs / 1000);
+      g_snprintf(buf, COL_MAX_LEN, "%s%d.%06lds",
+                negative ? "- " : "",
+                (gint32) secs,
+                nsecs / 1000);
     }
     break;
   case TS_PREC_FIXED_NSEC:
   case TS_PREC_AUTO_NSEC:
-    if (ts->secs >= (60*60)) {
-      g_snprintf(buf, COL_MAX_LEN,"%dh %dm %d.%09lds",
-                (gint32) ts->secs / (60 * 60),
-                (gint32) (ts->secs / 60) % 60,
-                (gint32) ts->secs % 60,
-                (long)ts->nsecs);
-    } else if (ts->secs >= 60) {
-      g_snprintf(buf, COL_MAX_LEN,"%dm %d.%09lds",
-                (gint32) ts->secs / 60,
-                (gint32) ts->secs % 60,
-                (long)ts->nsecs);
+    if (secs >= (60*60)) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dh %2dm %2d.%09lds",
+                negative ? "- " : "",
+                (gint32) secs / (60 * 60),
+                (gint32) (secs / 60) % 60,
+                (gint32) secs % 60,
+                nsecs);
+    } else if (secs >= 60) {
+      g_snprintf(buf, COL_MAX_LEN, "%s%dm %2d.%09lds",
+                negative ? "- " : "",
+                (gint32) secs / 60,
+                (gint32) secs % 60,
+                nsecs);
     } else {
-      g_snprintf(buf, COL_MAX_LEN,"%d.%09lds",
-                (gint32) ts->secs,
-                (long)ts->nsecs);
+      g_snprintf(buf, COL_MAX_LEN, "%s%d.%09lds",
+                negative ? "- " : "",
+                (gint32) secs,
+                nsecs);
     }
     break;
   default:
     g_assert_not_reached();
   }
-
-  return 1;
 }
 
 static void
 col_set_rel_time(const frame_data *fd, column_info *cinfo, const int col)
 {
+  if (!fd->flags.has_ts) {
+    cinfo->col_buf[col][0] = '\0';
+    return;
+  }
   switch (timestamp_get_seconds_type()) {
   case TS_SECONDS_DEFAULT:
-    if (set_time_seconds(&fd->rel_ts, cinfo->col_buf[col])) {
-      cinfo->col_expr.col_expr[col] = "frame.time_relative";
-      g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
-    }
+    set_time_seconds(&fd->rel_ts, cinfo->col_buf[col]);
+    cinfo->col_expr.col_expr[col] = "frame.time_relative";
+    g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
     break;
   case TS_SECONDS_HOUR_MIN_SEC:
-    if (set_time_hour_min_sec(&fd->rel_ts, cinfo->col_buf[col])) {
-      cinfo->col_expr.col_expr[col] = "frame.time_relative";
-      set_time_seconds(&fd->rel_ts, cinfo->col_expr.col_expr_val[col]);
-    }
+    set_time_hour_min_sec(&fd->rel_ts, cinfo->col_buf[col]);
+    cinfo->col_expr.col_expr[col] = "frame.time_relative";
+    set_time_seconds(&fd->rel_ts, cinfo->col_expr.col_expr_val[col]);
     break;
   default:
     g_assert_not_reached();
@@ -884,18 +944,20 @@ col_set_rel_time(const frame_data *fd, column_info *cinfo, const int col)
 static void
 col_set_delta_time(const frame_data *fd, column_info *cinfo, const int col)
 {
+  nstime_t del_cap_ts;
+
+  frame_delta_abs_time(fd, fd->prev_cap, &del_cap_ts);
+
   switch (timestamp_get_seconds_type()) {
   case TS_SECONDS_DEFAULT:
-    if (set_time_seconds(&fd->del_cap_ts, cinfo->col_buf[col])) {
-      cinfo->col_expr.col_expr[col] = "frame.time_delta";
-      g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
-    }
+    set_time_seconds(&del_cap_ts, cinfo->col_buf[col]);
+    cinfo->col_expr.col_expr[col] = "frame.time_delta";
+    g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
     break;
   case TS_SECONDS_HOUR_MIN_SEC:
-    if (set_time_hour_min_sec(&fd->del_cap_ts, cinfo->col_buf[col])) {
-      cinfo->col_expr.col_expr[col] = "frame.time_delta";
-      set_time_seconds(&fd->del_cap_ts, cinfo->col_expr.col_expr_val[col]);
-    }
+    set_time_hour_min_sec(&del_cap_ts, cinfo->col_buf[col]);
+    cinfo->col_expr.col_expr[col] = "frame.time_delta";
+    set_time_seconds(&del_cap_ts, cinfo->col_expr.col_expr_val[col]);
     break;
   default:
     g_assert_not_reached();
@@ -907,18 +969,25 @@ col_set_delta_time(const frame_data *fd, column_info *cinfo, const int col)
 static void
 col_set_delta_time_dis(const frame_data *fd, column_info *cinfo, const int col)
 {
+  nstime_t del_dis_ts;
+
+  if (!fd->flags.has_ts) {
+    cinfo->col_buf[col][0] = '\0';
+    return;
+  }
+
+  frame_delta_abs_time(fd, fd->prev_dis, &del_dis_ts);
+
   switch (timestamp_get_seconds_type()) {
   case TS_SECONDS_DEFAULT:
-    if (set_time_seconds(&fd->del_dis_ts, cinfo->col_buf[col])) {
-      cinfo->col_expr.col_expr[col] = "frame.time_delta_displayed";
-      g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
-    }
+    set_time_seconds(&del_dis_ts, cinfo->col_buf[col]);
+    cinfo->col_expr.col_expr[col] = "frame.time_delta_displayed";
+    g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
     break;
   case TS_SECONDS_HOUR_MIN_SEC:
-    if (set_time_hour_min_sec(&fd->del_dis_ts, cinfo->col_buf[col])) {
-      cinfo->col_expr.col_expr[col] = "frame.time_delta_displayed";
-      set_time_seconds(&fd->del_dis_ts, cinfo->col_expr.col_expr_val[col]);
-    }
+    set_time_hour_min_sec(&del_dis_ts, cinfo->col_buf[col]);
+    cinfo->col_expr.col_expr[col] = "frame.time_delta_displayed";
+    set_time_seconds(&del_dis_ts, cinfo->col_expr.col_expr_val[col]);
     break;
   default:
     g_assert_not_reached();
@@ -927,14 +996,20 @@ col_set_delta_time_dis(const frame_data *fd, column_info *cinfo, const int col)
   cinfo->col_data[col] = cinfo->col_buf[col];
 }
 
-static gint
-set_abs_time(const frame_data *fd, gchar *buf)
+static void
+set_abs_time(const frame_data *fd, gchar *buf, gboolean local)
 {
   struct tm *tmp;
   time_t then;
 
-  then = fd->abs_ts.secs;
-  tmp = localtime(&then);
+  if (fd->flags.has_ts) {
+    then = fd->abs_ts.secs;
+    if (local)
+       tmp = localtime(&then);
+    else
+       tmp = gmtime(&then);
+  } else
+    tmp = NULL;
   if (tmp != NULL) {
       switch(timestamp_get_precision()) {
       case TS_PREC_FIXED_SEC:
@@ -991,22 +1066,35 @@ set_abs_time(const frame_data *fd, gchar *buf)
   } else {
     *buf = '\0';
   }
-  return 1;
 }
 
 static void
 col_set_abs_time(const frame_data *fd, column_info *cinfo, const int col)
 {
-  if (set_abs_time(fd, cinfo->col_buf[col])) {
-      cinfo->col_expr.col_expr[col] = "frame.time";
-      g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
-  }
+  set_abs_time(fd, cinfo->col_buf[col], TRUE);
+  cinfo->col_expr.col_expr[col] = "frame.time";
+  g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
+
   cinfo->col_data[col] = cinfo->col_buf[col];
 }
 
-static gint
+static void
+col_set_utc_time(const frame_data *fd, column_info *cinfo, const int col)
+{
+  set_abs_time(fd, cinfo->col_buf[col], FALSE);
+  cinfo->col_expr.col_expr[col] = "frame.time";
+  g_strlcpy(cinfo->col_expr.col_expr_val[col],cinfo->col_buf[col],COL_MAX_LEN);
+
+  cinfo->col_data[col] = cinfo->col_buf[col];
+}
+
+static gboolean
 set_epoch_time(const frame_data *fd, gchar *buf)
 {
+  if (!fd->flags.has_ts) {
+    buf[0] = '\0';
+    return FALSE;
+  }
   switch(timestamp_get_precision()) {
       case TS_PREC_FIXED_SEC:
       case TS_PREC_AUTO_SEC:
@@ -1041,7 +1129,7 @@ set_epoch_time(const frame_data *fd, gchar *buf)
       default:
           g_assert_not_reached();
   }
-  return 1;
+  return TRUE;
 }
 
 static void
@@ -1054,51 +1142,96 @@ col_set_epoch_time(const frame_data *fd, column_info *cinfo, const int col)
   cinfo->col_data[col] = cinfo->col_buf[col];
 }
 
-#if 0
-/* Set the format of the variable time format.
-   XXX - this is called from "file.c" when the user changes the time
-   format they want for "command-line-specified" time; it's a bit ugly
-   that we have to export it, but if we go to a CList-like widget that
-   invokes callbacks to get the text for the columns rather than
-   requiring us to stuff the text into the widget from outside, we
-   might be able to clean this up. */
 void
-set_cls_time(frame_data *fd, gchar *buf)
+set_fd_time(frame_data *fd, gchar *buf)
 {
-  COL_CHECK_REF_TIME(fd, cinfo->col_buf[col]);
 
   switch (timestamp_get_type()) {
     case TS_ABSOLUTE:
-      set_abs_time(fd, buf);
+      set_abs_time(fd, buf, TRUE);
       break;
 
     case TS_ABSOLUTE_WITH_DATE:
-      set_abs_date_time(fd, buf);
+      set_abs_date_time(fd, buf, TRUE);
       break;
 
     case TS_RELATIVE:
-      set_rel_time(fd, buf);
+      if (fd->flags.has_ts) {
+        switch (timestamp_get_seconds_type()) {
+        case TS_SECONDS_DEFAULT:
+          set_time_seconds(&fd->rel_ts, buf);
+          break;
+        case TS_SECONDS_HOUR_MIN_SEC:
+          set_time_seconds(&fd->rel_ts, buf);
+          break;
+        default:
+          g_assert_not_reached();
+        }
+      } else {
+        buf[0] = '\0';
+      }
       break;
 
     case TS_DELTA:
-      set_delta_time(fd, buf);
+      if (fd->flags.has_ts) {
+        nstime_t del_cap_ts;
+
+        frame_delta_abs_time(fd, fd->prev_cap, &del_cap_ts);
+
+        switch (timestamp_get_seconds_type()) {
+        case TS_SECONDS_DEFAULT:
+          set_time_seconds(&del_cap_ts, buf);
+          break;
+        case TS_SECONDS_HOUR_MIN_SEC:
+          set_time_hour_min_sec(&del_cap_ts, buf);
+          break;
+        default:
+          g_assert_not_reached();
+        }
+      } else {
+        buf[0] = '\0';
+      }
       break;
 
     case TS_DELTA_DIS:
-      set_delta_time_dis(fd, buf);
+      if (fd->flags.has_ts) {
+        nstime_t del_dis_ts;
+
+        frame_delta_abs_time(fd, fd->prev_dis, &del_dis_ts);
+
+        switch (timestamp_get_seconds_type()) {
+        case TS_SECONDS_DEFAULT:
+          set_time_seconds(&del_dis_ts, buf);
+          break;
+        case TS_SECONDS_HOUR_MIN_SEC:
+          set_time_hour_min_sec(&del_dis_ts, buf);
+          break;
+        default:
+          g_assert_not_reached();
+        }
+      } else {
+        buf[0] = '\0';
+      }
       break;
 
     case TS_EPOCH:
       set_epoch_time(fd, buf);
       break;
 
+    case TS_UTC:
+      set_abs_time(fd, buf, FALSE);
+      break;
+
+    case TS_UTC_WITH_DATE:
+      set_abs_date_time(fd, buf, FALSE);
+      break;
+
     case TS_NOT_SET:
-    /* code is missing for this case, but I don't know which [jmayer20051219] */
-    g_assert(FALSE);
-        break;
+      /* code is missing for this case, but I don't know which [jmayer20051219] */
+      g_assert(FALSE);
+      break;
   }
 }
-#endif
 
 static void
 col_set_cls_time(const frame_data *fd, column_info *cinfo, const gint col)
@@ -1128,6 +1261,14 @@ col_set_cls_time(const frame_data *fd, column_info *cinfo, const gint col)
       col_set_epoch_time(fd, cinfo, col);
       break;
 
+    case TS_UTC:
+      col_set_utc_time(fd, cinfo, col);
+      break;
+
+    case TS_UTC_WITH_DATE:
+      col_set_utc_date_time(fd, cinfo, col);
+      break;
+
     case TS_NOT_SET:
       /* code is missing for this case, but I don't know which [jmayer20051219] */
       g_assert_not_reached();
@@ -1135,14 +1276,8 @@ col_set_cls_time(const frame_data *fd, column_info *cinfo, const gint col)
   }
 }
 
-/* Set the format of the variable time format.
-   XXX - this is called from "file.c" when the user changes the time
-   format they want for "command-line-specified" time; it's a bit ugly
-   that we have to export it, but if we go to a CList-like widget that
-   invokes callbacks to get the text for the columns rather than
-   requiring us to stuff the text into the widget from outside, we
-   might be able to clean this up. */
-void
+/* Set the format of the variable time format. */
+static void
 col_set_fmt_time(const frame_data *fd, column_info *cinfo, const gint fmt, const gint col)
 {
   COL_CHECK_REF_TIME(fd, cinfo->col_buf[col]);
@@ -1172,6 +1307,14 @@ col_set_fmt_time(const frame_data *fd, column_info *cinfo, const gint fmt, const
       col_set_delta_time_dis(fd, cinfo, col);
       break;
 
+    case COL_UTC_TIME:
+      col_set_utc_time(fd, cinfo, col);
+      break;
+
+    case COL_UTC_DATE_TIME:
+      col_set_utc_date_time(fd, cinfo, col);
+      break;
+
     default:
       g_assert_not_reached();
       break;
@@ -1179,6 +1322,17 @@ col_set_fmt_time(const frame_data *fd, column_info *cinfo, const gint fmt, const
 }
 
 /* --------------------------- */
+/* Set the given (relative) time to a column element.
+ *
+ * Used by multiple dissectors to set the time in the column
+ * COL_DELTA_CONV_TIME
+ *
+ * @param cinfo                the current packet row
+ * @param col          the column to use, e.g. COL_INFO
+ * @param ts           the time to set in the column
+ * @param fieldname    the fieldname to use for creating a filter (when
+ *                       applying/preparing/copying as filter)
+ */
 void
 col_set_time(column_info *cinfo, const gint el, const nstime_t *ts, char *fieldname)
 {
@@ -1187,7 +1341,7 @@ col_set_time(column_info *cinfo, const gint el, const nstime_t *ts, char *fieldn
   if (!CHECK_COL(cinfo, el))
     return;
 
-  /* TODO: We don't respect fd->flags.ref_time (no way to access 'fd')
+  /** @todo TODO: We don't respect fd->flags.ref_time (no way to access 'fd')
   COL_CHECK_REF_TIME(fd, buf);
   */
 
@@ -1242,24 +1396,38 @@ col_set_addr(packet_info *pinfo, const int col, const address *addr, const gbool
     return;
   }
 
-#ifdef NEW_PACKET_LIST
   pinfo->cinfo->col_data[col] = se_get_addr_name(addr);
-#else
-  get_addr_name_buf(addr, pinfo->cinfo->col_buf[col], COL_MAX_LEN);
-  pinfo->cinfo->col_data[col] = pinfo->cinfo->col_buf[col];
-#endif
 
   if (!fill_col_exprs)
     return;
 
   switch (addr->type) {
 
-  case AT_ETHER:
+  case AT_AX25:
     if (is_src)
-      pinfo->cinfo->col_expr.col_expr[col] = "eth.src";
+      pinfo->cinfo->col_expr.col_expr[col] = "ax25.src";
     else
-      pinfo->cinfo->col_expr.col_expr[col] = "eth.dst";
-    address_to_str_buf(addr, pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN);
+      pinfo->cinfo->col_expr.col_expr[col] = "ax25.dst";
+    g_strlcpy(pinfo->cinfo->col_expr.col_expr_val[col], ax25_to_str(addr->data), COL_MAX_LEN);
+    break;
+
+  case AT_ETHER:
+    switch(addr->subtype) {
+    default:
+      if (is_src)
+        pinfo->cinfo->col_expr.col_expr[col] = "eth.src";
+      else
+        pinfo->cinfo->col_expr.col_expr[col] = "eth.dst";
+      address_to_str_buf(addr, pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN);
+      break;
+    case AT_SUB_IEEE80211:
+      if (is_src)
+        pinfo->cinfo->col_expr.col_expr[col] = "wlan.sa";
+      else
+        pinfo->cinfo->col_expr.col_expr[col] = "wlan.da";
+      address_to_str_buf(addr, pinfo->cinfo->col_expr.col_expr_val[col], COL_MAX_LEN);
+      break;
+    }
     break;
 
   case AT_IPv4:
@@ -1409,6 +1577,8 @@ col_based_on_frame_data(column_info *cinfo, const gint col)
     case COL_CLS_TIME:
     case COL_ABS_TIME:
     case COL_ABS_DATE_TIME:
+    case COL_UTC_TIME:
+    case COL_UTC_DATE_TIME:
     case COL_REL_TIME:
     case COL_DELTA_TIME:
     case COL_DELTA_TIME_DIS:
@@ -1434,6 +1604,8 @@ col_fill_in_frame_data(const frame_data *fd, column_info *cinfo, const gint col,
     case COL_CLS_TIME:
     case COL_ABS_TIME:
     case COL_ABS_DATE_TIME:
+    case COL_UTC_TIME:
+    case COL_UTC_DATE_TIME:
     case COL_REL_TIME:
     case COL_DELTA_TIME:
     case COL_DELTA_TIME_DIS:
@@ -1468,6 +1640,8 @@ col_fill_in_frame_data(const frame_data *fd, column_info *cinfo, const gint col,
     case COL_CLS_TIME:
     case COL_ABS_TIME:
     case COL_ABS_DATE_TIME:
+    case COL_UTC_TIME:
+    case COL_UTC_DATE_TIME:
     case COL_REL_TIME:
     case COL_DELTA_TIME:
     case COL_DELTA_TIME_DIS:
@@ -1502,6 +1676,8 @@ col_fill_in(packet_info *pinfo, const gboolean fill_col_exprs, const gboolean fi
     case COL_CLS_TIME:
     case COL_ABS_TIME:
     case COL_ABS_DATE_TIME:
+    case COL_UTC_TIME:
+    case COL_UTC_DATE_TIME:
     case COL_REL_TIME:
     case COL_DELTA_TIME:
     case COL_DELTA_TIME_DIS:
@@ -1604,6 +1780,59 @@ col_fill_in(packet_info *pinfo, const gboolean fill_col_exprs, const gboolean fi
   }
 }
 
+/*
+ * Fill in columns if we got an error reading the packet.
+ * We set most columns to "???", and set the Info column to an error
+ * message.
+ */
+void
+col_fill_in_error(column_info *cinfo, frame_data *fdata, const gboolean fill_col_exprs, const gboolean fill_fd_colums)
+{
+  int i;
+
+  if (!cinfo)
+    return;
+
+  for (i = 0; i < cinfo->num_cols; i++) {
+    switch (cinfo->col_fmt[i]) {
+
+    case COL_NUMBER:
+    case COL_CLS_TIME:
+    case COL_ABS_TIME:
+    case COL_ABS_DATE_TIME:
+    case COL_UTC_TIME:
+    case COL_UTC_DATE_TIME:
+    case COL_REL_TIME:
+    case COL_DELTA_TIME:
+    case COL_DELTA_TIME_DIS:
+    case COL_PACKET_LENGTH:
+    case COL_CUMULATIVE_BYTES:
+      if (fill_fd_colums)
+        col_fill_in_frame_data(fdata, cinfo, i, fill_col_exprs);
+      break;
+
+    case COL_INFO:
+      /* XXX - say more than this */
+      cinfo->col_data[i] = "Read error";
+      break;
+
+    case NUM_COL_FMTS:  /* keep compiler happy - shouldn't get here */
+      g_assert_not_reached();
+      break;
+    default:
+      if (cinfo->col_fmt[i] >= NUM_COL_FMTS) {
+        g_assert_not_reached();
+      }
+      /*
+       * No dissection was done, and these columns are set as the
+       * result of the dissection, so....
+       */
+      cinfo->col_data[i] = "???";
+      break;
+    }
+  }
+}
+
 #if 0
 XXX this needs more rework?
 /* --------------------------- */
@@ -1643,7 +1872,9 @@ col_fill_fdata(packet_info *pinfo)
     case COL_CUMULATIVE_BYTES: /* fd->cum_bytes */
     case COL_CLS_TIME:
     case COL_ABS_TIME:
-    case COL_ABS_DATE_TIME:    /* from fd structures */
+    case COL_ABS_DATE_TIME:
+    case COL_UTC_TIME:
+    case COL_UTC_DATE_TIME:  /* from fd structures */
     case COL_REL_TIME:
     case COL_DELTA_TIME:
     case COL_DELTA_TIME_DIS:
@@ -1781,10 +2012,16 @@ gchar  *ptr;
       set_cls_time(fd, buf);
       break;
     case COL_ABS_TIME:
-      set_abs_time(fd, buf);
+      set_abs_time(fd, buf, TRUE);
+      break;
+    case COL_UTC_TIME:
+      set_abs_time(fd, buf, FALSE);
       break;
     case COL_ABS_DATE_TIME:
-      set_abs_date_time(fd, buf);
+      set_abs_date_time(fd, buf, TRUE);
+      break;
+    case COL_UTC_DATE_TIME:
+      set_abs_date_time(fd, buf, FALSE);
       break;
     case COL_REL_TIME:
       set_rel_time(fd, buf);