Add new netstatus plugin ported from GNOME netstatus panel applet.
authorHong Jen Yee (PCMan) <pcman.tw@gmail.com>
Fri, 6 Oct 2006 22:00:50 +0000 (22:00 +0000)
committerHong Jen Yee (PCMan) <pcman.tw@gmail.com>
Fri, 6 Oct 2006 22:00:50 +0000 (22:00 +0000)
14 files changed:
src/plugins/netstatus/COPYING [new file with mode: 0644]
src/plugins/netstatus/netstatus-enums.c [new file with mode: 0644]
src/plugins/netstatus/netstatus-enums.h [new file with mode: 0644]
src/plugins/netstatus/netstatus-fallback-pixbuf.h [new file with mode: 0644]
src/plugins/netstatus/netstatus-icon.c [new file with mode: 0644]
src/plugins/netstatus/netstatus-icon.h [new file with mode: 0644]
src/plugins/netstatus/netstatus-iface.c [new file with mode: 0644]
src/plugins/netstatus/netstatus-iface.h [new file with mode: 0644]
src/plugins/netstatus/netstatus-sysdeps.c [new file with mode: 0644]
src/plugins/netstatus/netstatus-sysdeps.h [new file with mode: 0644]
src/plugins/netstatus/netstatus-util.c [new file with mode: 0644]
src/plugins/netstatus/netstatus-util.h [new file with mode: 0644]
src/plugins/netstatus/netstatus.c [new file with mode: 0644]
src/plugins/netstatus/netstatus.schemas.in [new file with mode: 0644]

diff --git a/src/plugins/netstatus/COPYING b/src/plugins/netstatus/COPYING
new file mode 100644 (file)
index 0000000..461111b
--- /dev/null
@@ -0,0 +1,9 @@
+This netstatus plug-in is ported by Hong Jen Yee (PCMan).
+The original code comes from GNOME netstatus panel applet formerly written by:
+* Erwann Chenede <erwann.chenede@sun.com>
+* Mark McLoughlin  <mark@skynet.ie>
+
+The plug-in is released under GNU GPL.
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ * Copyright (C) 2004 Red Hat Inc.
+ * Copyright (C) 2006 Hong Jen Yee
diff --git a/src/plugins/netstatus/netstatus-enums.c b/src/plugins/netstatus/netstatus-enums.c
new file mode 100644 (file)
index 0000000..c8ccf05
--- /dev/null
@@ -0,0 +1,79 @@
+
+/* Generated data (by glib-mkenums) */
+
+#include <glib-object.h>
+#include "netstatus-enums.h"
+
+
+
+/* enumerations from "./netstatus-util.h" */
+#include "./netstatus-util.h"
+
+static const GEnumValue _netstatus_state_values[] = {
+  { NETSTATUS_STATE_DISCONNECTED, "NETSTATUS_STATE_DISCONNECTED", "disconnected" },
+  { NETSTATUS_STATE_IDLE, "NETSTATUS_STATE_IDLE", "idle" },
+  { NETSTATUS_STATE_TX, "NETSTATUS_STATE_TX", "tx" },
+  { NETSTATUS_STATE_RX, "NETSTATUS_STATE_RX", "rx" },
+  { NETSTATUS_STATE_TX_RX, "NETSTATUS_STATE_TX_RX", "tx-rx" },
+  { NETSTATUS_STATE_ERROR, "NETSTATUS_STATE_ERROR", "error" },
+  { NETSTATUS_STATE_LAST, "NETSTATUS_STATE_LAST", "last" },
+  { 0, NULL, NULL }
+};
+
+GType
+netstatus_state_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    type = g_enum_register_static ("NetstatusState", _netstatus_state_values);
+
+  return type;
+}
+
+
+static const GEnumValue _netstatus_error_values[] = {
+  { NETSTATUS_ERROR_NONE, "NETSTATUS_ERROR_NONE", "none" },
+  { NETSTATUS_ERROR_ICONS, "NETSTATUS_ERROR_ICONS", "icons" },
+  { NETSTATUS_ERROR_SOCKET, "NETSTATUS_ERROR_SOCKET", "socket" },
+  { NETSTATUS_ERROR_STATISTICS, "NETSTATUS_ERROR_STATISTICS", "statistics" },
+  { NETSTATUS_ERROR_IOCTL_IFFLAGS, "NETSTATUS_ERROR_IOCTL_IFFLAGS", "ioctl-ifflags" },
+  { NETSTATUS_ERROR_IOCTL_IFCONF, "NETSTATUS_ERROR_IOCTL_IFCONF", "ioctl-ifconf" },
+  { NETSTATUS_ERROR_NO_INTERFACES, "NETSTATUS_ERROR_NO_INTERFACES", "no-interfaces" },
+  { NETSTATUS_ERROR_WIRELESS_DETAILS, "NETSTATUS_ERROR_WIRELESS_DETAILS", "wireless-details" },
+  { 0, NULL, NULL }
+};
+
+GType
+netstatus_error_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    type = g_enum_register_static ("NetstatusError", _netstatus_error_values);
+
+  return type;
+}
+
+
+static const GEnumValue _netstatus_debug_flags_values[] = {
+  { NETSTATUS_DEBUG_NONE, "NETSTATUS_DEBUG_NONE", "none" },
+  { NETSTATUS_DEBUG_POLLING, "NETSTATUS_DEBUG_POLLING", "polling" },
+  { 0, NULL, NULL }
+};
+
+GType
+netstatus_debug_flags_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    type = g_enum_register_static ("NetstatusDebugFlags", _netstatus_debug_flags_values);
+
+  return type;
+}
+
+
+
+/* Generated data ends here */
+
diff --git a/src/plugins/netstatus/netstatus-enums.h b/src/plugins/netstatus/netstatus-enums.h
new file mode 100644 (file)
index 0000000..b78c993
--- /dev/null
@@ -0,0 +1,27 @@
+
+/* Generated data (by glib-mkenums) */
+
+#ifndef __NETSTATUS_ENUMS_H__
+#define __NETSTATUS_ENUMS_H__ 1
+
+G_BEGIN_DECLS
+
+
+
+/* --- ./netstatus-util.h --- */
+#define NETSTATUS_TYPE_STATE netstatus_state_get_type()
+GType netstatus_state_get_type (void);
+
+#define NETSTATUS_TYPE_ERROR netstatus_error_get_type()
+GType netstatus_error_get_type (void);
+
+#define NETSTATUS_TYPE_DEBUG_FLAGS netstatus_debug_flags_get_type()
+GType netstatus_debug_flags_get_type (void);
+
+G_END_DECLS
+
+#endif /* __PANEL_ENUMS_H__ */
+
+
+/* Generated data ends here */
+
diff --git a/src/plugins/netstatus/netstatus-fallback-pixbuf.h b/src/plugins/netstatus/netstatus-fallback-pixbuf.h
new file mode 100644 (file)
index 0000000..44aa8fd
--- /dev/null
@@ -0,0 +1,398 @@
+/* GdkPixbuf RGBA C-Source image dump */
+
+#ifdef __SUNPRO_C
+#pragma align 4 (fallback_icon_data)
+#endif
+#ifdef __GNUC__
+static const guint8 fallback_icon_data[] __attribute__ ((__aligned__ (4))) = 
+#else
+static const guint8 fallback_icon_data[] = 
+#endif
+{ ""
+  /* Pixbuf magic (0x47646b50) */
+  "GdkP"
+  /* length: header (24) + pixel_data (9216) */
+  "\0\0$\30"
+  /* pixdata_type (0x1010002) */
+  "\1\1\0\2"
+  /* rowstride (192) */
+  "\0\0\0\300"
+  /* width (48) */
+  "\0\0\0""0"
+  /* height (48) */
+  "\0\0\0""0"
+  /* pixel_data: */
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\246\0\0\0\246\0\0\0\246\0"
+  "\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246"
+  "\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246"
+  "\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246"
+  "\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\1\0\0\0\1\0"
+  "\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\246"
+  "\377\377\377\246\377\377\377\246\377\377\377\246\377\377\377\246\377"
+  "\377\377\246\377\377\377\246\377\377\377\246\377\377\377\246\377\377"
+  "\377\246\377\377\377\246\377\377\377\246\377\377\377\246\377\377\377"
+  "\246\377\377\377\246\377\377\377\246\377\377\377\246\377\377\377\246"
+  "\377\377\377\246\377\377\377\246\377\377\377\246\377\377\377\246\377"
+  "\377\377\246\377\377\377\246\377\377\377\246\377\377\377\246\377\377"
+  "\377\246\377\377\377\246\377\377\377\246\377\377\377\246\0\0\0\246\0"
+  "\0\0\6\0\0\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\246"
+  "\377\377\377\246\303\303\303\246\303\303\303\246\303\303\303\246\303"
+  "\303\303\246\302\302\302\246\302\302\302\246\302\302\302\246\302\302"
+  "\302\246\302\302\302\246\302\302\302\246\302\302\302\246\303\303\303"
+  "\246\303\303\303\246\303\303\303\246\303\303\303\246\303\303\303\246"
+  "\303\303\303\246\302\302\302\246\302\302\302\246\302\302\302\246\302"
+  "\302\302\246\302\302\302\246\302\302\302\246\302\302\302\246\302\302"
+  "\302\246\302\302\302\246\302\302\302\246\302\302\302\246\303\303\303"
+  "\246aaa\246\0\0\0\246\0\0\0\24\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\246\377\377\377\246\303\303\303\246\303\303\303\246\303"
+  "\303\303\246\303\303\303\246\303\303\303\246\303\303\303\246\303\303"
+  "\303\246\303\303\303\246\303\303\303\246\303\303\303\246\303\303\303"
+  "\246\303\303\303\246\303\303\303\246\303\303\303\246\303\303\303\246"
+  "\303\303\303\246\303\303\303\246\303\303\303\246\303\303\303\246\303"
+  "\303\303\246\303\303\303\246\303\303\303\246\303\303\303\246\303\303"
+  "\303\246\303\303\303\246\303\303\303\246\303\304\303\246\302\302\302"
+  "\246\303\303\303\246aaa\246\0\0\0\246\0\0\0(\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\1\0\0\0\246\377\377\377\246\302\302\302\246\303\303"
+  "\303\246aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246"
+  "aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246"
+  "aaa\246aaa\246aaa\246aaa\246aaa\246\302\302\302\246\302\302\302\246\303"
+  "\303\303\246aaa\246\0\0\0\246\0\0\0""5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\1\0\0\0\246\377\377\377\246\303\303\303\246\303\303\303"
+  "\246aaa\246KKK\246KKK\246JJJ\246GGG\246CCC\246@@@\246===\246999\2466"
+  "66\246333\246///\246,,,\246)))\246%%%\246\"\"\"\246\37\37\37\246\34\34"
+  "\34\246\30\30\30\246\25\25\25\246\22\22\22\246\16\16\16\246\13\13\13"
+  "\246\10\10\10\246\377\377\377\246\302\302\302\246\303\303\303\246aaa"
+  "\246\0\0\0\246\0\0\0;\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0"
+  "\0\246\377\377\377\246\302\302\302\246\302\302\302\262\224\224\224\315"
+  "\244\244\244\342\264\264\264\362\274\274\274\374\300\300\300\377\300"
+  "\300\300\377\300\300\300\377\274\274\274\374\262\262\262\362\236\236"
+  "\236\342~~~\315III\262)))\246&&&\246###\246\37\37\37\246\34\34\34\246"
+  "\31\31\31\246\25\25\25\246\22\22\22\246\17\17\17\246\13\13\13\246\10"
+  "\10\10\246\5\5\5\246\377\377\377\246\303\303\303\246\303\303\303\246"
+  "aaa\246\0\0\0\246\0\0\0<\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2"
+  "\0\0\0\246\353\353\353\273\300\300\300\342\300\300\300\377\300\276\276"
+  "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0"
+  "\0\377\0\0\0\377\0\0\0\377\300\300\300\377\300\300\300\377\234\234\234"
+  "\342TTT\273\40\40\40\246\35\35\35\246\31\31\31\246\26\26\26\246\23\23"
+  "\23\246\17\17\17\246\14\14\14\246\11\11\11\246\5\5\5\246\2\2\2\246\377"
+  "\377\377\246\303\303\303\246\303\303\303\246aaa\246\0\0\0\246\0\0\0<"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0"
+  "\0\1\0\0\0\1\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\202\202\202\331\300\300"
+  "\300\377\300\277\277\377\0\0\0\377\0\0\0\377\0\0\0\377\371\5\5\377\367"
+  "\6\6\377\365\7\7\377\364\11\11\377\362\12\12\377\361\14\14\377\357\15"
+  "\15\377\0\0\0\377\0\0\0\377\0\0\0\377\300\300\300\377\300\300\300\377"
+  "\213\213\213\331\32\32\32\246\26\26\26\246\23\23\23\246\20\20\20\246"
+  "\14\14\14\246\11\11\11\246\6\6\6\246\3\3\3\246\0\0\0\246\377\377\377"
+  "\246\303\303\303\246\303\303\303\246aaa\246\0\0\0\246\0\0\0<\0\0\0\0"
+  "\0\0\0\0\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246"
+  "\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246$$$\262\242\242\242\354\300\300"
+  "\300\377\0\0\0\377\0\0\0\377\0\0\0\377\372\3\3\377\370\5\5\377\367\6"
+  "\6\377\365\10\10\377\364\11\11\377\362\12\12\377\360\14\14\377\357\15"
+  "\15\377\355\17\17\377\354\20\20\377\352\21\21\377\0\0\0\377\0\0\0\377"
+  "\0\0\0\377\300\300\300\377\246\246\246\354444\262\20\20\20\246\15\15"
+  "\15\246\12\12\12\246\6\6\6\246\3\3\3\246\0\0\0\246\0\0\0\246\377\377"
+  "\377\246\302\302\302\246\303\303\303\246aaa\246\0\0\0\246\0\0\0<\0\0"
+  "\0\0\0\0\0\246\377\377\377\246\377\377\377\246\377\377\377\246\377\377"
+  "\377\246\377\377\377\246\377\377\377\246\377\377\377\246\377\377\377"
+  "\246\377\377\377\246\362\362\362\262\306\306\306\362\300\277\277\377"
+  "\0\0\0\377\0\0\0\377\373\2\2\377\372\4\4\377\370\5\5\377\366\7\7\377"
+  "\365\10\10\377\363\11\11\377\362\13\13\377\360\14\14\377\356\16\16\377"
+  "\355\17\17\377\353\20\20\377\352\22\22\377\350\23\23\377\346\25\25\377"
+  "\345\26\26\377\0\0\0\377\0\0\0\377\300\300\300\377\256\256\256\36200"
+  "0\262\12\12\12\246\7\7\7\246\4\4\4\246\0\0\0\246\0\0\0\246\0\0\0\246"
+  "\377\377\377\246\302\302\302\246\303\303\303\246aaa\246\0\0\0\246\0\0"
+  "\0<\0\0\0\246\377\377\377\246\303\303\303\246\303\303\303\246\303\303"
+  "\303\246\303\303\303\246\302\302\302\246\302\302\302\246\302\302\302"
+  "\246\302\302\302\246\302\302\302\246\300\300\300\354\300\300\300\377"
+  "\40\40\40\377\0\0\0\377\373\3\3\377\371\4\4\377\370\5\5\377\366\7\7\377"
+  "\365\10\10\377\363\12\12\377\361\13\13\377\360\14\14\377\356\16\16\377"
+  "\355\17\17\377\353\21\21\377\351\22\22\377\350\23\23\377\346\25\25\377"
+  "\344\26\26\377\343\30\30\377\341\31\31\377\0\0\0\377\0\0\0\377\300\300"
+  "\300\377\244\244\244\354\7\7\7\246\4\4\4\246\1\1\1\246\0\0\0\246\0\0"
+  "\0\246\0\0\0\246\377\377\377\246\302\302\302\246\303\303\303\246aaa\246"
+  "\0\0\0\246\0\0\0<\0\0\0\246\377\377\377\246\303\303\303\246\303\303\303"
+  "\246\303\303\303\246\303\303\303\246\303\303\303\246\303\303\303\246"
+  "\303\303\303\246\303\303\303\246\300\300\300\331\300\300\300\377%%%\377"
+  "\0\0\0\377\373\3\3\377\371\4\4\377\367\6\6\377\366\7\7\377\364\10\10"
+  "\377\363\12\12\377\361\13\13\377\357\15\15\377\356\16\16\377\354\17\17"
+  "\377\353\21\21\377\351\22\22\377\347\24\24\377\346\25\25\377\344\26\26"
+  "\377\343\30\30\377\341\31\31\377\337\33\33\377\336\34\34\377\0\0\0\377"
+  "\0\0\0\377\300\300\300\377\202\202\202\332\1\1\1\246\0\0\0\246\0\0\0"
+  "\246\0\0\0\246\0\0\0\246\377\377\377\246\302\302\302\246\303\303\303"
+  "\246aaa\246\0\0\0\246\0\0\0<\0\0\0\246\377\377\377\246\302\302\302\246"
+  "\303\303\303\246aaa\246aaa\246aaa\246aaa\246aaa\246~~~\273\300\300\300"
+  "\377\26\26\26\377\0\0\0\377\372\3\3\377\371\4\4\377\367\6\6\377\366\7"
+  "\7\377\364\11\11\377\362\12\12\377\361\13\13\377\357\15\15\377\356\16"
+  "\16\377\354\20\20\377\352\21\21\377\351\22\22\377\347\24\24\377\345\25"
+  "\25\377\344\27\27\377\342\30\30\377\341\31\31\377\337\33\33\377\335\34"
+  "\34\377\334\36\36\377\332\37\37\377\0\0\0\377\0\0\0\377\300\300\300\377"
+  "<<<\273\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\377\377\377\246\302\302"
+  "\302\246\303\303\303\246aaa\246\0\0\0\246\0\0\0<\0\0\0\246\377\377\377"
+  "\246\303\303\303\246\303\303\303\246aaa\246KKK\246GGG\246DDD\246@@@\246"
+  "\241\241\241\342\300\300\300\377\0\0\0\377\372\3\3\377\370\5\5\377\367"
+  "\6\6\377\365\10\10\377\364\11\11\377\362\12\12\377\360\14\14\377\357"
+  "\15\15\377\355\17\17\377\354\20\20\377\352\21\21\377\350\23\23\377\347"
+  "\24\24\377\345\26\26\377\344\27\27\377\342\30\30\377\340\32\32\377\337"
+  "\33\33\377\335\35\35\377\334\36\36\377\332\37\37\377\330!!\377\327\""
+  "\"\377\0\0\0\377\300\300\300\377\221\221\221\344\0\0\0\247\0\0\0\246"
+  "\0\0\0\246\0\0\0\246\377\377\377\246\302\302\302\246\303\303\303\246"
+  "aaa\246\0\0\0\246\0\0\0<\0\0\0\246\377\377\377\246\302\302\302\246\303"
+  "\303\303\246aaa\246GGG\246DDD\246AAA\246VVV\262\300\300\300\377\0\0\0"
+  "\377\0\0\0\377\370\5\5\377\367\6\6\377\365\10\10\377\363\11\11\377\362"
+  "\13\13\377\360\14\14\377\357\15\15\377\355\17\17\377\353\20\20\377\352"
+  "\22\22\377\350\23\23\377\346\24\24\377\345\26\26\377\343\27\27\377\342"
+  "\31\31\377\340\32\32\377\336\33\33\377\335\35\35\377\333\36\36\377\332"
+  "\40\40\377\330!!\377\326\"\"\377\325$$\377\0\0\0\377\0\0\0\377\300\300"
+  "\300\377###\266\0\0\0\247\0\0\0\246\0\0\0\246\377\377\377\246\302\302"
+  "\302\246\303\303\303\246aaa\246\0\0\0\246\0\0\0<\0\0\0\246\377\377\377"
+  "\246\302\302\302\246\303\303\303\246aaa\246DDD\246AAA\246>>>\246\203"
+  "\203\203\315\303\265\265\377\0\0\0\377\370\5\5\377\366\7\7\377\365\10"
+  "\10\377\363\11\11\377\361\13\13\377\360\14\14\377\356\16\16\377\355\17"
+  "\17\377\353\20\20\377\351\22\22\377\350\23\23\377\346\25\25\377\345\26"
+  "\26\377\343\27\27\377\341\31\31\377\340\32\32\377\336\34\34\377\335\35"
+  "\35\377\333\36\36\377\331\40\40\377\330!!\377\326##\377\324$$\377\323"
+  "%%\377\321''\377\0\0\0\377\300\300\300\377ddd\326\0\0\0\252\0\0\0\246"
+  "\0\0\0\246\377\377\377\246\302\302\302\246\303\303\303\246aaa\246\0\0"
+  "\0\246\0\0\0<\0\0\0\246\377\377\377\246\303\303\303\246\303\303\303\246"
+  "aaa\246AAA\246>>>\246;;;\246\237\237\237\342\0\0\0\377\0\0\0\377\366"
+  "\7\7\377\364\10\10\377\363\12\12\377\361\13\13\377\360\15\15\377\356"
+  "\16\16\377\354\17\17\377\353\21\21\377\351\22\22\377\347\24\24\377\346"
+  "\25\25\377\344\26\26\377\343\30\30\377\341\31\31\377\337\33\33\377\336"
+  "\34\34\377\334\35\35\377\333\37\37\377\331\40\40\377\327\"\"\377\326"
+  "##\377\324$$\377\323&&\377\321''\377\317))\377\0\0\0\377\0\0\0\377\215"
+  "\215\215\353\0\0\0\260\0\0\0\250\0\0\0\246\377\377\377\246\302\302\302"
+  "\246\303\303\303\246aaa\246\0\0\0\246\0\0\0<\0\0\0\246\377\377\377\246"
+  "\303\303\303\246\303\303\303\246aaa\246>>>\246;;;\246888\246\262\262"
+  "\262\362\0\0\0\377\366\7\7\377\364\11\11\377\362\12\12\377\361\13\13"
+  "\377\357\15\15\377\356\16\16\377\354\20\20\377\352\21\21\377\351\22\22"
+  "\377\347\24\24\377\346\25\25\377\344\27\27\377\342\30\30\377\341\31\31"
+  "\377\337\33\33\377\336\34\34\377\334\36\36\377\332\37\37\377\331\40\40"
+  "\377\327\"\"\377\326##\377\324%%\377\322&&\377\321''\377\317))\377\315"
+  "**\377\315**\377\0\0\0\377\251\251\251\367\0\0\0\267\0\0\0\253\0\0\0"
+  "\246\377\377\377\246\302\302\302\246\303\303\303\246aaa\246\0\0\0\246"
+  "\0\0\0<\0\0\0\246\377\377\377\246\303\303\303\246\303\303\303\246aaa"
+  "\246;;;\246888\246444\246\274\274\274\374\0\0\0\377\364\11\11\377\362"
+  "\12\12\377\361\14\14\377\377\377\377\377\375\375\375\377\374\374\374"
+  "\377\373\373\373\377\372\372\372\377\371\371\371\377\370\370\370\377"
+  "\367\367\367\377\366\366\366\377\365\365\365\377\364\364\364\377\363"
+  "\363\363\377\362\362\362\377\361\361\361\377\360\360\360\377\357\357"
+  "\357\377\356\356\356\377\355\355\355\377\354\354\354\377\352\352\352"
+  "\377\353\353\353\377\315**\377\314,,\377\314,,\377\0\0\0\377\271\271"
+  "\271\375\0\0\0\301\0\0\0\260\0\0\0\250\377\377\377\246\302\302\302\246"
+  "\303\303\303\246aaa\246\0\0\0\246\0\0\0<\0\0\0\246\377\377\377\246\302"
+  "\302\302\246\303\303\303\246aaa\246888\246555\246111\246\300\300\300"
+  "\377\0\0\0\377\362\13\13\377\360\14\14\377\357\15\15\377\376\376\376"
+  "\377\375\375\375\377\374\374\374\377\373\373\373\377\372\372\372\377"
+  "\371\371\371\377\370\370\370\377\367\367\367\377\366\366\366\377\365"
+  "\365\365\377\364\364\364\377\363\363\363\377\362\362\362\377\361\361"
+  "\361\377\360\360\360\377\357\357\357\377\356\356\356\377\355\355\355"
+  "\377\354\354\354\377\353\353\353\377\353\353\353\377\313,,\377\312.."
+  "\377\30700\377\0\0\0\377\300\300\300\377\0\0\0\310\0\0\0\267\0\0\0\253"
+  "\375\375\375\246\302\302\302\246\303\303\303\246aaa\246\0\0\0\246\0\0"
+  "\0<\0\0\0\246\377\377\377\246\303\303\303\246\303\303\303\246aaa\246"
+  "555\246222\246...\246\300\300\300\377\0\0\0\377\360\14\14\377\356\16"
+  "\16\377\355\17\17\377\376\376\376\377\375\375\375\377\374\374\374\377"
+  "\373\373\373\377\372\372\372\377\371\371\371\377\370\370\370\377\367"
+  "\367\367\377\366\366\366\377\365\365\365\377\364\364\364\377\363\363"
+  "\363\377\362\362\362\377\361\361\361\377\360\360\360\377\357\357\357"
+  "\377\356\356\356\377\355\355\355\377\354\354\354\377\353\353\353\377"
+  "\353\353\353\377\311..\377\310//\377\30522\377\0\0\0\377\300\300\300"
+  "\377\0\0\0\316\0\0\0\301\0\0\0\257\370\370\370\247\302\302\302\246\303"
+  "\303\303\246aaa\246\0\0\0\246\0\0\0<\0\0\0\246\377\377\377\246\303\303"
+  "\303\246\303\303\303\246aaa\246222\246///\246+++\246\300\300\300\377"
+  "\0\0\0\377\356\16\16\377\354\17\17\377\353\21\21\377\376\376\376\377"
+  "\375\375\375\377\374\374\374\377\373\373\373\377\372\372\372\377\371"
+  "\371\371\377\370\370\370\377\367\367\367\377\366\366\366\377\365\365"
+  "\365\377\364\364\364\377\363\363\363\377\362\362\362\377\361\361\361"
+  "\377\360\360\360\377\357\357\357\377\356\356\356\377\355\355\355\377"
+  "\354\354\354\377\353\353\353\377\353\353\353\377\307//\377\30611\377"
+  "\30611\377\0\0\0\377\300\300\300\377\0\0\0\321\0\0\0\305\0\0\0\262\367"
+  "\367\367\250\302\302\302\246\303\303\303\246aaa\246\0\0\0\246\0\0\0<"
+  "\0\0\0\246\377\377\377\246\302\302\302\246\303\303\303\246aaa\246///"
+  "\246,,,\246(((\246\273\273\273\374\0\0\0\377\354\20\20\377\353\21\21"
+  "\377\351\22\22\377\376\376\376\377\375\375\375\377\374\374\374\377\373"
+  "\373\373\377\372\372\372\377\371\371\371\377\370\370\370\377\367\367"
+  "\367\377\366\366\366\377\365\365\365\377\364\364\364\377\363\363\363"
+  "\377\362\362\362\377\361\361\361\377\360\360\360\377\357\357\357\377"
+  "\356\356\356\377\355\355\355\377\354\354\354\377\353\353\353\377\353"
+  "\353\353\377\30611\377\30433\377\30433\377\0\0\0\377\271\271\271\375"
+  "\0\0\0\321\0\0\0\306\0\0\0\262\367\367\367\250\302\302\302\246\303\303"
+  "\303\246aaa\246\0\0\0\246\0\0\0<\0\0\0\246\377\377\377\246\303\303\303"
+  "\246\302\302\302\246aaa\246,,,\246(((\246%%%\246\260\260\260\362\0\0"
+  "\0\377\352\21\21\377\351\23\23\377\347\24\24\377\345\25\25\377\344\27"
+  "\27\377\342\30\30\377\341\32\32\377\337\33\33\377\335\34\34\377\334\36"
+  "\36\377\332\37\37\377\331!!\377\327\"\"\377\325##\377\324%%\377\322&"
+  "&\377\320((\377\317))\377\315**\377\314,,\377\312--\377\310//\377\307"
+  "00\377\30511\377\30433\377\30244\377\30055\377\0\0\0\377\264\264\264"
+  "\371hhh\321\210\210\210\306\314\314\314\262\367\367\367\250\302\302\302"
+  "\246\303\303\303\246aaa\246\0\0\0\246\0\0\0<\0\0\0\246\377\377\377\246"
+  "\303\303\303\246\302\302\302\246aaa\246)))\246%%%\246\"\"\"\246\232\232"
+  "\232\342\0\0\0\377\0\0\0\377\347\24\24\377\345\26\26\377\343\27\27\377"
+  "\342\30\30\377\340\32\32\377\337\33\33\377\335\35\35\377\333\36\36\377"
+  "\332\37\37\377\330!!\377\327\"\"\377\325$$\377\323%%\377\322&&\377\320"
+  "((\377\317))\377\315++\377\313,,\377\312--\377\310//\377\30700\377\305"
+  "22\377\30333\377\30244\377\30055\377\0\0\0\377\0\0\0\377\237\237\237"
+  "\361OOO\321ggg\306\233\233\233\262\274\274\274\250\302\302\302\246\303"
+  "\303\303\246aaa\246\0\0\0\246\0\0\0<\0\0\0\246\377\377\377\246\303\303"
+  "\303\246\302\302\302\246aaa\246&&&\246\"\"\"\246\37\37\37\246uuu\315"
+  "\300\300\300\377\0\0\0\377\345\26\26\377\343\27\27\377\342\31\31\377"
+  "\340\32\32\377\336\34\34\377\335\35\35\377\333\36\36\377\332\40\40\377"
+  "\330!!\377\326##\377\325$$\377\323%%\377\321''\377\320((\377\316**\377"
+  "\315++\377\313,,\377\311..\377\310//\377\30611\377\30522\377\30333\377"
+  "\30155\377\30055\377\30055\377\0\0\0\377\300\300\300\377\204\204\204"
+  "\346OOO\321ggg\306\233\233\233\262\274\274\274\250\303\303\303\246\303"
+  "\303\303\246aaa\246\0\0\0\246\0\0\0<\0\0\0\246\377\377\377\246\303\303"
+  "\303\246\303\303\303\246aaa\246###\246\37\37\37\246\34\34\34\246888\262"
+  "\300\300\300\377\0\0\0\377\0\0\0\377\341\31\31\377\340\32\32\377\336"
+  "\34\34\377\334\35\35\377\333\37\37\377\331\40\40\377\330!!\377\326##"
+  "\377\324$$\377\323&&\377\321''\377\320((\377\316**\377\314++\377\313"
+  "--\377\311..\377\310//\377\30611\377\30422\377\30344\377\30155\377\300"
+  "55\377\30055\377\0\0\0\377\0\0\0\377\300\300\300\377>>>\331'''\32133"
+  "3\306MMM\262^^^\250aaa\246aaa\246\0\0\0\246\0\0\0@\0\0\0:\0\0\0\246\377"
+  "\377\377\246\303\303\303\246\303\303\303\246aaa\246\37\37\37\246\34\34"
+  "\34\246\31\31\31\246\25\25\25\246\227\227\227\342\300\300\300\377\0\0"
+  "\0\377\337\33\33\377\336\34\34\377\334\35\35\377\333\37\37\377\331\40"
+  "\40\377\327\"\"\377\326##\377\324$$\377\322&&\377\321''\377\317))\377"
+  "\316**\377\314++\377\312--\377\311..\377\30700\377\30611\377\30422\377"
+  "\30244\377\30155\377\30055\377\30055\377\30055\377\0\0\0\377\300\300"
+  "\300\377\211\246\211\361LLL\322PPP\321iii\305\234\234\234\262^^^\250"
+  "\0\0\0\246\0\0\0\246\0\0\0A\0\0\0=\0\0\0""4\0\0\0\246\377\377\377\246"
+  "\303\303\303\246\303\303\303\246aaa\246\34\34\34\246\31\31\31\246\26"
+  "\26\26\246\22\22\22\246FFF\273\300\300\300\377\0\0\0\377\0\0\0\377\334"
+  "\36\36\377\332\37\37\377\331\40\40\377\327\"\"\377\325##\377\324%%\377"
+  "\322&&\377\321''\377\317))\377\315**\377\314,,\377\312--\377\311..\377"
+  "\30700\377\30511\377\30433\377\30244\377\30055\377\30055\377\30055\377"
+  "\30066\377\0\0\0\377\0\0\0\377\300\300\300\377OOO\335&&&\322+++\316:"
+  "::\301RRR\257\0\0\0\247\0\0\0A\0\0\0@\0\0\0<\0\0\0""5\0\0\0(\0\0\0\246"
+  "\377\377\377\246\303\303\303\246\303\303\303\246aaa\246\31\31\31\246"
+  "\26\26\26\246\23\23\23\246\17\17\17\246\14\14\14\246\204\204\204\331"
+  "\300\300\300\377\0\0\0\377\0\0\0\377\330!!\377\327\"\"\377\325$$\377"
+  "\323%%\377\322&&\377\320((\377\317))\377\315++\377\313,,\377\312--\377"
+  "\310//\377\30700\377\30522\377\30333\377\30244\377\30055\377\30055\377"
+  "\30055\377\30055\377\0\0\0\377\0\0\0\377\300\300\300\377www\354\0\0\0"
+  "\322\0\0\0\321\0\0\0\310\0\0\0\267\0\0\0\253\0\0\0B\0\0\0>\0\0\0""8\0"
+  "\0\0""0\0\0\0$\0\0\0\27\0\0\0\246\377\377\377\246\303\303\303\246\303"
+  "\303\303\246aaa\246\26\26\26\246\23\23\23\246\20\20\20\246\14\14\14\246"
+  "\11\11\11\246\6\6\6\246\242\242\242\354\300\300\300\377\0\0\0\377\0\0"
+  "\0\377\325$$\377\323%%\377\322''\377\320((\377\316))\377\315++\377\313"
+  ",,\377\312..\377\310//\377\30600\377\30522\377\30333\377\30255\377\300"
+  "55\377\30055\377\30055\377\30066\377\0\0\0\377\0\0\0\377\300\300\300"
+  "\377\256\256\256\366ddd\323fff\322VVV\316\0\0\0\301\0\0\0W\0\0\0D\0\0"
+  "\0<\0\0\0""5\0\0\0*\0\0\0\35\0\0\0\23\0\0\0\12\0\0\0\246\377\377\377"
+  "\246\303\303\303\246\303\303\303\246aaa\246\23\23\23\246\20\20\20\246"
+  "\15\15\15\246\11\11\11\246\6\6\6\246\2\2\2\246$$$\262\254\254\254\363"
+  "\300\300\300\377\0\0\0\377\0\0\0\377\321''\377\320((\377\316**\377\314"
+  "++\377\313,,\377\311..\377\310//\377\30611\377\30422\377\30333\377\301"
+  "55\377\30055\377\30055\377\30055\377\30055\377\0\0\0\377\0\0\0\377\300"
+  "\300\300\377\261\261\261\371^^^\331LLL\322OOO\321111\310\0\0\0\267\0"
+  "\0\0J\0\0\0<\0\0\0""1\0\0\0&\0\0\0\31\0\0\0\15\0\0\0\7\0\0\0\3\0\0\0"
+  "\246\377\377\377\246\303\303\303\246\303\303\303\246\302\302\302\246"
+  "\377\377\377\246\377\377\377\246\377\377\377\246\377\377\377\246\377"
+  "\377\377\246\377\377\377\246\377\377\377\246\355\355\355\263\303\303"
+  "\303\356\300\300\300\377\0\0\0\377\0\0\0\377\0\0\0\377\314++\377\313"
+  "--\377\311..\377\30700\377\30611\377\30422\377\30344\377\30155\377\300"
+  "55\377\30055\377\30055\377\0\0\0\377\0\0\0\377\0\0\0\377\300\300\300"
+  "\377\243\243\243\366>>>\331&&&\322'''\322,,,\315:::\301\0\0\0\260\0\0"
+  "\0B\0\0\0""3\0\0\0#\0\0\0\25\0\0\0\12\0\0\0\4\0\0\0\1\0\0\0\0\0\0\0\246"
+  "\377\377\377\246\303\303\303\246\303\303\303\246\303\303\303\246\303"
+  "\303\303\246\303\303\303\246\303\303\303\246\303\303\303\246\303\303"
+  "\303\246\303\303\303\246\303\303\303\246\301\301\301\246\265\265\265"
+  "\252\261\261\261\340\300\300\300\377\300\300\300\377\0\0\0\377\0\0\0"
+  "\377\0\0\0\377\313,,\377\313,,\377\30344\377\30155\377\30344\377\300"
+  "55\377\30055\377\0\0\0\377\0\0\0\377\0\0\0\377\300\300\300\377\300\300"
+  "\300\377www\354\0\0\0\323\0\0\0\322\0\0\0\322\0\0\0\315\0\0\0\303\0\0"
+  "\0\265\0\0\0\252\0\0\0=\0\0\0.\0\0\0\31\0\0\0\12\0\0\0\3\0\0\0\1\0\0"
+  "\0\0\0\0\0\0\0\0\0\246\377\377\377\246\302\302\302\246\302\302\302\246"
+  "\302\302\302\246\302\302\302\246\302\302\302\246\302\302\302\246\302"
+  "\302\302\246\302\302\302\246\302\302\302\246\302\302\302\246\302\302"
+  "\302\246\277\277\277\247\262\262\262\253\240\240\240\306\252\252\252"
+  "\354\300\300\300\377\300\300\300\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
+  "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\300\300\300"
+  "\377\300\300\300\377\237\237\237\361OOO\335\0\0\0\323\0\0\0\237\0\0\0"
+  "\236\0\0\0\224\0\0\0}\0\0\0]\0\0\0G\0\0\0=\0\0\0""6\0\0\0(\0\0\0\25\0"
+  "\0\0\7\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\246aaa\246aaa\246"
+  "aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246"
+  "___\247YYY\253III\265MMM\313uuu\343\225\225\225\360\255\255\255\370\273"
+  "\273\273\375\300\300\300\377\300\300\300\377\300\300\300\377\273\273"
+  "\273\375\254\254\254\371\224\224\224\361ppp\346>>>\331&&&\323\0\0\0\322"
+  "\0\0\0\237\0\0\0\231\0\0\0\220\0\0\0v\0\0\0Q\0\0\0""8\0\0\0.\0\0\0,\0"
+  "\0\0(\0\0\0\35\0\0\0\16\0\0\0\4\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\246\0\0\0\246aaa\246\302\302\302\246\302\302\302\246"
+  "\302\302\302\246\302\302\302\246\302\302\302\246\302\302\302\246\302"
+  "\302\302\246\302\302\302\246\302\302\302\246\302\302\302\246\277\277"
+  "\277\247\262\262\262\253\224\224\224\265uuu\301bbb\310VVV\316OOO\321"
+  "\0f\0\322\0d\0\322LLL\322LLL\323LLL\323LLL\323&&&\323\0\0\0\322\0\0\0"
+  "\322\0\0\0\235\0\0\0\224\0\0\0|\0\0\0i\0\0\0D\0\0\0&\0\0\0\31\0\0\0\26"
+  "\0\0\0\25\0\0\0\24\0\0\0\16\0\0\0\7\0\0\0\2\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\37\0\0\0*\0\0\0\246aaa\246aaa\246aaa\246"
+  "aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246___\247ZZZ\252"
+  "QQQ\260FFF\267:::\301111\310+++\316(((\320(((\321'''\321'''\321'''\321"
+  "\0\0\0\321\0\0\0\234\0\0\0\225\0\0\0\207\0\0\0r\0\0\0F\0\0\0""3\0\0\0"
+  "\31\0\0\0\12\0\0\0\7\0\0\0\7\0\0\0\7\0\0\0\6\0\0\0\4\0\0\0\2\0\0\0\1"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\16\0\0\0\31\0"
+  "\0\0$\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0"
+  "\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0"
+  "\0\0\247\0\0\0\253\0\0\0\260\0\0\0\267\0\0\0\301\0\0\0\305\0\0\0\306"
+  "\0\0\0\306\0\0\0\306\0\0\0\306\0\0\0\206\0\0\0\203\0\0\0u\0\0\0Y\0\0"
+  "\0>\0\0\0\26\0\0\0\16\0\0\0\6\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1"
+  "\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\4\0\0\0\12\0\0\0\23\0\0\0\35\0\0\0Q\0\0\0\246\377\377\377"
+  "\246\377\377\377\246\377\377\377\246\377\377\377\246\377\377\377\246"
+  "\377\377\377\246\377\377\377\246\377\377\377\246\377\377\377\246\377"
+  "\377\377\246\377\377\377\246\375\375\375\246\370\370\370\247\353\353"
+  "\353\253\327\327\327\257\316\316\316\262\233\233\233\262\0\0\0\262\0"
+  "\0\0\\\0\0\0Z\0\0\0X\0\0\0S\0\0\0E\0\0\0,\0\0\0\30\0\0\0\1\0\0\0\3\0"
+  "\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\3\0"
+  "\0\0\7\0\0\0\15\0\0\0""6\0\0\0\246\377\377\377\246\302\302\302\246\302"
+  "\302\302\246\302\302\302\246\302\302\302\246\302\302\302\246\302\302"
+  "\302\246\302\302\302\246\302\302\302\246\303\303\303\246\303\303\303"
+  "\246\303\303\303\246\303\303\303\246\300\300\300\246\276\276\276\247"
+  "\275\275\275\247^^^\247\0\0\0\250\0\0\0D\0\0\0\77\0\0\0""7\0\0\0.\0\0"
+  "\0#\0\0\0\23\0\0\0\10\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\4\0\0\0\31\0\0\0\246"
+  "\302\302\302\246aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246aaa"
+  "\246aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246aaa\246\0\0\0\246"
+  "\0\0\0>\0\0\0""3\0\0\0$\0\0\0\30\0\0\0\20\0\0\0\10\0\0\0\3\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\1\0\0\0\10\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246"
+  "\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246"
+  "\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246\0\0\0\246"
+  "\0\0\0\246\0\0\0<\0\0\0.\0\0\0\32\0\0\0\14\0\0\0\5\0\0\0\2\0\0\0\1\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\7\0\0\0\25\0\0\0(\0\0\0"
+  "6\0\0\0;\0\0\0<\0\0\0<\0\0\0<\0\0\0<\0\0\0<\0\0\0<\0\0\0<\0\0\0<\0\0"
+  "\0<\0\0\0<\0\0\0<\0\0\0<\0\0\0<\0\0\0;\0\0\0""6\0\0\0(\0\0\0\25\0\0\0"
+  "\7\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0"
+  "\0\0\4\0\0\0\16\0\0\0\35\0\0\0(\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0"
+  "\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,\0\0\0,"
+  "\0\0\0(\0\0\0\35\0\0\0\16\0\0\0\4\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\7\0\0\0\16\0\0\0\24\0\0\0"
+  "\25\0\0\0\26\0\0\0\26\0\0\0\26\0\0\0\26\0\0\0\26\0\0\0\26\0\0\0\26\0"
+  "\0\0\26\0\0\0\26\0\0\0\26\0\0\0\26\0\0\0\26\0\0\0\26\0\0\0\25\0\0\0\24"
+  "\0\0\0\16\0\0\0\7\0\0\0\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"};
+
+
diff --git a/src/plugins/netstatus/netstatus-icon.c b/src/plugins/netstatus/netstatus-icon.c
new file mode 100644 (file)
index 0000000..9f0cf28
--- /dev/null
@@ -0,0 +1,1109 @@
+/*
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * 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.
+ *
+ * Authors:
+ *     Mark McLoughlin <mark@skynet.ie>
+ */
+
+#include <config.h>
+
+#include "netstatus-icon.h"
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include "netstatus-util.h"
+#include "netstatus-enums.h"
+#include "netstatus-fallback-pixbuf.h"
+
+typedef enum
+{
+  NETSTATUS_SIGNAL_0_24 = 0,
+  NETSTATUS_SIGNAL_25_49,
+  NETSTATUS_SIGNAL_50_74,
+  NETSTATUS_SIGNAL_75_100,
+  NETSTATUS_SIGNAL_LAST
+} NetstatusSignal;
+
+struct _NetstatusIconPrivate
+{
+  GtkWidget      *image;
+  GtkWidget      *signal_image;
+  GtkWidget      *error_dialog;
+
+  NetstatusIface *iface;
+  NetstatusState  state;
+  NetstatusSignal signal_strength;
+
+  GtkIconTheme   *icon_theme;
+  GdkPixbuf      *icons [NETSTATUS_STATE_LAST];
+  GdkPixbuf      *scaled_icons [NETSTATUS_STATE_LAST];
+
+  GdkPixbuf      *signal_icons [NETSTATUS_SIGNAL_LAST];
+  GdkPixbuf      *rotated_signal_icons [NETSTATUS_SIGNAL_LAST];
+  GdkPixbuf      *scaled_signal_icons [NETSTATUS_SIGNAL_LAST];
+
+  GtkOrientation  orientation;
+  int             size;
+
+  GtkTooltips    *tooltips;
+
+  gulong          state_changed_id;
+  gulong          name_changed_id;
+  gulong          wireless_changed_id;
+  gulong          signal_changed_id;
+
+  guint           tooltips_enabled : 1;
+  guint           show_signal : 1;
+};
+
+enum {
+  INVOKED,
+  LAST_SIGNAL
+};
+
+enum {
+  PROP_0,
+  PROP_IFACE,
+  PROP_ORIENTATION,
+  PROP_TOOLTIPS_ENABLED,
+  PROP_SHOW_SIGNAL
+};
+
+static void netstatus_icon_init_pixbufs (NetstatusIcon *icon);
+static void netstatus_icon_scale_icons  (NetstatusIcon *icon,
+                                        int            height);
+
+static GObjectClass *parent_class;
+static guint icon_signals [LAST_SIGNAL] = { 0 };
+
+
+static GdkPixbuf *
+netstatus_icon_get_default_pixbuf (NetstatusIcon *icon)
+{
+  static GdkPixbuf *fallback_pixbuf = NULL;
+
+  if (!fallback_pixbuf)
+    {
+      fallback_pixbuf = gdk_pixbuf_new_from_inline (-1,
+                                                   fallback_icon_data,
+                                                   FALSE,
+                                                   NULL);
+      g_object_add_weak_pointer (G_OBJECT (fallback_pixbuf),
+                                (gpointer) &fallback_pixbuf);
+
+      return fallback_pixbuf;
+   }
+
+  return g_object_ref (fallback_pixbuf);
+}
+
+static void
+netstatus_icon_theme_changed (NetstatusIcon *icon,
+                             GtkIconTheme  *icon_theme)
+{
+  int i;
+
+  for (i = 0; i < NETSTATUS_STATE_LAST; i++)
+    {
+      g_object_unref (icon->priv->scaled_icons [i]);
+      icon->priv->scaled_icons [i] = NULL;
+
+      g_object_unref (icon->priv->icons [i]);
+      icon->priv->icons [i] = NULL;
+    }
+  
+  for (i = 0; i < NETSTATUS_SIGNAL_LAST; i++)
+    {
+      g_object_unref (icon->priv->scaled_signal_icons [i]);
+      icon->priv->scaled_signal_icons [i] = NULL;
+
+      g_object_unref (icon->priv->signal_icons [i]);
+      icon->priv->signal_icons [i] = NULL;
+    }
+
+  netstatus_icon_init_pixbufs (icon);
+
+  if (icon->priv->size)
+    {
+      netstatus_icon_scale_icons (icon, icon->priv->size);
+    }
+}
+
+static GtkIconTheme *
+netstatus_icon_get_icon_theme (NetstatusIcon *icon)
+{
+  if (!icon->priv->icon_theme)
+    {
+      GdkScreen *screen;
+
+      screen = gtk_widget_get_screen (GTK_WIDGET (icon));
+      icon->priv->icon_theme = gtk_icon_theme_get_for_screen (screen);
+
+      g_signal_connect_object (icon->priv->icon_theme, "changed",
+                              G_CALLBACK (netstatus_icon_theme_changed),
+                              icon,
+                              G_CONNECT_SWAPPED);
+    }
+
+  return icon->priv->icon_theme;
+}
+
+static char *
+netstatus_icon_lookup_icon_theme (NetstatusIcon *icon,
+                                 const char    *icon_name)
+{
+  GtkIconTheme *icon_theme;
+  GtkIconInfo  *icon_info;
+  char         *filename = NULL;
+
+  icon_theme = netstatus_icon_get_icon_theme (icon);
+
+  if ((icon_info = gtk_icon_theme_lookup_icon (icon_theme, icon_name, 1000, 0)))
+    {
+      filename = g_strdup (gtk_icon_info_get_filename (icon_info));
+
+      gtk_icon_info_free (icon_info);
+    }
+
+  return filename;
+}
+
+static void
+netstatus_icon_init_pixbuf (NetstatusIcon  *icon,
+                           GdkPixbuf     **pixbuf,
+                           const char     *icon_name)
+{
+  char *filename;
+
+  g_assert (*pixbuf == NULL);
+
+  if ((filename = netstatus_icon_lookup_icon_theme (icon, icon_name)))
+    {
+      GError *error;
+
+      error = NULL;
+      *pixbuf = gdk_pixbuf_new_from_file (filename, &error);
+      if (error)
+       {
+         netstatus_adopt_error (error, NETSTATUS_ERROR_ICONS);
+         netstatus_iface_set_error (icon->priv->iface, error);
+         g_error_free (error);
+      
+       }
+
+      g_free (filename);
+    }
+
+  if (!*pixbuf)
+    {
+      *pixbuf = netstatus_icon_get_default_pixbuf (icon);
+      g_assert (*pixbuf != NULL);
+    }
+}
+
+static GdkPixbuf *
+rotate_pixbuf (GdkPixbuf *pixbuf)
+{
+  GdkPixbuf *freeme;
+  GdkPixbuf *retval;
+  guint32   *dest;
+  guint32   *src;
+  int        width;
+  int        height;
+  int        x;
+  int        y;
+
+  freeme = NULL;
+  if (!gdk_pixbuf_get_has_alpha (pixbuf))
+    pixbuf = freeme = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
+
+  width  = gdk_pixbuf_get_width  (pixbuf);
+  height = gdk_pixbuf_get_height (pixbuf);
+
+  retval = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, height, width);
+
+  dest = (guint32 *) gdk_pixbuf_get_pixels (retval);
+  src  = (guint32 *) gdk_pixbuf_get_pixels (pixbuf);
+
+  for (y = 0; y < height; y++)
+    for (x = 0; x < width; x++)
+      dest [(height - y - 1) + height * (width - x - 1)] = src [y * width + x];
+
+  if (freeme)
+    g_object_unref (freeme);
+
+  return retval;
+}
+
+static void
+netstatus_icon_rotate_signal_icons (NetstatusIcon  *icon,
+                                   GtkOrientation  orientation)
+{
+  int i;
+
+  if (!icon->priv->signal_icons [0])
+    return;
+
+  for (i = 0; i < NETSTATUS_SIGNAL_LAST; i++)
+    {
+      GdkPixbuf *pixbuf;
+
+      if (orientation == GTK_ORIENTATION_HORIZONTAL)
+       {
+         pixbuf = g_object_ref (icon->priv->signal_icons [i]);
+       }
+      else /* if (orientation == GTK_ORIENTATION_VERTICAL) */
+       {
+         pixbuf = rotate_pixbuf (icon->priv->signal_icons [i]);
+       }
+
+      if (icon->priv->rotated_signal_icons [i])
+       g_object_unref (icon->priv->rotated_signal_icons [i]);
+      icon->priv->rotated_signal_icons [i] = pixbuf;
+
+      if (icon->priv->scaled_signal_icons [i])
+       g_object_unref (icon->priv->scaled_signal_icons [i]);
+      icon->priv->scaled_signal_icons [i] = NULL;
+    }
+}
+
+static void
+netstatus_icon_init_pixbufs (NetstatusIcon *icon)
+{
+  netstatus_icon_init_pixbuf (icon,
+                             &icon->priv->icons [NETSTATUS_STATE_DISCONNECTED],
+                             "gnome-netstatus-disconn");
+  icon->priv->scaled_icons [NETSTATUS_STATE_DISCONNECTED] = NULL;
+
+  netstatus_icon_init_pixbuf (icon,
+                             &icon->priv->icons [NETSTATUS_STATE_IDLE],
+                             "gnome-netstatus-idle");
+  icon->priv->scaled_icons [NETSTATUS_STATE_IDLE] = NULL;
+
+  netstatus_icon_init_pixbuf (icon,
+                             &icon->priv->icons [NETSTATUS_STATE_TX],
+                             "gnome-netstatus-tx");
+  icon->priv->scaled_icons [NETSTATUS_STATE_TX] = NULL;
+
+  netstatus_icon_init_pixbuf (icon,
+                             &icon->priv->icons [NETSTATUS_STATE_RX],
+                             "gnome-netstatus-rx");
+  icon->priv->scaled_icons [NETSTATUS_STATE_RX] = NULL;
+
+  netstatus_icon_init_pixbuf (icon,
+                             &icon->priv->icons [NETSTATUS_STATE_TX_RX],
+                             "gnome-netstatus-txrx");
+  icon->priv->scaled_icons [NETSTATUS_STATE_TX_RX] = NULL;
+
+  netstatus_icon_init_pixbuf (icon,
+                             &icon->priv->icons [NETSTATUS_STATE_ERROR],
+                             "gnome-netstatus-error");
+  icon->priv->scaled_icons [NETSTATUS_STATE_ERROR] = NULL;
+
+  netstatus_icon_init_pixbuf (icon,
+                             &icon->priv->signal_icons [NETSTATUS_SIGNAL_0_24],
+                             "gnome-netstatus-0-24");
+  icon->priv->rotated_signal_icons [NETSTATUS_SIGNAL_0_24] = NULL;
+  icon->priv->scaled_signal_icons  [NETSTATUS_SIGNAL_0_24] = NULL;
+
+  netstatus_icon_init_pixbuf (icon,
+                             &icon->priv->signal_icons [NETSTATUS_SIGNAL_25_49],
+                             "gnome-netstatus-25-49");
+  icon->priv->rotated_signal_icons [NETSTATUS_SIGNAL_25_49] = NULL;
+  icon->priv->scaled_signal_icons  [NETSTATUS_SIGNAL_25_49] = NULL;
+
+  netstatus_icon_init_pixbuf (icon,
+                             &icon->priv->signal_icons [NETSTATUS_SIGNAL_50_74],
+                             "gnome-netstatus-50-74");
+  icon->priv->rotated_signal_icons [NETSTATUS_SIGNAL_50_74] = NULL;
+  icon->priv->scaled_signal_icons  [NETSTATUS_SIGNAL_50_74] = NULL;
+
+  netstatus_icon_init_pixbuf (icon,
+                             &icon->priv->signal_icons [NETSTATUS_SIGNAL_75_100],
+                             "gnome-netstatus-75-100");
+  icon->priv->rotated_signal_icons [NETSTATUS_SIGNAL_75_100] = NULL;
+  icon->priv->scaled_signal_icons  [NETSTATUS_SIGNAL_75_100] = NULL;
+
+  netstatus_icon_rotate_signal_icons (icon, icon->priv->orientation);
+}
+
+static void
+netstatus_icon_update_image (NetstatusIcon *icon)
+{
+  GdkPixbuf *pixbuf;
+
+  if (!icon->priv->icons [icon->priv->state])
+    netstatus_icon_init_pixbufs (icon);
+
+  pixbuf = icon->priv->scaled_icons [icon->priv->state];
+  if (!pixbuf)
+    pixbuf = icon->priv->icons [icon->priv->state];
+
+  if (gtk_image_get_pixbuf (GTK_IMAGE (icon->priv->image)) != pixbuf)
+    gtk_image_set_from_pixbuf (GTK_IMAGE (icon->priv->image), pixbuf);
+
+  pixbuf = icon->priv->scaled_signal_icons [icon->priv->signal_strength];
+  if (!pixbuf)
+    pixbuf = icon->priv->rotated_signal_icons [icon->priv->signal_strength];
+  
+  if (gtk_image_get_pixbuf (GTK_IMAGE (icon->priv->signal_image)) != pixbuf)
+    gtk_image_set_from_pixbuf (GTK_IMAGE (icon->priv->signal_image), pixbuf);
+}
+
+static void
+netstatus_icon_name_changed (NetstatusIface *iface,
+                            GParamSpec     *pspec,
+                            NetstatusIcon  *icon)
+{
+  const char *iface_name;
+  const char *tip;
+  char       *freeme = NULL;
+
+  iface_name = netstatus_iface_get_name (icon->priv->iface);
+  if (iface_name)
+    {
+      freeme = g_strdup_printf (_("Network Connection: %s"), iface_name);
+      tip = freeme;
+    }
+  else
+    {
+      tip = _("Network Connection");
+    }
+
+  gtk_tooltips_set_tip (icon->priv->tooltips, GTK_WIDGET (icon), tip, NULL);
+
+  g_free (freeme);
+}
+
+static void
+netstatus_icon_state_changed (NetstatusIface *iface,
+                             GParamSpec     *pspec,
+                             NetstatusIcon  *icon)
+{
+  NetstatusState state;
+
+  g_return_if_fail (NETSTATUS_IS_ICON (icon));
+
+  state = netstatus_iface_get_state (iface);
+
+  if (icon->priv->state != state)
+    {
+      icon->priv->state = state;
+
+      netstatus_icon_update_image (icon);
+    }
+}
+
+static void
+netstatus_icon_is_wireless_changed (NetstatusIface *iface,
+                                   GParamSpec     *pspec,
+                                   NetstatusIcon  *icon)
+{
+  if (netstatus_iface_get_is_wireless (iface) && icon->priv->show_signal)
+    gtk_widget_show (icon->priv->signal_image);
+  else
+    gtk_widget_hide (icon->priv->signal_image);
+}
+
+static void
+netstatus_icon_signal_changed (NetstatusIface *iface,
+                              GParamSpec     *pspec,
+                              NetstatusIcon  *icon)
+{
+  NetstatusSignal signal_strength;
+  int             percent;
+
+  percent = netstatus_iface_get_signal_strength (iface);
+
+  if (percent < 25)
+    signal_strength = NETSTATUS_SIGNAL_0_24;
+  else if (percent < 50)
+    signal_strength = NETSTATUS_SIGNAL_25_49;
+  else if (percent < 75)
+    signal_strength = NETSTATUS_SIGNAL_50_74;
+  else
+    signal_strength = NETSTATUS_SIGNAL_75_100;
+
+  if (icon->priv->signal_strength != signal_strength)
+    {
+      icon->priv->signal_strength = signal_strength;
+
+      netstatus_icon_update_image (icon);
+    }
+}
+
+static void
+netstatus_icon_destroy (GtkObject *widget)
+{
+  NetstatusIcon *icon = (NetstatusIcon *) widget;
+
+  if (icon->priv->error_dialog)
+    gtk_widget_destroy (icon->priv->error_dialog);
+  icon->priv->error_dialog = NULL;
+
+  if (icon->priv->state_changed_id)
+    {
+      g_assert (icon->priv->iface != NULL);
+      g_assert (icon->priv->name_changed_id != 0);
+      g_signal_handler_disconnect (icon->priv->iface,
+                                  icon->priv->state_changed_id);
+      g_signal_handler_disconnect (icon->priv->iface,
+                                  icon->priv->name_changed_id);
+      g_signal_handler_disconnect (icon->priv->iface,
+                                  icon->priv->wireless_changed_id);
+      g_signal_handler_disconnect (icon->priv->iface,
+                                  icon->priv->signal_changed_id);
+    }
+  icon->priv->state_changed_id    = 0;
+  icon->priv->name_changed_id     = 0;
+  icon->priv->wireless_changed_id = 0;
+  icon->priv->signal_changed_id   = 0;
+
+  if (icon->priv->tooltips)
+    g_object_unref (icon->priv->tooltips);
+  icon->priv->tooltips = NULL;
+  
+  icon->priv->image = NULL;
+
+  GTK_OBJECT_CLASS (parent_class)->destroy (widget);
+}
+
+static GdkPixbuf *
+scale_pixbuf (GdkPixbuf      *pixbuf,
+             GtkOrientation  orientation,
+             int             size,
+             gboolean        retain_aspect)
+{
+  GdkPixbuf *retval;
+  int        orig_size;
+
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
+      orig_size = gdk_pixbuf_get_height (pixbuf);
+    }
+  else /* if (orientation == GTK_ORIENTATION_VERTICAL) */
+    {
+      orig_size = gdk_pixbuf_get_width (pixbuf);
+    }
+
+  if (size >= orig_size)
+    {
+      retval = g_object_ref (pixbuf);
+    }
+  else
+    {
+      int    orig_width;
+      int    orig_height;
+      int    scaled_width;
+      int    scaled_height;
+      double scale;
+
+      orig_width  = gdk_pixbuf_get_width  (pixbuf);
+      orig_height = gdk_pixbuf_get_height (pixbuf);
+
+      scale = (double) size / orig_size;
+
+      if (retain_aspect)
+       {
+         scaled_width  = orig_width  * scale;
+         scaled_height = orig_height * scale;
+       }
+      else
+       {
+         if (orientation == GTK_ORIENTATION_HORIZONTAL)
+           {
+             scaled_width  = orig_width;
+             scaled_height = orig_height * scale;
+           }
+         else /* if (orientation == GTK_ORIENTATION_VERTICAL) */
+           {
+             scaled_width  = orig_width * scale;
+             scaled_height = orig_height;
+           }
+       }
+
+      retval = gdk_pixbuf_scale_simple (pixbuf,
+                                       scaled_width,
+                                       scaled_height,
+                                       GDK_INTERP_BILINEAR);
+    }
+
+  return retval;
+}
+
+static void
+netstatus_icon_scale_icons (NetstatusIcon  *icon,
+                           int             size)
+{
+  int i;
+
+  g_return_if_fail (size > 0);
+
+  if (!icon->priv->icons [0])
+    netstatus_icon_init_pixbufs (icon);
+
+  for (i = 0; i < NETSTATUS_STATE_LAST; i++)
+    {
+      if (icon->priv->scaled_icons [i])
+       g_object_unref (icon->priv->scaled_icons [i]);
+      icon->priv->scaled_icons [i] = scale_pixbuf (icon->priv->icons [i],
+                                                  icon->priv->orientation,
+                                                  size,
+                                                  TRUE);
+    }
+
+  for (i = 0; i < NETSTATUS_SIGNAL_LAST; i++)
+    {
+      if (icon->priv->scaled_signal_icons [i])
+       g_object_unref (icon->priv->scaled_signal_icons [i]);
+      icon->priv->scaled_signal_icons [i] = scale_pixbuf (icon->priv->rotated_signal_icons [i],
+                                                         icon->priv->orientation,
+                                                         size,
+                                                         TRUE);
+    }
+
+  netstatus_icon_update_image (icon);
+}
+
+static inline GObjectClass *
+get_box_class (GtkOrientation orientation)
+{
+  return gtk_type_class (orientation == GTK_ORIENTATION_HORIZONTAL ? GTK_TYPE_HBOX : GTK_TYPE_VBOX);
+}
+
+static void
+netstatus_icon_size_request (GtkWidget      *widget,
+                            GtkRequisition *requisition)
+{
+  NetstatusIcon *icon = NETSTATUS_ICON (widget);
+  GObjectClass  *klass;
+
+  klass = get_box_class (icon->priv->orientation);
+
+  if (GTK_WIDGET_CLASS (klass)->size_request)
+    GTK_WIDGET_CLASS (klass)->size_request (widget, requisition);
+}
+
+static void
+netstatus_icon_size_allocate (GtkWidget     *widget,
+                             GtkAllocation *allocation)
+{
+  NetstatusIcon *icon = (NetstatusIcon *) widget;
+  GtkAllocation  child_allocation;
+  GObjectClass  *klass;
+  int            size;
+
+  if (icon->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+    size = allocation->height;
+  else
+    size = allocation->width;
+
+  if (icon->priv->size != size)
+    {
+      icon->priv->size = size;
+
+      netstatus_icon_scale_icons (icon, size);
+    }
+
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+      gdk_window_move_resize (widget->window,
+                              allocation->x + GTK_CONTAINER (widget)->border_width,
+                              allocation->y + GTK_CONTAINER (widget)->border_width,
+                              MAX (allocation->width - GTK_CONTAINER (widget)->border_width * 2, 0),
+                             MAX (allocation->height - GTK_CONTAINER (widget)->border_width * 2, 0));
+    }
+
+  klass = get_box_class (icon->priv->orientation);
+
+  child_allocation.x = 0;
+  child_allocation.y = 0;
+  child_allocation.width  = MAX (allocation->width  - GTK_CONTAINER (widget)->border_width * 2, 0);
+  child_allocation.height = MAX (allocation->height - GTK_CONTAINER (widget)->border_width * 2, 0);
+
+  if (GTK_WIDGET_CLASS (klass)->size_allocate)
+    GTK_WIDGET_CLASS (klass)->size_allocate (widget, &child_allocation);
+
+  widget->allocation = *allocation;
+}
+
+static void
+netstatus_icon_realize (GtkWidget *widget)
+{
+  GdkWindowAttr attributes;
+  int           attributes_mask;
+  int           border_width;
+
+  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+  
+  border_width = GTK_CONTAINER (widget)->border_width;
+
+  attributes.x = widget->allocation.x + border_width;
+  attributes.y = widget->allocation.y + border_width;
+  attributes.width = widget->allocation.width - 2 * border_width;
+  attributes.height = widget->allocation.height - 2 * border_width;
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.colormap = gtk_widget_get_colormap (widget);
+  attributes.event_mask = gtk_widget_get_events (widget) |
+                          GDK_BUTTON_MOTION_MASK         |
+                          GDK_BUTTON_PRESS_MASK          |
+                          GDK_BUTTON_RELEASE_MASK        |
+                          GDK_EXPOSURE_MASK              |
+                          GDK_ENTER_NOTIFY_MASK          |
+                          GDK_LEAVE_NOTIFY_MASK;
+
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+  widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
+  gdk_window_set_user_data (widget->window, widget);
+
+  widget->style = gtk_style_attach (widget->style, widget->window);
+  gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+}
+
+static gboolean
+netstatus_icon_button_press_event (GtkWidget      *widget,
+                                  GdkEventButton *event)
+{
+  if (event->button == 1)
+    {
+      netstatus_icon_invoke (NETSTATUS_ICON (widget));
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+netstatus_icon_set_property (GObject      *object,
+                            guint         prop_id,
+                            const GValue *value,
+                            GParamSpec   *pspec)
+{
+  NetstatusIcon *icon;
+
+  g_return_if_fail (NETSTATUS_IS_ICON (object));
+
+  icon = NETSTATUS_ICON (object);
+
+  switch (prop_id)
+    {
+    case PROP_IFACE:
+      netstatus_icon_set_iface (icon, g_value_get_object (value));
+      break;
+    case PROP_ORIENTATION:
+      netstatus_icon_set_orientation (icon, g_value_get_enum (value));
+      break;
+    case PROP_TOOLTIPS_ENABLED:
+      netstatus_icon_set_tooltips_enabled (icon, g_value_get_boolean (value));
+      break;
+    case PROP_SHOW_SIGNAL:
+      netstatus_icon_set_show_signal (icon, g_value_get_boolean (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+netstatus_icon_get_property (GObject    *object,
+                            guint       prop_id,
+                            GValue     *value,
+                            GParamSpec *pspec)
+{
+  NetstatusIcon *icon;
+
+  g_return_if_fail (NETSTATUS_IS_ICON (object));
+
+  icon = NETSTATUS_ICON (object);
+
+  switch (prop_id)
+    {
+    case PROP_IFACE:
+      g_value_set_object (value, icon->priv->iface);
+      break;
+    case PROP_ORIENTATION:
+      g_value_set_enum (value, icon->priv->orientation);
+      break;
+    case PROP_TOOLTIPS_ENABLED:
+      g_value_set_boolean (value, icon->priv->tooltips_enabled);
+      break;
+    case PROP_SHOW_SIGNAL:
+      g_value_set_boolean (value, icon->priv->show_signal);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+netstatus_icon_finalize (GObject *object)
+{
+  NetstatusIcon *icon = (NetstatusIcon *) object;
+  int            i;
+
+  if (icon->priv->iface)
+    g_object_unref (icon->priv->iface);
+  icon->priv->iface = NULL;
+
+  for (i = 0; i < NETSTATUS_STATE_LAST; i++) 
+    {
+      if (icon->priv->icons [i])
+       g_object_unref (icon->priv->icons [i]);
+      icon->priv->icons [i] = NULL;
+
+      if (icon->priv->scaled_icons [i])
+       g_object_unref (icon->priv->scaled_icons [i]);
+      icon->priv->scaled_icons [i] = NULL;
+    }
+
+  g_free (icon->priv);
+  icon->priv = NULL;
+
+  parent_class->finalize (object);
+}
+
+static void
+netstatus_icon_class_init (NetstatusIconClass *klass)
+{
+  GObjectClass   *gobject_class   = (GObjectClass   *) klass;
+  GtkObjectClass *gtkobject_class = (GtkObjectClass *) klass;
+  GtkWidgetClass *widget_class    = (GtkWidgetClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->set_property = netstatus_icon_set_property;
+  gobject_class->get_property = netstatus_icon_get_property;
+  gobject_class->finalize     = netstatus_icon_finalize;
+
+  gtkobject_class->destroy = netstatus_icon_destroy;
+
+  widget_class->size_request       = netstatus_icon_size_request;
+  widget_class->size_allocate      = netstatus_icon_size_allocate;
+  widget_class->realize            = netstatus_icon_realize;
+  widget_class->button_press_event = netstatus_icon_button_press_event;
+
+  g_object_class_install_property (gobject_class,
+                                  PROP_IFACE,
+                                  g_param_spec_object ("iface",
+                                                       _("Interface"),
+                                                       _("The current interface the icon is monitoring."),
+                                                       NETSTATUS_TYPE_IFACE,
+                                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+  
+  g_object_class_install_property (gobject_class,
+                                   PROP_ORIENTATION,
+                                   g_param_spec_enum ("orientation",
+                                                      _("Orientation"),
+                                                      _("The orientation of the tray."),
+                                                      GTK_TYPE_ORIENTATION,
+                                                      GTK_ORIENTATION_HORIZONTAL,
+                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_TOOLTIPS_ENABLED,
+                                   g_param_spec_boolean ("tooltips-enabled",
+                                                        _("Tooltips Enabled"),
+                                                        _("Whether or not the icon's tooltips are enabled."),
+                                                        TRUE,
+                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_SHOW_SIGNAL,
+                                   g_param_spec_boolean ("show-signal",
+                                                        _("Show Signal"),
+                                                        _("Whether or not the signal strength should be displayed."),
+                                                        TRUE,
+                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+  icon_signals [INVOKED] =
+    g_signal_new ("invoked",
+                 G_OBJECT_CLASS_TYPE (gobject_class),
+                 G_SIGNAL_RUN_FIRST,
+                 G_STRUCT_OFFSET (NetstatusIconClass, invoked),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE, 0);
+}
+
+static void
+netstatus_icon_instance_init (NetstatusIcon      *icon,
+                             NetstatusIconClass *klass)
+{
+  icon->priv = g_new0 (NetstatusIconPrivate, 1);
+
+  GTK_WIDGET_UNSET_FLAGS (icon, GTK_NO_WINDOW);
+
+  icon->priv->iface            = NULL;
+  icon->priv->state            = NETSTATUS_STATE_DISCONNECTED;
+  icon->priv->orientation      = GTK_ORIENTATION_HORIZONTAL;
+  icon->priv->size             = 0;
+  icon->priv->state_changed_id = 0;
+
+  gtk_box_set_spacing (GTK_BOX (icon), 3);
+
+  icon->priv->image = gtk_image_new ();
+  gtk_container_add (GTK_CONTAINER (icon), icon->priv->image);
+  gtk_widget_show (icon->priv->image);
+
+  icon->priv->signal_image = gtk_image_new ();
+  gtk_container_add (GTK_CONTAINER (icon), icon->priv->signal_image);
+  gtk_widget_hide (icon->priv->signal_image);
+
+  icon->priv->tooltips = gtk_tooltips_new ();
+  g_object_ref (icon->priv->tooltips);
+  gtk_object_sink (GTK_OBJECT (icon->priv->tooltips));
+
+  gtk_widget_add_events (GTK_WIDGET (icon),
+                        GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
+}
+
+GType
+netstatus_icon_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo info =
+       {
+         sizeof (NetstatusIconClass),
+         NULL,
+         NULL,
+         (GClassInitFunc) netstatus_icon_class_init,
+         NULL,
+         NULL,
+         sizeof (NetstatusIcon),
+         0,
+         (GInstanceInitFunc) netstatus_icon_instance_init,
+         NULL
+       };
+
+      type = g_type_register_static (GTK_TYPE_BOX, "NetstatusIcon", &info, 0);
+    }
+
+  return type;
+}
+
+GtkWidget *
+netstatus_icon_new (NetstatusIface *iface)
+{
+  return g_object_new (NETSTATUS_TYPE_ICON,
+                      "iface", iface,
+                      NULL);
+}
+
+void
+netstatus_icon_invoke (NetstatusIcon *icon)
+{
+  g_return_if_fail (NETSTATUS_IS_ICON (icon));
+
+  if (netstatus_iface_get_state (icon->priv->iface) != NETSTATUS_STATE_ERROR)
+    {
+      if (icon->priv->error_dialog)
+       gtk_widget_destroy (icon->priv->error_dialog);
+      icon->priv->error_dialog = NULL;
+
+      g_signal_emit (icon, icon_signals [INVOKED], 0);
+    }
+  else
+    {
+      const GError *error;
+
+      error = netstatus_iface_get_error (icon->priv->iface);
+      g_assert (error != NULL);
+
+      if (icon->priv->error_dialog)
+        {
+         gtk_window_set_screen (GTK_WINDOW (icon->priv->error_dialog),
+                                gtk_widget_get_screen (GTK_WIDGET (icon)));
+          gtk_window_present (GTK_WINDOW (icon->priv->error_dialog));
+          return;
+        }
+
+      icon->priv->error_dialog =
+       gtk_message_dialog_new (NULL, 0,
+                               GTK_MESSAGE_ERROR,
+                               GTK_BUTTONS_CLOSE,
+                               _("Please contact your system administrator to resolve the following problem:\n\n%s"),
+                               error->message);
+
+      gtk_window_set_screen (GTK_WINDOW (icon->priv->error_dialog),
+                            gtk_widget_get_screen (GTK_WIDGET (icon)));
+
+      g_signal_connect (icon->priv->error_dialog, "response",
+                       G_CALLBACK (gtk_widget_destroy), NULL);
+      g_signal_connect (icon->priv->error_dialog, "destroy",
+                        G_CALLBACK (gtk_widget_destroyed),
+                       &icon->priv->error_dialog);
+
+      gtk_widget_show (icon->priv->error_dialog);
+    }
+}
+
+void
+netstatus_icon_set_iface (NetstatusIcon  *icon,
+                         NetstatusIface *iface)
+{
+
+  g_return_if_fail (NETSTATUS_IS_ICON (icon));
+
+  if (icon->priv->iface != iface)
+    {
+      NetstatusIface *old_iface;
+
+      old_iface = icon->priv->iface;
+
+      if (icon->priv->state_changed_id)
+       {
+         g_assert (icon->priv->iface != NULL);
+         g_assert (icon->priv->name_changed_id != 0);
+         g_signal_handler_disconnect (icon->priv->iface,
+                                      icon->priv->state_changed_id);
+         g_signal_handler_disconnect (icon->priv->iface,
+                                      icon->priv->name_changed_id);
+         g_signal_handler_disconnect (icon->priv->iface,
+                                      icon->priv->wireless_changed_id);
+         g_signal_handler_disconnect (icon->priv->iface,
+                                      icon->priv->signal_changed_id);
+       }
+
+      if (iface)
+       g_object_ref (iface);
+      icon->priv->iface = iface;
+
+      if (old_iface)
+       g_object_unref (old_iface);
+
+      icon->priv->state_changed_id     = g_signal_connect (icon->priv->iface, "notify::state",
+                                                          G_CALLBACK (netstatus_icon_state_changed), icon);
+      icon->priv->name_changed_id      = g_signal_connect (icon->priv->iface, "notify::name",
+                                                          G_CALLBACK (netstatus_icon_name_changed), icon);
+      icon->priv->wireless_changed_id  = g_signal_connect (icon->priv->iface, "notify::wireless",
+                                                          G_CALLBACK (netstatus_icon_is_wireless_changed), icon);
+      icon->priv->signal_changed_id    = g_signal_connect (icon->priv->iface, "notify::signal-strength",
+                                                          G_CALLBACK (netstatus_icon_signal_changed), icon);
+
+      netstatus_icon_state_changed       (icon->priv->iface, NULL, icon);
+      netstatus_icon_name_changed        (icon->priv->iface, NULL, icon);
+      netstatus_icon_is_wireless_changed (icon->priv->iface, NULL, icon);
+      netstatus_icon_signal_changed      (icon->priv->iface, NULL, icon);
+
+      g_object_notify (G_OBJECT (icon), "iface");
+    }
+}
+
+NetstatusIface *
+netstatus_icon_get_iface (NetstatusIcon *icon)
+{
+  g_return_val_if_fail (NETSTATUS_IS_ICON (icon), 0);
+
+  return icon->priv->iface;
+}
+
+void
+netstatus_icon_set_orientation (NetstatusIcon  *icon,
+                               GtkOrientation  orientation)
+{
+  g_return_if_fail (NETSTATUS_IS_ICON (icon));
+
+  if (icon->priv->orientation != orientation)
+    {
+      icon->priv->orientation = orientation;
+
+      netstatus_icon_rotate_signal_icons (icon, orientation);
+      netstatus_icon_update_image (icon);
+
+      icon->priv->size = -1;
+
+      gtk_widget_queue_resize (GTK_WIDGET (icon));
+
+      g_object_notify (G_OBJECT (icon), "orientation");
+    }
+}
+
+GtkOrientation
+netstatus_icon_get_orientation (NetstatusIcon *icon)
+{
+  g_return_val_if_fail (NETSTATUS_IS_ICON (icon), GTK_ORIENTATION_HORIZONTAL);
+
+  return icon->priv->orientation;
+}
+
+void
+netstatus_icon_set_tooltips_enabled (NetstatusIcon *icon,
+                                    gboolean       enabled)
+{
+  g_return_if_fail (NETSTATUS_IS_ICON (icon));
+
+  enabled = enabled != FALSE;
+
+  if (icon->priv->tooltips_enabled != enabled)
+    {
+      icon->priv->tooltips_enabled = enabled;
+
+      if (enabled)
+       gtk_tooltips_enable (icon->priv->tooltips);
+      else
+       gtk_tooltips_disable (icon->priv->tooltips);
+
+      g_object_notify (G_OBJECT (icon), "tooltips-enabled");
+    }
+}
+
+gboolean
+netstatus_icon_get_tooltips_enabled (NetstatusIcon *icon)
+{
+  g_return_val_if_fail (NETSTATUS_ICON (icon), TRUE);
+
+  return icon->priv->tooltips_enabled;
+}
+
+void
+netstatus_icon_set_show_signal (NetstatusIcon *icon,
+                               gboolean       show_signal)
+{
+  g_return_if_fail (NETSTATUS_IS_ICON (icon));
+
+  show_signal = show_signal != FALSE;
+
+  if (icon->priv->show_signal != show_signal)
+    {
+      icon->priv->show_signal = show_signal;
+
+      if (show_signal && netstatus_iface_get_is_wireless (icon->priv->iface))
+       gtk_widget_show (icon->priv->signal_image);
+      else
+       gtk_widget_hide (icon->priv->signal_image);
+
+      g_object_notify (G_OBJECT (icon), "show-signal");
+    }
+}
+
+gboolean
+netstatus_icon_get_show_signal (NetstatusIcon *icon)
+{
+  g_return_val_if_fail (NETSTATUS_ICON (icon), TRUE);
+
+  return icon->priv->show_signal;
+}
diff --git a/src/plugins/netstatus/netstatus-icon.h b/src/plugins/netstatus/netstatus-icon.h
new file mode 100644 (file)
index 0000000..311b0f6
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * 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.
+
+ * Authors:
+ *     Mark McLoughlin <mark@skynet.ie>
+ */
+
+#ifndef __NETSTATUS_ICON_H__
+#define __NETSTATUS_ICON_H__
+
+#include <gtk/gtk.h>
+
+#include "netstatus-iface.h"
+
+G_BEGIN_DECLS
+
+#define NETSTATUS_TYPE_ICON         (netstatus_icon_get_type ())
+#define NETSTATUS_ICON(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), NETSTATUS_TYPE_ICON, NetstatusIcon))
+#define NETSTATUS_ICON_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), NETSTATUS_TYPE_ICON, NetstatusIconClass))
+#define NETSTATUS_IS_ICON(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), NETSTATUS_TYPE_ICON))
+#define NETSTATUS_IS_ICON_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), NETSTATUS_TYPE_ICON))
+#define NETSTATUS_ICON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NETSTATUS_TYPE_ICON, NetstatusIconClass))
+
+typedef struct _NetstatusIcon        NetstatusIcon;
+typedef struct _NetstatusIconClass   NetstatusIconClass;
+typedef struct _NetstatusIconPrivate NetstatusIconPrivate;
+
+struct _NetstatusIcon
+{
+  GtkBox                 box_instance;
+
+  NetstatusIconPrivate  *priv;
+};
+
+struct _NetstatusIconClass
+{
+  GtkBoxClass      box_class;
+
+  void (*invoked) (NetstatusIcon *icon);
+};
+
+GType           netstatus_icon_get_type            (void) G_GNUC_CONST;
+
+GtkWidget *     netstatus_icon_new                  (NetstatusIface *iface);
+
+void            netstatus_icon_invoke               (NetstatusIcon  *icon);
+
+void            netstatus_icon_set_iface            (NetstatusIcon  *icon,
+                                                    NetstatusIface *interface);
+NetstatusIface *netstatus_icon_get_iface            (NetstatusIcon  *icon);
+
+void            netstatus_icon_set_orientation      (NetstatusIcon  *icon,
+                                                    GtkOrientation  orientation);
+GtkOrientation  netstatus_icon_get_orientation      (NetstatusIcon  *icon);
+
+void            netstatus_icon_set_tooltips_enabled (NetstatusIcon  *icon,
+                                                    gboolean        enabled);
+gboolean        netstatus_icon_get_tooltips_enabled (NetstatusIcon  *icon);
+
+void            netstatus_icon_set_show_signal      (NetstatusIcon  *icon,
+                                                    gboolean        show_signal);
+gboolean        netstatus_icon_get_show_signal      (NetstatusIcon  *icon);
+
+G_END_DECLS
+
+#endif /* __NETSTATUS_ICON_H__ */
diff --git a/src/plugins/netstatus/netstatus-iface.c b/src/plugins/netstatus/netstatus-iface.c
new file mode 100644 (file)
index 0000000..339d635
--- /dev/null
@@ -0,0 +1,1258 @@
+/*
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ * Copyright (C) 2004 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * 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.
+ *
+ * Authors:
+ *    Erwann Chenede  <erwann.chenede@sun.com>
+ *    Mark McLoughlin  <mark@skynet.ie>
+ *
+ * Support for the various hardware types is adapted from the
+ * net-tools package (version 1.60) which is also distributed
+ * under the GNU General Public License. The code used below
+ * is Copyright (C) 1993 MicroWalt Corporation.
+ */
+
+#include <config.h>
+
+#include "netstatus-iface.h"
+
+#include <glib/gi18n.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif /* HAVE_SYS_SOCKIO_H */
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "netstatus-sysdeps.h"
+#include "netstatus-enums.h"
+
+#define NETSTATUS_IFACE_POLL_DELAY       500  /* milliseconds between polls */
+#define NETSTATUS_IFACE_POLLS_IN_ERROR   10   /* no. of polls in error before increasing delay */
+#define NETSTATUS_IFACE_ERROR_POLL_DELAY 5000 /* delay to use when in error state */
+
+enum
+{
+  PROP_0,
+  PROP_NAME,
+  PROP_STATE,
+  PROP_STATS,
+  PROP_WIRELESS,
+  PROP_SIGNAL_STRENGTH,
+  PROP_ERROR
+};
+
+struct _NetstatusIfacePrivate
+{
+  char           *name;
+
+  NetstatusState  state;
+  NetstatusStats  stats;
+  int             signal_strength;
+  GError         *error;
+
+  int             sockfd;
+  guint           monitor_id;
+
+  guint           error_polling : 1;
+  guint           is_wireless : 1;
+};
+
+static void     netstatus_iface_instance_init   (NetstatusIface      *iface,
+                                                NetstatusIfaceClass *klass);
+static void     netstatus_iface_class_init      (NetstatusIfaceClass *klass);
+static void     netstatus_iface_finalize        (GObject             *object);
+static void     netstatus_iface_set_property    (GObject             *object,
+                                                guint                property_id,
+                                                const GValue        *value,
+                                                GParamSpec          *pspec);
+static void     netstatus_iface_get_property    (GObject             *object,
+                                                guint                property_id,
+                                                GValue              *value,
+                                                GParamSpec          *pspec);
+static gboolean netstatus_iface_monitor_timeout (NetstatusIface      *iface);
+static void     netstatus_iface_init_monitor    (NetstatusIface      *iface);
+
+
+
+static GObjectClass *parent_class;
+
+GType
+netstatus_iface_get_type (void)
+{
+  static GType type = 0;
+
+  if (!type)
+    {
+      static const GTypeInfo info =
+      {
+       sizeof (NetstatusIfaceClass),
+       NULL,
+       NULL,
+       (GClassInitFunc) netstatus_iface_class_init,
+       NULL,
+       NULL,
+       sizeof (NetstatusIface),
+       0,
+       (GInstanceInitFunc) netstatus_iface_instance_init,
+       NULL
+      };
+
+      type = g_type_register_static (G_TYPE_OBJECT, "NetstatusIface", &info, 0);
+    }
+
+  return type;
+}
+
+
+static void
+netstatus_iface_instance_init (NetstatusIface      *iface,
+                              NetstatusIfaceClass *klass)
+{
+  iface->priv = g_new0 (NetstatusIfacePrivate, 1);
+  
+  iface->priv->state = NETSTATUS_STATE_DISCONNECTED;
+}
+
+static void
+netstatus_iface_class_init (NetstatusIfaceClass *klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize     = netstatus_iface_finalize;
+  gobject_class->get_property = netstatus_iface_get_property;
+  gobject_class->set_property = netstatus_iface_set_property;
+
+  g_object_class_install_property (gobject_class,
+                                  PROP_NAME,
+                                  g_param_spec_string ("name",
+                                                       _("Name"),
+                                                       _("The interface name"),
+                                                       NULL,
+                                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+  g_object_class_install_property (gobject_class,
+                                  PROP_STATE,
+                                  g_param_spec_enum ("state",
+                                                     _("State"),
+                                                     _("The interface state"),
+                                                     NETSTATUS_TYPE_STATE,
+                                                     NETSTATUS_STATE_DISCONNECTED,
+                                                     G_PARAM_READABLE));
+
+  g_object_class_install_property (gobject_class,
+                                  PROP_STATS,
+                                  g_param_spec_boxed ("stats",
+                                                      _("Stats"),
+                                                      _("The interface packets/bytes statistics"),
+                                                      NETSTATUS_TYPE_STATS,
+                                                      G_PARAM_READABLE));
+
+  g_object_class_install_property (gobject_class,
+                                  PROP_WIRELESS,
+                                  g_param_spec_boolean ("wireless",
+                                                        _("Wireless"),
+                                                        _("Whether the interface is a wireless interface"),
+                                                        FALSE,
+                                                        G_PARAM_READABLE));
+
+  g_object_class_install_property (gobject_class,
+                                  PROP_SIGNAL_STRENGTH,
+                                  g_param_spec_int ("signal-strength",
+                                                    _("Signal"),
+                                                    _("Wireless signal strength percentage"),
+                                                    0,
+                                                    100,
+                                                    0,
+                                                    G_PARAM_READABLE));
+
+  g_object_class_install_property (gobject_class,
+                                  PROP_ERROR,
+                                  g_param_spec_boxed ("error",
+                                                      _("Error"),
+                                                      _("The current error condition"),
+                                                      NETSTATUS_TYPE_G_ERROR,
+                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+}
+
+static void
+netstatus_iface_finalize (GObject *object)
+{
+  NetstatusIface *iface = (NetstatusIface *) object;
+
+  if (iface->priv->error)
+    g_error_free (iface->priv->error);
+  iface->priv->error = NULL;
+
+  if (iface->priv->monitor_id)
+    g_source_remove (iface->priv->monitor_id);
+  iface->priv->monitor_id = 0;
+
+  if (iface->priv->sockfd)
+    close (iface->priv->sockfd);
+  iface->priv->sockfd = 0;
+
+  g_free (iface->priv->name);
+  iface->priv->name = NULL;
+
+  g_free (iface->priv);
+  iface->priv = NULL;
+
+  parent_class->finalize (object);
+}
+
+static void 
+netstatus_iface_set_property (GObject      *object,
+                             guint         property_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+  NetstatusIface *iface = (NetstatusIface *) object;
+
+  switch (property_id)
+    {
+    case PROP_NAME:
+      netstatus_iface_set_name (iface, g_value_get_string (value));
+      break;
+    case PROP_ERROR:
+      netstatus_iface_set_error (iface, g_value_get_boxed (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+netstatus_iface_get_property (GObject    *object,
+                             guint       property_id,
+                             GValue     *value,
+                             GParamSpec *pspec)
+{
+  NetstatusIface *iface = (NetstatusIface *) object;
+  
+  switch (property_id)
+    {
+    case PROP_NAME:
+      g_value_set_string (value, iface->priv->name);
+      break;
+    case PROP_STATE:
+      g_value_set_enum (value, iface->priv->state);
+      break;
+    case PROP_STATS:
+      g_value_set_boxed (value, &iface->priv->stats);
+      break;
+    case PROP_WIRELESS:
+      g_value_set_boolean (value, iface->priv->is_wireless);
+      break;
+    case PROP_SIGNAL_STRENGTH:
+      g_value_set_int (value, iface->priv->signal_strength);
+      break;
+    case PROP_ERROR:
+      g_value_set_boxed (value, iface->priv->error);
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+NetstatusIface *
+netstatus_iface_new (const char *name)
+{
+  return g_object_new (NETSTATUS_TYPE_IFACE,
+                      "name", name,
+                      NULL);
+}
+
+void
+netstatus_iface_set_name (NetstatusIface *iface,
+                         const char     *name)
+{
+  g_return_if_fail (NETSTATUS_IS_IFACE (iface));
+
+  if (iface->priv->name && name &&
+      !strcmp (iface->priv->name, name))
+    return;
+
+  if (name && strlen (name) >= IF_NAMESIZE)
+    {
+      g_warning (G_STRLOC ": interface name '%s' is too long\n", name);
+      return;
+    }
+
+  if (iface->priv->name)
+    g_free (iface->priv->name);
+  iface->priv->name = g_strdup (name);
+
+  netstatus_iface_init_monitor (iface);
+  
+  g_object_notify (G_OBJECT (iface), "name");
+}
+
+G_CONST_RETURN char *
+netstatus_iface_get_name (NetstatusIface *iface)
+{
+  g_return_val_if_fail (NETSTATUS_IS_IFACE (iface), NULL);
+
+  return iface->priv->name;
+}
+
+NetstatusState
+netstatus_iface_get_state (NetstatusIface *iface)
+{
+  g_return_val_if_fail (NETSTATUS_IS_IFACE (iface), NETSTATUS_STATE_DISCONNECTED);
+
+  return iface->priv->state;
+}
+
+void
+netstatus_iface_get_statistics (NetstatusIface *iface,
+                               NetstatusStats *stats)
+{
+  g_return_if_fail (NETSTATUS_IS_IFACE (iface));
+
+  if (stats)
+    *stats  = iface->priv->stats;
+}
+
+gboolean
+netstatus_iface_get_is_wireless (NetstatusIface *iface)
+{
+  g_return_val_if_fail (NETSTATUS_IS_IFACE (iface), FALSE);
+
+  return iface->priv->is_wireless;
+}
+
+int
+netstatus_iface_get_signal_strength (NetstatusIface *iface)
+{
+  g_return_val_if_fail (NETSTATUS_IS_IFACE (iface), 0);
+
+  return iface->priv->signal_strength;
+}
+
+void
+netstatus_iface_set_error (NetstatusIface *iface,
+                          const GError   *error)
+{
+  g_return_if_fail (NETSTATUS_IS_IFACE (iface));
+
+  if (iface->priv->state != NETSTATUS_STATE_ERROR && error)
+    {
+      g_assert (iface->priv->error == NULL);
+
+      iface->priv->state = NETSTATUS_STATE_ERROR;
+      iface->priv->error = g_error_copy (error);
+
+      g_object_notify (G_OBJECT (iface), "state");
+      g_object_notify (G_OBJECT (iface), "error");
+    }
+}
+
+G_CONST_RETURN GError *
+netstatus_iface_get_error (NetstatusIface *iface)
+{
+  g_return_val_if_fail (NETSTATUS_IS_IFACE (iface), NULL);
+
+  return iface->priv->error;
+}
+
+void
+netstatus_iface_clear_error (NetstatusIface *iface,
+                            NetstatusError  code)
+{
+  g_return_if_fail (NETSTATUS_IS_IFACE (iface));
+
+  if (iface->priv->state == NETSTATUS_STATE_ERROR &&
+      g_error_matches (iface->priv->error, NETSTATUS_ERROR, code))
+    {
+      iface->priv->state = NETSTATUS_STATE_DISCONNECTED;
+
+      g_error_free (iface->priv->error);
+      iface->priv->error = NULL;
+     
+      g_object_notify (G_OBJECT (iface), "state");
+      g_object_notify (G_OBJECT (iface), "error");
+    }
+}
+
+static void
+netstatus_iface_set_polling_error (NetstatusIface *iface,
+                                  NetstatusError  code,
+                                  const char     *format,
+                                  ...)
+{
+  GError  *error;
+  va_list  args;
+  char    *error_message;
+  
+  va_start (args, format);
+
+  error_message = g_strdup_vprintf (format, args);
+  error = g_error_new (NETSTATUS_ERROR, code, error_message);
+
+  dprintf (POLLING, "ERROR: %s\n", error->message);
+  netstatus_iface_set_error (iface, error);
+
+  g_error_free (error);
+  g_free (error_message);
+
+  va_end (args);
+}
+
+static int
+netstatus_iface_get_sockfd (NetstatusIface *iface)
+{
+  int fd;
+
+  if (iface->priv->sockfd)
+    return iface->priv->sockfd;
+
+  if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
+    {
+      netstatus_iface_set_polling_error (iface,
+                                        NETSTATUS_ERROR_SOCKET,
+                                        _("Unable to open socket: %s"),
+                                        g_strerror (errno));
+      return 0;
+    }
+
+  dprintf (POLLING, "Successfully opened socket for polling\n");
+  netstatus_iface_clear_error (iface, NETSTATUS_ERROR_SOCKET);
+
+  iface->priv->sockfd = fd;
+
+  return iface->priv->sockfd;
+}
+
+static gboolean
+netstatus_iface_poll_iface_statistics (NetstatusIface *iface,
+                                      gulong         *in_packets,
+                                      gulong         *out_packets,
+                                      gulong         *in_bytes,
+                                      gulong         *out_bytes)
+{
+  char *error_message;
+
+  error_message = netstatus_sysdeps_read_iface_statistics (iface->priv->name,
+                                                          in_packets,
+                                                          out_packets,
+                                                          in_bytes,
+                                                          out_bytes);
+  if (error_message)
+    {
+      netstatus_iface_set_polling_error (iface,
+                                        NETSTATUS_ERROR_STATISTICS,
+                                        error_message);
+      g_free (error_message);
+      
+      return FALSE;
+    }
+
+  netstatus_iface_clear_error (iface, NETSTATUS_ERROR_STATISTICS);
+
+  return TRUE;
+}
+
+static NetstatusState
+netstatus_iface_poll_state (NetstatusIface *iface)
+{
+  NetstatusState state;
+  struct ifreq   if_req;
+  gboolean       tx, rx;
+  int            fd;
+  gulong         in_packets, out_packets;
+  gulong         in_bytes, out_bytes;
+
+  if (!(fd = netstatus_iface_get_sockfd (iface)))
+    return NETSTATUS_STATE_DISCONNECTED;
+
+  memset (&if_req, 0, sizeof (struct ifreq));
+  strcpy (if_req.ifr_name, iface->priv->name);
+
+  if (ioctl (fd, SIOCGIFFLAGS, &if_req) < 0)
+    {
+      netstatus_iface_set_polling_error (iface,
+                                        NETSTATUS_ERROR_IOCTL_IFFLAGS,
+                                        _("SIOCGIFFLAGS error: %s"),
+                                        g_strerror (errno));
+      return NETSTATUS_STATE_DISCONNECTED;
+    }
+
+  netstatus_iface_clear_error (iface, NETSTATUS_ERROR_IOCTL_IFFLAGS);
+
+  dprintf (POLLING, "Interface is %sup and %srunning\n",
+          if_req.ifr_flags & IFF_UP ? "" : "not ",
+          if_req.ifr_flags & IFF_RUNNING ? "" : "not ");
+
+  if (!(if_req.ifr_flags & IFF_UP) || !(if_req.ifr_flags & IFF_RUNNING))
+    return NETSTATUS_STATE_DISCONNECTED;
+
+  if (!netstatus_iface_poll_iface_statistics (iface, &in_packets, &out_packets, &in_bytes, &out_bytes))
+    return NETSTATUS_STATE_IDLE;
+
+  dprintf (POLLING, "Packets in: %ld out: %ld. Prev in: %ld out: %ld\n",
+          in_packets, out_packets,
+          iface->priv->stats.in_packets, iface->priv->stats.out_packets);
+  dprintf (POLLING, "Bytes in: %ld out: %ld. Prev in: %ld out: %ld\n",
+          in_bytes, out_bytes,
+          iface->priv->stats.in_bytes, iface->priv->stats.out_bytes);
+  
+  rx = in_packets  > iface->priv->stats.in_packets;
+  tx = out_packets > iface->priv->stats.out_packets;
+
+  if (!tx && !rx)
+    state = NETSTATUS_STATE_IDLE;
+  else if (tx && rx)
+    state = NETSTATUS_STATE_TX_RX;
+  else if (tx)
+    state = NETSTATUS_STATE_TX;
+  else /* if (rx) */
+    state = NETSTATUS_STATE_RX;
+
+  dprintf (POLLING, "State: %s\n", netstatus_get_state_string (state));
+
+  if (tx || rx)
+    {
+      iface->priv->stats.in_packets  = in_packets;
+      iface->priv->stats.out_packets = out_packets;
+      iface->priv->stats.in_bytes    = in_bytes;
+      iface->priv->stats.out_bytes   = out_bytes;
+
+      g_object_notify (G_OBJECT (iface), "stats");
+    }
+
+  return state;
+}
+
+static gboolean
+netstatus_iface_poll_wireless_details (NetstatusIface *iface,
+                                      int            *signal_strength)
+{
+  char     *error_message;
+  gboolean  is_wireless;
+
+  error_message = netstatus_sysdeps_read_iface_wireless_details (iface->priv->name,
+                                                                &is_wireless,
+                                                                signal_strength);
+
+  if (error_message)
+    {
+      netstatus_iface_set_polling_error (iface,
+                                        NETSTATUS_ERROR_WIRELESS_DETAILS,
+                                        error_message);
+      g_free (error_message);
+      
+      return FALSE;
+    }
+
+  netstatus_iface_clear_error (iface, NETSTATUS_ERROR_WIRELESS_DETAILS);
+
+  return is_wireless;
+}
+
+static void
+netstatus_iface_increase_poll_delay_in_error (NetstatusIface *iface)
+{
+  static int polls_in_error = 0;
+
+  if (iface->priv->state == NETSTATUS_STATE_ERROR)
+    {
+      dprintf (POLLING, "Interface in error state\n");
+
+      if (!iface->priv->error_polling &&
+         ++polls_in_error >= NETSTATUS_IFACE_POLLS_IN_ERROR)
+       {
+         dprintf (POLLING, "Increasing polling delay after too many errors\n");
+         iface->priv->error_polling = TRUE;
+         g_source_remove (iface->priv->monitor_id);
+         iface->priv->monitor_id = g_timeout_add (NETSTATUS_IFACE_ERROR_POLL_DELAY,
+                                                  (GSourceFunc) netstatus_iface_monitor_timeout,
+                                                  iface);
+       }
+    }
+  else if (iface->priv->error_polling)
+    {
+      dprintf (POLLING, "Recovered from errors. Increasing polling delay again\n");
+
+      iface->priv->error_polling = FALSE;
+      polls_in_error = 0;
+
+      g_source_remove (iface->priv->monitor_id);
+      iface->priv->monitor_id = g_timeout_add (NETSTATUS_IFACE_POLL_DELAY,
+                                              (GSourceFunc) netstatus_iface_monitor_timeout,
+                                              iface);
+    }
+}
+
+static gboolean
+netstatus_iface_monitor_timeout (NetstatusIface *iface)
+{
+  NetstatusState state;
+  int            signal_strength;
+  gboolean       is_wireless;
+  state = netstatus_iface_poll_state (iface);
+
+  if (iface->priv->state != state &&
+      iface->priv->state != NETSTATUS_STATE_ERROR)
+    {
+      iface->priv->state = state;
+      g_object_notify (G_OBJECT (iface), "state");
+    }
+
+  is_wireless = netstatus_iface_poll_wireless_details (iface, &signal_strength);
+  if (iface->priv->is_wireless != is_wireless)
+    {
+      iface->priv->is_wireless = is_wireless;
+      g_object_notify (G_OBJECT (iface), "wireless");
+    }
+
+  if (iface->priv->signal_strength != signal_strength)
+    {
+      iface->priv->signal_strength = signal_strength;
+      g_object_notify (G_OBJECT (iface), "signal-strength");
+    }
+
+  netstatus_iface_increase_poll_delay_in_error (iface);
+  
+  return TRUE;
+}
+
+static void
+netstatus_iface_init_monitor (NetstatusIface *iface)
+{
+  iface->priv->stats.in_packets  = 0;
+  iface->priv->stats.out_packets = 0;
+  iface->priv->stats.in_bytes    = 0;
+  iface->priv->stats.out_bytes   = 0;
+  iface->priv->signal_strength   = 0;
+  iface->priv->is_wireless       = FALSE;
+
+  g_object_freeze_notify (G_OBJECT (iface));
+  g_object_notify (G_OBJECT (iface), "state");
+  g_object_notify (G_OBJECT (iface), "wireless");
+  g_object_notify (G_OBJECT (iface), "signal-strength");
+  g_object_thaw_notify (G_OBJECT (iface));
+
+  if (iface->priv->monitor_id)
+    {
+      dprintf (POLLING, "Removing existing monitor\n");
+      g_source_remove (iface->priv->monitor_id);
+      iface->priv->monitor_id = 0;
+    }
+
+  if (iface->priv->name)
+    {
+      dprintf (POLLING, "Initialising monitor with delay of %d\n", NETSTATUS_IFACE_POLL_DELAY);
+      iface->priv->monitor_id = g_timeout_add (NETSTATUS_IFACE_POLL_DELAY,
+                                              (GSourceFunc) netstatus_iface_monitor_timeout,
+                                              iface);
+
+      netstatus_iface_monitor_timeout (iface);
+    }
+}
+
+gboolean
+netstatus_iface_get_inet4_details (NetstatusIface  *iface,
+                                  char           **addr,
+                                  char           **dest,
+                                  char           **bcast,
+                                  char           **mask)
+{
+  struct ifreq if_req;
+  int          fd;
+  int          flags;
+
+  if (addr)
+    *addr = NULL;
+  if (dest)
+    *dest = NULL;
+  if (mask)
+    *mask = NULL;
+
+  if (!iface->priv->name)
+    return FALSE;
+
+  if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
+    {
+      g_warning (G_STRLOC ": unable to open AF_INET socket: %s\n",
+                g_strerror (errno));
+      return FALSE;
+    }
+  
+  if_req.ifr_addr.sa_family = AF_INET;
+
+  strncpy (if_req.ifr_name, iface->priv->name, IF_NAMESIZE - 1);
+  if_req.ifr_name [IF_NAMESIZE - 1] = '\0';
+  if (addr && ioctl (fd, SIOCGIFADDR, &if_req) == 0)
+    *addr = g_strdup (inet_ntoa (((struct sockaddr_in *) &if_req.ifr_addr)->sin_addr));
+
+  if (addr && !*addr)
+    {
+      close (fd);
+      return FALSE;
+    }
+
+  strncpy (if_req.ifr_name, iface->priv->name, IF_NAMESIZE - 1);
+  if_req.ifr_name [IF_NAMESIZE - 1] = '\0';
+  if (ioctl (fd, SIOCGIFFLAGS, &if_req) < 0)
+    {
+      close (fd);
+      return TRUE;
+    }
+
+  flags = if_req.ifr_flags;
+
+  strncpy (if_req.ifr_name, iface->priv->name, IF_NAMESIZE - 1);
+  if_req.ifr_name [IF_NAMESIZE - 1] = '\0';
+  if (dest && flags & IFF_POINTOPOINT &&
+      ioctl (fd, SIOCGIFDSTADDR, &if_req) == 0)
+    *dest = g_strdup (inet_ntoa (((struct sockaddr_in *) &if_req.ifr_dstaddr)->sin_addr));
+
+  strncpy (if_req.ifr_name, iface->priv->name, IF_NAMESIZE - 1);
+  if_req.ifr_name [IF_NAMESIZE - 1] = '\0';
+  if (bcast && flags & IFF_BROADCAST &&
+      ioctl (fd, SIOCGIFBRDADDR, &if_req) == 0)
+    *bcast = g_strdup (inet_ntoa (((struct sockaddr_in *) &if_req.ifr_broadaddr)->sin_addr));
+
+  strncpy (if_req.ifr_name, iface->priv->name, IF_NAMESIZE - 1);
+  if_req.ifr_name [IF_NAMESIZE - 1] = '\0';
+  if (mask && ioctl (fd, SIOCGIFNETMASK, &if_req) == 0)
+    *mask = g_strdup (inet_ntoa (((struct sockaddr_in *) &if_req.ifr_addr)->sin_addr));
+
+  close (fd);
+
+  return TRUE;
+}
+
+static char *
+print_mac_addr (guchar *p)
+{
+  return g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
+                         p [0] & 0377,
+                         p [1] & 0377,
+                         p [2] & 0377,
+                         p [3] & 0377,
+                         p [4] & 0377,
+                         p [5] & 0377);
+}
+
+static char *
+print_ash_addr (guchar *p)
+{
+#define ASH_ALEN 64
+
+  GString *str;
+  char    *retval;
+  int      i = 0;
+
+  str = g_string_new ("[");
+  
+  while (p [i] != 0xc9 && p [i] != 0xff && (i < ASH_ALEN))
+    g_string_append_printf (str, "%1x", p [i++]);
+
+  g_string_append_c (str, ']');
+  
+  retval = str->str;
+  g_string_free (str, FALSE);
+
+  return retval;
+  
+#undef ASH_ALEN
+}
+
+static char *
+print_ax25_addr (guchar *p)
+{
+  GString *str;
+  char    *retval;
+  int      i;
+
+  str = g_string_new (NULL);
+  
+  for (i = 0; i < 6; i++)
+    {
+      char c = (p [i] & 0377) >> 1;
+
+      if (c == ' ')
+       {
+         retval = str->str;
+         g_string_free (str, FALSE);
+         
+         return retval;
+       }
+
+      g_string_append_c (str, c);
+    }
+
+  i = (p [6] & 0x1E) >> 1;
+  if (i != 0)
+    g_string_append_printf (str, "-%d", i);
+
+  retval = str->str;
+  g_string_free (str, FALSE);
+
+  return retval;
+}
+
+static char *
+print_rose_addr (guchar *p)
+{
+  return g_strdup_printf ("%02x%02x%02x%02x%02x", p [0], p [1], p [2], p [3], p [4]);
+}
+
+static char *
+print_x25_addr (guchar *p)
+{
+  return g_strdup (p);
+}
+
+static char *
+print_arcnet_addr (guchar *p)
+{
+  return g_strdup_printf ("%02X", p [0] & 0377);
+}
+
+static char *
+print_dlci_addr (guchar *p)
+{
+  return g_strdup_printf ("%i", *(short *) p);
+}
+
+static char *
+print_irda_addr (guchar *p)
+{
+  return g_strdup_printf ("%02x:%02x:%02x:%02x", p [3], p [2], p [1], p [0]);
+}
+
+static char *
+print_econet_addr (guchar *p)
+{
+  /* This should really be:
+   *   #include <neteconet/ec.h>
+   *
+   *   struct ec_addr *ec = (struct ec_addr *) p;
+   *   return g_strdup_printf ("%d.%d, ec->net, ec->station);
+   *
+   * But I think the hack is safe enough.
+   */
+  return g_strdup_printf ("%d.%d", p [0], p [1]);
+}
+
+static struct HwType
+{
+  int   hw_type;
+  char *hw_name;
+  char *(*print_hw_addr) (guchar *p);
+} hw_types [] =
+  {
+#ifdef ARPHRD_NETROM
+    { ARPHRD_NETROM, N_("AMPR NET/ROM"), print_ax25_addr },
+#endif
+#ifdef ARPHRD_ETHER
+    { ARPHRD_ETHER, N_("Ethernet"), print_mac_addr },
+#endif
+#ifdef ARPHRD_EETHER
+    { ARPHRD_EETHER, NULL, NULL },
+#endif
+#ifdef ARPHRD_AX25
+    { ARPHRD_AX25, N_("AMPR AX.25"), NULL },
+#endif
+#ifdef ARPHRD_PRONET
+    { ARPHRD_PRONET, NULL, NULL },
+#endif
+#ifdef ARPHRD_CHAOS
+    { ARPHRD_CHAOS, NULL, NULL },
+#endif
+#ifdef ARPHRD_IEEE802
+    { ARPHRD_IEEE802, N_("16/4 Mbps Token Ring"), print_mac_addr },
+#endif
+#ifdef ARPHRD_ARCNET
+    { ARPHRD_ARCNET, N_("ARCnet"), print_arcnet_addr },
+#endif
+#ifdef ARPHRD_APPLETLK
+    { ARPHRD_APPLETLK, NULL, NULL },
+#endif
+#ifdef ARPHRD_DLCI
+    { ARPHRD_DLCI, N_("Frame Relay DLCI"), print_dlci_addr },
+#endif
+#ifdef ARPHRD_ATM
+    { ARPHRD_ATM, NULL, NULL },
+#endif
+#ifdef ARPHRD_METRICOM
+    { ARPHRD_METRICOM, N_("Metricom Starmode IP"), NULL },
+#endif
+#ifdef ARPHRD_SLIP
+    { ARPHRD_SLIP, N_("Serial Line IP"), NULL },
+#endif
+#ifdef ARPHRD_CSLIP
+    { ARPHRD_CSLIP, N_("VJ Serial Line IP"), NULL },
+#endif
+#ifdef ARPHRD_SLIP6
+    { ARPHRD_SLIP6, N_("6-bit Serial Line IP"), NULL },
+#endif
+#ifdef ARPHRD_CSLIP6
+    { ARPHRD_CSLIP6, N_("VJ 6-bit Serial Line IP"), NULL },
+#endif
+#ifdef ARPHRD_RSRVD
+    { ARPHRD_RSRVD, NULL, NULL },
+#endif
+#ifdef ARPHRD_ADAPT
+    { ARPHRD_ADAPT, N_("Adaptive Serial Line IP"), NULL },
+#endif
+#ifdef ARPHRD_ROSE
+    { ARPHRD_ROSE, N_("AMPR ROSE"), print_rose_addr },
+#endif
+#ifdef ARPHRD_X25
+    { ARPHRD_X25, N_("Generic X.25"), print_x25_addr },
+#endif
+#ifdef ARPHRD_PPP
+    { ARPHRD_PPP, N_("Point-to-Point Protocol"), NULL },
+#endif
+#ifdef ARPHRD_CISCO
+    { ARPHRD_CISCO, NULL, NULL },
+#endif
+#ifdef ARPHRD_HDLC
+    { ARPHRD_HDLC, N_("(Cisco)-HDLC"), NULL },
+#endif
+#ifdef ARPHRD_LAPB
+    { ARPHRD_LAPB, N_("LAPB"), NULL },
+#endif
+#ifdef ARPHRD_DDCMP
+    { ARPHRD_DDCMP, NULL, NULL },
+#endif
+#ifdef ARPHRD_RAWHDLC
+    { ARPHRD_RAWHDLC, NULL, NULL },
+#endif
+#ifdef ARPHRD_TUNNEL
+    { ARPHRD_TUNNEL, N_("IPIP Tunnel"), NULL },
+#endif
+#ifdef ARPHRD_TUNNEL6
+    { ARPHRD_TUNNEL6, NULL, NULL },
+#endif
+#ifdef ARPHRD_FRAD
+    { ARPHRD_FRAD, N_("Frame Relay Access Device"), NULL },
+#endif
+#ifdef ARPHRD_SKIP
+    { ARPHRD_SKIP, NULL, NULL },
+#endif
+#ifdef ARPHRD_LOOPBACK
+    { ARPHRD_LOOPBACK, N_("Local Loopback"), print_mac_addr },
+#endif
+#ifdef ARPHRD_LOCALTLK
+    { ARPHRD_LOCALTLK, NULL, NULL },
+#endif
+#ifdef ARPHRD_FDDI
+    { ARPHRD_FDDI, N_("Fiber Distributed Data Interface"), print_mac_addr },
+#endif
+#ifdef ARPHRD_BIF
+    { ARPHRD_BIF, NULL, NULL },
+#endif
+#ifdef ARPHRD_SIT
+    { ARPHRD_SIT, N_("IPv6-in-IPv4"), NULL },
+#endif
+#ifdef ARPHRD_IPDDP
+    { ARPHRD_IPDDP, NULL, NULL },
+#endif
+#ifdef ARPHRD_IPGRE
+    { ARPHRD_IPGRE, NULL, NULL },
+#endif
+#ifdef ARPHRD_PIMREG
+    { ARPHRD_PIMREG, NULL, NULL },
+#endif
+#ifdef ARPHRD_HIPPI
+    { ARPHRD_HIPPI, N_("HIPPI"), print_mac_addr },
+#endif
+#ifdef ARPHRD_ASH
+    { ARPHRD_ASH, N_("Ash"), print_ash_addr },
+#endif
+#ifdef ARPHRD_ECONET
+    { ARPHRD_ECONET, N_("Econet"), print_econet_addr },
+#endif
+#ifdef ARPHRD_IRDA
+    { ARPHRD_IRDA, N_("IrLAP"), print_irda_addr },
+#endif
+#ifdef ARPHRD_FCPP
+    { ARPHRD_FCPP, NULL, NULL },
+#endif
+#ifdef ARPHRD_FCAL
+    { ARPHRD_FCAL, NULL, NULL },
+#endif
+#ifdef ARPHRD_FCPL
+    { ARPHRD_FCPL, NULL, NULL },
+#endif
+#ifdef ARPHRD_FCPFABRIC
+    { ARPHRD_FCPFABRIC, NULL, NULL },
+#endif
+#ifdef ARPHRD_IEEE802_TR
+    { ARPHRD_IEEE802_TR, N_("16/4 Mbps Token Ring"), print_mac_addr },
+#endif
+#ifdef ARPHRD_IEEE80211
+    { ARPHRD_IEEE80211, NULL, NULL },
+#endif
+  };
+
+static struct HwType *
+netstatus_iface_get_hw_details (NetstatusIface  *iface,
+                               char           **hw_addr)
+                               
+{
+#ifdef SIOCGIFHWADDR
+  static struct HwType *hw_type = NULL;
+  struct ifreq          if_req;
+  int                   fd;
+  int                   i;
+
+  if (hw_addr)
+    *hw_addr = NULL;
+  
+  if (!iface->priv->name)
+    return NULL;
+
+  if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
+    {
+      g_warning (G_STRLOC ": unable to open AF_INET socket: %s\n",
+                g_strerror (errno));
+      return NULL;
+    }
+  
+  strncpy (if_req.ifr_name, iface->priv->name, IF_NAMESIZE - 1);
+  if_req.ifr_name [IF_NAMESIZE - 1] = '\0';
+  if (ioctl (fd, SIOCGIFHWADDR, &if_req) < 0)
+    {
+      g_warning (G_STRLOC ": unable to obtain hardware address: %s\n",
+                g_strerror (errno));
+      close (fd);
+      return NULL;
+    }
+
+  close (fd);
+
+  if (hw_type && hw_type->hw_type != if_req.ifr_hwaddr.sa_family)
+    hw_type = NULL;
+
+  for (i = 0; !hw_type && i < G_N_ELEMENTS (hw_types); i++)
+    if (hw_types [i].hw_type == if_req.ifr_hwaddr.sa_family)
+      hw_type = &hw_types [i];
+
+  if (!hw_type || !hw_type->hw_name)
+    {
+      g_warning (G_STRLOC ": no support for hardware type %d\n",
+                if_req.ifr_hwaddr.sa_family);
+      return NULL;
+    }
+
+  if (hw_addr && if_req.ifr_hwaddr.sa_data && hw_type->print_hw_addr)
+    *hw_addr = hw_type->print_hw_addr (if_req.ifr_hwaddr.sa_data);
+
+  return hw_type;
+
+#else /* !defined(SIOCGIFHWADDR) */
+  return NULL;
+#endif 
+}
+
+gboolean
+netstatus_iface_get_is_loopback (NetstatusIface *iface)
+{
+  struct HwType *hw_type;
+
+  g_return_val_if_fail (NETSTATUS_IS_IFACE (iface), FALSE);
+
+  if (!(hw_type = netstatus_iface_get_hw_details (iface, NULL)))
+    return FALSE;
+
+#ifdef ARPHRD_LOOPBACK
+  return hw_type->hw_type == ARPHRD_LOOPBACK ? TRUE : FALSE;
+#else
+  return FALSE;
+#endif
+}
+
+gboolean
+netstatus_iface_get_device_details (NetstatusIface  *iface,
+                                   const char     **hw_name,
+                                   char           **hw_addr)
+{
+  struct HwType *hw_type;
+
+  g_return_val_if_fail (NETSTATUS_IS_IFACE (iface), FALSE);
+
+  if (hw_name)
+    *hw_name = NULL;
+  if (hw_addr)
+    *hw_addr = NULL;
+
+  if (!(hw_type = netstatus_iface_get_hw_details (iface, hw_addr)))
+    return FALSE;
+
+  g_assert (hw_type->hw_name != NULL);
+
+  if (hw_name)
+    *hw_name = _(hw_type->hw_name);
+
+  return TRUE;
+}
+
+#if !defined(HAVE_SOCKADDR_SA_LEN)
+#define NETSTATUS_SA_LEN(saddr) (sizeof (struct sockaddr))
+#else
+#define NETSTATUS_SA_LEN(saddr) (MAX ((saddr)->sa_len, sizeof (struct sockaddr)))
+#endif /* HAVE_SOCKADDR_SA_LEN */
+
+/* Taken From R. Stevens Unix Network Programming Vol. 1.
+ *
+ * SIOCGIFCONF does not return an error on all systems if
+ * the buffer is not large enough for all available
+ * interfaces. This loop portably ensures that we get the
+ * information for all interfaces.
+ */
+static struct ifconf *
+get_ifconf (int      fd,
+           GError **error)
+{
+  struct ifconf  if_conf;
+  struct ifconf *retval;
+  int            len, lastlen;
+
+  lastlen = 0;
+  len = 10 * sizeof (struct ifreq);
+
+  while (TRUE)
+    {
+      if_conf.ifc_len = len;
+      if_conf.ifc_buf = g_malloc0 (len);
+
+      if (ioctl (fd, SIOCGIFCONF, &if_conf) < 0)
+       {
+         if (errno != EINVAL || lastlen != 0)
+           {
+             g_free (if_conf.ifc_buf);
+
+             if (error)
+               *error = g_error_new (NETSTATUS_ERROR,
+                                     NETSTATUS_ERROR_IOCTL_IFCONF,
+                                     _("SIOCGIFCONF error: %s"),
+                                     g_strerror (errno));
+                                     
+             return NULL;
+           }
+       }
+      else
+       {
+         if (if_conf.ifc_len == lastlen)
+           break;
+         lastlen = if_conf.ifc_len;
+       }
+
+      g_free (if_conf.ifc_buf);
+      if_conf.ifc_buf = NULL;
+
+      len *= 2;
+    }
+
+  retval = g_new0 (struct ifconf, 1);
+
+  retval->ifc_len = if_conf.ifc_len;
+  retval->ifc_buf = if_conf.ifc_buf;
+
+  return retval;
+}
+
+GList *
+netstatus_list_interface_names (GError **error)
+{
+
+  struct ifconf *if_conf;
+  GList         *interfaces;
+  GList         *loopbacks;
+  char          *p;
+  int            fd;
+  
+  if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
+    {
+      if (error)
+       *error = g_error_new (NETSTATUS_ERROR,
+                             NETSTATUS_ERROR_SOCKET,
+                             _("Unable to open socket: %s"),
+                             g_strerror (errno));
+      return NULL;
+    }
+
+  if ((if_conf = get_ifconf (fd, error)) == NULL)
+    {
+      close (fd);
+      return NULL;
+    }
+
+  interfaces = NULL;
+  loopbacks  = NULL;
+
+  for (p = if_conf->ifc_buf; p < if_conf->ifc_buf + if_conf->ifc_len;)
+    {
+      struct ifreq *if_req = (struct ifreq *) p;
+      gboolean      loopback = FALSE;
+
+      p += sizeof (if_req->ifr_name) + NETSTATUS_SA_LEN (&if_req->ifr_addr);
+
+      if (ioctl (fd, SIOCGIFFLAGS, if_req) < 0)
+       {
+         if (error)
+           *error = g_error_new (NETSTATUS_ERROR,
+                                 NETSTATUS_ERROR_IOCTL_IFFLAGS,
+                                 _("SIOCGIFFLAGS error: %s"),
+                                 g_strerror (errno));
+       }
+      else
+       {
+         loopback = (if_req->ifr_flags & IFF_LOOPBACK);
+       }
+
+      if (!loopback)
+       interfaces = netstatus_list_insert_unique (interfaces,
+                                                  g_strdup (if_req->ifr_name));
+      else
+       loopbacks  = netstatus_list_insert_unique (loopbacks,
+                                                  g_strdup (if_req->ifr_name));
+    }
+
+  interfaces = g_list_concat (interfaces, loopbacks);
+
+  g_free (if_conf->ifc_buf);
+  g_free (if_conf);
+  close (fd);
+
+  if (!interfaces && error)
+    *error = g_error_new (NETSTATUS_ERROR,
+                         NETSTATUS_ERROR_NO_INTERFACES,
+                         _("No network devices found"));
+
+  return interfaces;
+}
diff --git a/src/plugins/netstatus/netstatus-iface.h b/src/plugins/netstatus/netstatus-iface.h
new file mode 100644 (file)
index 0000000..3b315b9
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ * Copyright (C) 2004 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * 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.
+ *
+ * Authors:
+ *    Erwann Chenede  <erwann.chenede@sun.com>
+ *    Mark McLoughlin  <mark@skynet.ie>  
+ */
+
+#ifndef __NETSTATUS_IFACE_H__
+#define __NETSTATUS_IFACE_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "netstatus-util.h"
+
+G_BEGIN_DECLS
+
+#define NETSTATUS_TYPE_IFACE         (netstatus_iface_get_type ())
+#define NETSTATUS_IFACE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), NETSTATUS_TYPE_IFACE, NetstatusIface))
+#define NETSTATUS_IFACE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), NETSTATUS_TYPE_IFACE, NetstatusIfaceClass))
+#define NETSTATUS_IS_IFACE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), NETSTATUS_TYPE_IFACE))
+#define NETSTATUS_IS_IFACE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), NETSTATUS_TYPE_IFACE))
+#define NETSTATUS_IFACE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NETSTATUS_TYPE_IFACE, NetstatusIfaceClass))
+
+typedef struct _NetstatusIface        NetstatusIface;
+typedef struct _NetstatusIfaceClass   NetstatusIfaceClass;
+typedef struct _NetstatusIfacePrivate NetstatusIfacePrivate;
+
+struct _NetstatusIface
+{
+  GObject                 parent_instance; 
+       
+  NetstatusIfacePrivate  *priv;
+};
+
+struct _NetstatusIfaceClass
+{
+  GObjectClass parent_class;
+};
+
+GList *                netstatus_list_interface_names        (GError         **error);
+
+GType                  netstatus_iface_get_type              (void) G_GNUC_CONST;
+
+NetstatusIface *       netstatus_iface_new                   (const char      *name);
+
+G_CONST_RETURN char *  netstatus_iface_get_name              (NetstatusIface  *iface);
+void                   netstatus_iface_set_name              (NetstatusIface  *iface,
+                                                             const char      *name);
+NetstatusState         netstatus_iface_get_state             (NetstatusIface  *iface);
+void                   netstatus_iface_get_statistics        (NetstatusIface  *iface,
+                                                             NetstatusStats  *stats);
+gboolean               netstatus_iface_get_is_wireless       (NetstatusIface  *iface);
+int                    netstatus_iface_get_signal_strength   (NetstatusIface  *iface);
+
+void                   netstatus_iface_set_error             (NetstatusIface  *iface,
+                                                             const GError    *error);
+G_CONST_RETURN GError *netstatus_iface_get_error             (NetstatusIface  *iface);
+void                   netstatus_iface_clear_error           (NetstatusIface  *iface,
+                                                             NetstatusError   code);
+
+gboolean               netstatus_iface_get_inet4_details     (NetstatusIface  *iface,
+                                                             char           **addr,
+                                                             char           **dest,
+                                                             char           **bcast,
+                                                             char           **mask);
+gboolean               netstatus_iface_get_device_details    (NetstatusIface  *iface,
+                                                             const char     **hw_name,
+                                                             char           **hw_addr);
+gboolean               netstatus_iface_get_is_loopback       (NetstatusIface  *iface);
+
+G_END_DECLS
+
+#endif /* __NETSTATUS_IFACE_H__ */
diff --git a/src/plugins/netstatus/netstatus-sysdeps.c b/src/plugins/netstatus/netstatus-sysdeps.c
new file mode 100644 (file)
index 0000000..8b23ce0
--- /dev/null
@@ -0,0 +1,673 @@
+/*
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ * Copyright (C) 2004 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * 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.
+ *
+ * Authors:
+ *    Erwann Chenede  <erwann.chenede@sun.com>
+ *    Mark McLoughlin  <mark@skynet.ie>  
+ *    Joe Marcus Clarke  <marcus@freebsd.org>
+ */
+
+#include <config.h>
+
+#include "netstatus-sysdeps.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include <errno.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <dev/an/if_aironet_ieee.h>
+#include <dev/wi/if_wavelan_ieee.h>
+#endif
+
+static inline gboolean
+parse_stats (char    *buf,
+            int      prx_idx,
+            int      ptx_idx,
+            gulong  *in_packets,
+            gulong  *out_packets,
+            int      brx_idx,
+            int      btx_idx,
+            gulong  *in_bytes,
+            gulong  *out_bytes)
+{
+  char *p;
+  int   i;
+
+  p = strtok (buf, " \t\n");
+  for (i = 0; p; i++, p = strtok (NULL, " \t\n"))
+    {
+      if (i == prx_idx)
+       *in_packets = g_ascii_strtoull (p, NULL, 10);
+      if (i == ptx_idx)
+       *out_packets = g_ascii_strtoull (p, NULL, 10);
+      if (i == brx_idx)
+       *in_bytes = g_ascii_strtoull (p, NULL, 10);
+      if (i == btx_idx)
+       *out_bytes = g_ascii_strtoull (p, NULL, 10);
+    }
+
+  if (i <= prx_idx || i <= ptx_idx || i <= brx_idx || i <=btx_idx)
+    return FALSE;
+
+  return TRUE;
+}
+
+#if !defined (__FreeBSD__)
+
+static inline char *
+parse_iface_name (const char *buf)
+{
+  char *p1;
+
+  if ((p1 = strchr (buf, ':')))
+    {
+      char *p2;
+
+      p2 = strchr (p1, ':');
+      if (p2)
+       *p2++ = '\0';
+      else
+       *p1++ = '\0';
+
+      return p2 ? p2 : p1;
+    }
+  else if ((p1 = strchr (buf, ' ')))
+    {
+      *p1++ = '\0';
+      return p1;
+    }
+
+  return NULL;
+}
+
+static inline void
+parse_stats_header (char *buf,
+                   int  *prx_idx,
+                   int  *ptx_idx,
+                   int  *brx_idx,
+                   int  *btx_idx)
+{
+  char *p;
+  int   i;
+
+  *prx_idx = *ptx_idx = -1;
+  *brx_idx = *btx_idx = -1;
+
+  p = strtok (buf, "| \t\n");
+  p = strtok (NULL, "| \t\n"); /* Skip the first one */
+  for (i = 0; p; i++, p = strtok (NULL, "| \t\n"))
+    {
+      if (!strcmp (p, "packets"))
+       {
+         if (*prx_idx == -1)
+           *prx_idx = i;
+         else
+           *ptx_idx = i;
+       }
+      else if (!strcmp (p, "bytes"))
+       {
+         if (*brx_idx == -1)
+           *brx_idx = i;
+         else
+           *btx_idx = i;
+       }
+    }
+}
+
+static inline FILE *
+get_proc_net_dev_fh (void)
+{
+  static FILE *retval = NULL;
+
+  if (retval != NULL)
+    return retval;
+
+  return retval = fopen ("/proc/net/dev", "r");
+}
+
+char *
+netstatus_sysdeps_read_iface_statistics (const char  *iface,
+                                        gulong      *in_packets,
+                                        gulong      *out_packets,
+                                        gulong      *in_bytes,
+                                        gulong      *out_bytes)
+{
+  FILE *fh;
+  char  buf [512];
+  int   prx_idx, ptx_idx;
+  int   brx_idx, btx_idx;
+  char *error_message = NULL;
+
+  g_return_val_if_fail (iface != NULL, NULL);
+  g_return_val_if_fail (in_packets != NULL, NULL);
+  g_return_val_if_fail (out_packets != NULL, NULL);
+  g_return_val_if_fail (in_bytes != NULL, NULL);
+  g_return_val_if_fail (out_bytes != NULL, NULL);
+  
+  *in_packets  = -1;
+  *out_packets = -1;
+  *in_bytes    = -1;
+  *out_bytes   = -1;
+
+  fh = get_proc_net_dev_fh ();
+  if (!fh)
+    return g_strdup_printf (_("Cannot open /proc/net/dev: %s"),
+                           g_strerror (errno));
+
+  fgets (buf, sizeof (buf), fh);
+  fgets (buf, sizeof (buf), fh);
+
+  parse_stats_header (buf, &prx_idx, &ptx_idx, &brx_idx, &btx_idx);
+  if (prx_idx == -1 || ptx_idx == -1 ||
+      brx_idx == -1 || btx_idx == -1)
+    return g_strdup (_("Could not parse /proc/net/dev. Unknown format."));
+
+  while (fgets (buf, sizeof (buf), fh))
+    {
+      char *stats;
+      char *name;
+
+      name = buf;
+      while (g_ascii_isspace (name [0]))
+       name++;
+
+      stats = parse_iface_name (name);
+      if (!stats)
+       {
+         if (!error_message)
+           error_message = g_strdup_printf (_("Could not parse interface name from '%s'"), buf);
+         continue;
+       }
+
+      if (strcmp (name, iface) != 0)
+       continue;
+
+      if (!parse_stats (stats,
+                       prx_idx, ptx_idx, in_packets, out_packets,
+                       brx_idx, btx_idx, in_bytes, out_bytes))
+       {
+         if (error_message)
+           g_free (error_message);
+         error_message = g_strdup_printf (_("Could not parse interface statistics from '%s'. "
+                                            "prx_idx = %d; ptx_idx = %d; brx_idx = %d; btx_idx = %d;"),
+                                          buf, prx_idx, ptx_idx, brx_idx, btx_idx);
+         continue;
+       }
+
+      break;
+    }
+
+  if ((*in_packets == -1 || *out_packets == -1 || *in_bytes == -1 || *out_bytes == -1) && !error_message)
+    error_message = g_strdup_printf ("Could not find information on interface '%s' in /proc/net/dev", iface);
+
+  rewind (fh);
+  fflush (fh);
+
+  return error_message;
+}
+
+static inline gboolean
+parse_wireless (char  *buf,
+               int    link_idx,
+               int   *link)
+{
+  char *p;
+  int   i;
+
+  p = strtok (buf, " \t\n");
+  for (i = 0; p; i++, p = strtok (NULL, " \t\n"))
+    {
+      if (i == link_idx)
+       *link = g_ascii_strtoull (p, NULL, 10);
+    }
+
+  if (i <= link_idx)
+    return FALSE;
+
+  return TRUE;
+}
+
+static inline int
+parse_wireless_header (char *buf)
+{
+  char *p;
+  int   i;
+
+  p = strtok (buf, "| \t\n");
+  p = strtok (NULL, "| \t\n"); /* Skip the first one */
+  for (i = 0; p; i++, p = strtok (NULL, "| \t\n"))
+    {
+      if (!strcmp (p, "link"))
+       {
+         return i;
+       }
+    }
+
+  return -1;
+}
+
+static inline FILE *
+get_proc_net_wireless_fh (void)
+{
+  static FILE *retval = NULL;
+
+  if (retval != NULL)
+    return retval;
+
+  return retval = fopen ("/proc/net/wireless", "r");
+}
+
+char *
+netstatus_sysdeps_read_iface_wireless_details (const char *iface,
+                                              gboolean   *is_wireless,
+                                              int        *signal_strength)
+{
+  FILE *fh;
+  char  buf [512];
+  int   link_idx;
+  char *error_message = NULL;
+
+  g_return_val_if_fail (iface != NULL, NULL);
+  g_return_val_if_fail (is_wireless != NULL, NULL);
+  g_return_val_if_fail (signal_strength != NULL, NULL);
+
+  if (is_wireless)
+    *is_wireless = FALSE;
+  if (signal_strength)
+    *signal_strength = 0;
+  
+  fh = get_proc_net_wireless_fh ();
+  if (!fh)
+    return NULL;
+
+  fgets (buf, sizeof (buf), fh);
+  fgets (buf, sizeof (buf), fh);
+
+  link_idx = parse_wireless_header (buf);
+  if (link_idx == -1)
+    return g_strdup (_("Could not parse /proc/net/wireless. Unknown format."));
+
+  while (fgets (buf, sizeof (buf), fh))
+    {
+      char *details;
+      char *name;
+      int   link;
+
+      name = buf;
+      while (g_ascii_isspace (name [0]))
+       name++;
+
+      details = parse_iface_name (name);
+      if (!details)
+       {
+         if (!error_message)
+           error_message = g_strdup_printf (_("Could not parse interface name from '%s'"), buf);
+         continue;
+       }
+
+      if (strcmp (name, iface) != 0)
+       continue;
+
+      if (!parse_wireless (details, link_idx, &link))
+       {
+         if (error_message)
+           g_free (error_message);
+         error_message = g_strdup_printf (_("Could not parse wireless details from '%s'. link_idx = %d;"),
+                                          buf, link_idx);
+         continue;
+       }
+
+      /* Stolen from the wireless applet */
+      *signal_strength = (int) rint ((log (link) / log (92)) * 100.0);
+      *signal_strength = CLAMP (*signal_strength, 0, 100);
+      *is_wireless = TRUE;
+
+      break;
+    }
+
+  rewind (fh);
+  fflush (fh);
+
+  return error_message;
+}
+
+#else /* defined(__FreeBSD__) */
+
+static inline void
+parse_header (char *buf,
+             int  *prx_idx,
+             int  *ptx_idx,
+             int  *brx_idx,
+             int  *btx_idx)
+{
+   char *p;
+   int   i;
+
+   *prx_idx = *ptx_idx = -1;
+   *brx_idx = *btx_idx = -1;
+
+   p = strtok (buf, " \n\t");
+   for (i = 0; p; i++, p = strtok (NULL, " \t\n"))
+     {
+        if (!strcmp (p, "Ipkts"))
+         {
+            *prx_idx = i;
+         }
+       else if (!strcmp (p, "Ibytes"))
+         {
+            *brx_idx = i;
+         }
+       else if (!strcmp (p, "Opkts"))
+         {
+            *ptx_idx = i;
+         }
+       else if (!strcmp (p, "Obytes"))
+         {
+            *btx_idx = i;
+         }
+     }
+}
+
+static inline gboolean
+wireless_getval (const char      *iface,
+                gpointer         req,
+                unsigned long    req_type,
+                char           **error)
+{
+  struct ifreq ifr;
+  int          s;
+
+  memset (&ifr, 0, sizeof (ifr));
+
+  strlcpy (ifr.ifr_name, iface, sizeof (ifr.ifr_name));
+  ifr.ifr_data = (caddr_t) req;
+
+  s = socket (AF_INET, SOCK_DGRAM, 0);
+  if (s == -1)
+    {
+      *error = g_strdup_printf (_("Could not connect to interface, '%s'"), iface);
+      return FALSE;
+    }
+
+  if (ioctl (s, req_type, &ifr) == -1)
+    {
+      *error = g_strdup_printf (_("Could not send ioctl to interface, '%s'"), iface);
+      close (s);
+      return FALSE;
+    }
+
+  close (s);
+  return TRUE;
+}
+
+static inline char *
+get_an_data (const char *iface,
+            int        *signal_strength)
+{
+#ifdef AN_RID_RSSI_MAP
+  struct an_ltv_rssi_map  an_rssimap;
+#endif
+  struct an_req         areq;
+  struct an_ltv_status *sts;
+  int                   level;
+  char                 *error = NULL;
+  gboolean              rssimap_valid = FALSE;
+
+#ifdef AN_RID_RSSI_MAP
+  an_rssimap.an_len = sizeof (an_rssimap);
+  an_rssimap.an_type = AN_RID_RSSI_MAP;
+  rssimap_valid = wireless_getval (iface, (gpointer) &an_rssimap, SIOCGAIRONET, &error);
+#endif
+
+  areq.an_len = sizeof (areq);
+  areq.an_type = AN_RID_STATUS;
+
+  if (!wireless_getval (iface, (gpointer) &areq, SIOCGAIRONET, &error))
+    return error;
+
+  sts = (struct an_ltv_status *) &areq;
+
+#ifdef AN_RID_RSSI_MAP
+  if (rssimap_valid)
+    level = (int) (an_rssimap.an_entries[sts->an_normalized_strength].an_rss_pct);
+  else
+    level = (int) (sts->an_normalized_strength);
+#else
+  level = (int) (sts->an_normalized_rssi);
+#endif
+
+  memcpy (signal_strength, &level, sizeof (signal_strength));
+
+  return error;
+}
+
+static inline char *
+get_wi_data (const char *iface,
+            int        *signal_strength)
+{
+  struct wi_req  wreq;
+  int            level;
+  char          *error = NULL;
+
+  memset (&wreq, 0, sizeof (wreq));
+
+  wreq.wi_len  = WI_MAX_DATALEN;
+  wreq.wi_type = WI_RID_COMMS_QUALITY;
+
+  if (!wireless_getval (iface, &wreq, SIOCGWAVELAN, &error))
+    return error;
+
+  level = (int) wreq.wi_val[1];
+
+#ifdef WI_RID_READ_APS
+  if (signal_strength <= 0)
+    {
+      /* we fail to get signal strength by usual means, try another way */
+      static time_t   last_scan;
+      static long int cached;
+      time_t          now;
+
+      now = time (NULL);
+
+      /* XXX: this is long operation, and we will scan station not often then one in 5 secs */
+      if (now > last_scan + 5)
+        {
+          struct wi_apinfo *w;
+          int              nstations;
+
+          bzero (&wreq, sizeof (wreq));
+          wreq.wi_len  = WI_MAX_DATALEN;
+          wreq.wi_type = WI_RID_READ_APS;
+          if (!wireless_getval (iface, &wreq, SIOCGWAVELAN, &error))
+            return error;
+          nstations = *(int *) wreq.wi_val;
+          if (nstations > 0)
+           {
+              w = (struct wi_apinfo *)(((char *) &wreq.wi_val) + sizeof (int));
+              signal_strength = (long int) w->signal;
+            }
+
+            cached = signal_strength;
+            last_scan = now;
+          }
+        else
+         {
+            signal_strength = cached;
+          }
+    }
+#endif
+
+  memcpy (signal_strength, &level, sizeof (signal_strength));
+
+  return error;
+}
+
+char *
+netstatus_sysdeps_read_iface_wireless_details (const char *iface,
+                                              gboolean   *is_wireless,
+                                              int        *signal_strength)
+{
+  char *error_message = NULL;
+
+  g_return_val_if_fail (iface != NULL, NULL);
+  g_return_val_if_fail (is_wireless != NULL, NULL);
+  g_return_val_if_fail (signal_strength != NULL, NULL);
+
+  if (is_wireless)
+    *is_wireless = FALSE;
+  if (signal_strength)
+    *signal_strength = 0;
+
+  if (g_strncasecmp (iface, "an",   2) &&
+      g_strncasecmp (iface, "wi",   2) &&
+      g_strncasecmp (iface, "ath",  3) &&
+      g_strncasecmp (iface, "ndis", 4) &&
+      g_strncasecmp (iface, "ipw",  3) &&
+      g_strncasecmp (iface, "iwi",  3) &&
+      g_strncasecmp (iface, "acx",  3))
+    return error_message;
+
+  if (g_strncasecmp (iface, "an", 2) == 0)
+    {
+      error_message = get_an_data (iface, signal_strength);
+      *is_wireless = TRUE;
+    }
+  else
+    {
+      error_message = get_wi_data (iface, signal_strength);
+      *is_wireless = TRUE;
+    }
+
+  return error_message;
+}
+
+char *
+netstatus_sysdeps_read_iface_statistics (const char *iface,
+                                        gulong     *in_packets,
+                                        gulong     *out_packets,
+                                        gulong     *in_bytes,
+                                        gulong     *out_bytes)
+{
+  GError  *error;
+  char    *command_line;
+  char   **argv;
+  char    *error_message = NULL;
+  int      pipe_out;
+
+  g_return_val_if_fail (iface != NULL, NULL);
+  g_return_val_if_fail (in_packets != NULL, NULL);
+  g_return_val_if_fail (out_packets != NULL, NULL);
+  g_return_val_if_fail (in_bytes != NULL, NULL);
+  g_return_val_if_fail (out_bytes != NULL, NULL);
+
+  *in_packets  = -1;
+  *out_packets = -1;
+  *in_bytes    = -1;
+  *out_bytes   = -1;
+
+  error = NULL;
+  command_line = g_strdup_printf ("/usr/bin/netstat -n -I %s -b -f inet", iface);
+  if (!g_shell_parse_argv (command_line, NULL, &argv, &error))
+    {
+      error_message = g_strdup_printf (_("Could not parse command line '%s': %s"),
+                                      command_line,
+                                      error->message);
+      g_error_free (error);
+      g_free (command_line);
+      
+      return error_message;
+    }
+  g_free (command_line);
+
+  error = NULL;
+  if (g_spawn_async_with_pipes (NULL,
+                               argv,
+                               NULL,
+                               0,
+                               NULL,
+                               NULL,
+                               NULL,
+                               NULL,
+                               &pipe_out,
+                               NULL,
+                               &error))
+    {
+      GIOChannel *channel;
+      char       *buf;
+      int         prx_idx, ptx_idx;
+      int         brx_idx, btx_idx;
+
+      channel = g_io_channel_unix_new (pipe_out);
+
+      g_io_channel_read_line (channel, &buf, NULL, NULL, NULL);
+      parse_header (buf, &prx_idx, &ptx_idx, &brx_idx, &btx_idx);
+      g_free (buf);
+
+      if (prx_idx == -1 || ptx_idx == -1 ||
+         brx_idx == -1 || btx_idx == -1)
+       {
+         error_message = g_strdup (_("Could not parse 'netstat' output. Unknown format"));
+         goto error_shutdown;
+       }
+
+      g_io_channel_read_line (channel, &buf, NULL, NULL, NULL);
+
+      if (!parse_stats (buf,
+                       prx_idx, ptx_idx, in_packets, out_packets,
+                       brx_idx, btx_idx, in_bytes, out_bytes))
+       {
+         error_message = g_strdup_printf (_("Could not parse interface statistics from '%s'. "
+                                            "prx_idx = %d; ptx_idx = %d; brx_idx = %d; btx_idx = %d;"),
+                                          buf, prx_idx, ptx_idx, brx_idx, btx_idx);
+       }
+      else if (*in_packets == -1 || *out_packets == -1 || *in_bytes == -1 || *out_bytes == -1)
+       {
+         error_message = g_strdup_printf ("Could not obtain information on interface '%s' from netstat",
+                                          iface);
+       }
+
+      g_free (buf);
+
+    error_shutdown:
+      g_io_channel_unref (channel);
+      close (pipe_out);
+    }
+  else
+    {
+      error_message = g_strdup_printf ("Error running /usr/bin/netstat for '%s': %s", 
+                                      iface, error->message);
+      g_error_free (error);
+    }
+
+  g_strfreev (argv);
+
+  return error_message;
+}
+
+#endif /* !defined(__FreeBSD__) */
diff --git a/src/plugins/netstatus/netstatus-sysdeps.h b/src/plugins/netstatus/netstatus-sysdeps.h
new file mode 100644 (file)
index 0000000..fbb8c0f
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ * Copyright (C) 2004 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * 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.
+ *
+ * Authors:
+ *    Erwann Chenede  <erwann.chenede@sun.com>
+ *    Mark McLoughlin  <mark@skynet.ie>  
+ */
+
+#ifndef __NETSTATUS_SYSDEPS_H__
+#define __NETSTATUS_SYSDEPS_H__
+
+#include <glib/gtypes.h>
+#include <glib/gmacros.h>
+
+G_BEGIN_DECLS
+
+char *netstatus_sysdeps_read_iface_statistics       (const char *iface,
+                                                    gulong     *in_packets,
+                                                    gulong     *out_packets,
+                                                    gulong     *in_bytes,
+                                                    gulong     *out_bytes);
+char *netstatus_sysdeps_read_iface_wireless_details (const char *iface,
+                                                    gboolean   *is_wireless,
+                                                    int        *signal_strength);
+
+G_END_DECLS
+
+#endif /* __NETSTATUS_SYSDEPS_H__ */
diff --git a/src/plugins/netstatus/netstatus-util.c b/src/plugins/netstatus/netstatus-util.c
new file mode 100644 (file)
index 0000000..551f8b6
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * netstatus-util.c: Utility methods.
+ *
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * 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.
+
+ * Authors:
+ *      Mark McLoughlin <mark@skynet.ie>
+ */
+
+#include <config.h>
+
+#include "netstatus-util.h"
+
+#include <glib-object.h>
+#include <glib/gi18n.h>
+#include <string.h>
+
+#ifdef G_ENABLE_DEBUG
+NetstatusDebugFlags _netstatus_debug_flags = NETSTATUS_DEBUG_NONE;
+
+void
+netstatus_setup_debug_flags (void)
+{
+  const char       *env_str;
+  static GDebugKey  debug_keys [] =
+    {
+      { "polling", NETSTATUS_DEBUG_POLLING }
+    };
+
+  env_str = g_getenv ("NETSTATUS_DEBUG");
+
+  if (env_str)
+    _netstatus_debug_flags |= g_parse_debug_string (env_str,
+                                                   debug_keys,
+                                                   G_N_ELEMENTS (debug_keys));
+}
+#endif /* G_ENABLE_DEBUG */
+
+GQuark
+netstatus_error_quark (void)
+{
+  static GQuark error_quark = 0;
+
+  if (error_quark == 0)
+    error_quark = g_quark_from_static_string ("netstatus-error-quark");
+
+  return error_quark;
+}
+
+/* Remove this if there is ever a boxed type for
+ * GError with glib as standard.
+ */
+GType
+netstatus_g_error_get_type (void)
+{
+  static GType type_id = 0;
+
+  if (type_id == 0)
+    type_id = g_boxed_type_register_static ("NetstatusGError",
+                                           (GBoxedCopyFunc) g_error_copy,
+                                           (GBoxedFreeFunc) g_error_free);
+
+  return type_id;
+}
+
+static NetstatusStats *
+netstatus_stats_copy (NetstatusStats *stats)
+{
+  return (NetstatusStats *)g_memdup (stats, sizeof (NetstatusStats));
+}
+
+static void
+netstatus_stats_free (NetstatusStats *stats)
+{
+  g_free (stats);
+}
+
+GType
+netstatus_stats_get_type (void)
+{
+  static GType type_id = 0;
+
+  if (type_id == 0)
+    type_id = g_boxed_type_register_static ("NetstatusStats",
+                                           (GBoxedCopyFunc) netstatus_stats_copy,
+                                           (GBoxedFreeFunc) netstatus_stats_free);
+
+  return type_id;
+}
+
+/* Adopt an existing error into our domain.
+ */
+void
+netstatus_adopt_error (GError         *error,
+                      NetstatusError  code)
+{
+  g_return_if_fail (error != NULL);
+
+  error->domain = NETSTATUS_ERROR;
+  error->code   = code;
+}
+
+void
+netstatus_connect_signal_while_alive (gpointer    object,
+                                     const char *detailed_signal,
+                                     GCallback   func,
+                                     gpointer    func_data,
+                                     gpointer    alive_object)
+{
+  GClosure *closure;
+  GType     type;
+  guint     signal_id = 0;
+  GQuark    detail = 0;
+  
+  type = G_OBJECT_TYPE (object);
+
+  if (!g_signal_parse_name (detailed_signal, type, &signal_id, &detail, FALSE))
+    {
+      g_warning (G_STRLOC ": unable to parse signal \"%s\" for type \"%s\"",
+                detailed_signal, g_type_name (type));
+      return;
+    }
+
+  closure = g_cclosure_new (func, func_data, NULL);
+  g_object_watch_closure (G_OBJECT (alive_object), closure);
+  g_signal_connect_closure_by_id (object, signal_id, detail, closure, FALSE);
+}
+
+G_CONST_RETURN char *
+netstatus_get_state_string (NetstatusState state)
+{
+  char *retval = NULL;
+
+  switch (state)
+    {
+    case NETSTATUS_STATE_DISCONNECTED:
+      retval = _("Disconnected");
+      break;
+    case NETSTATUS_STATE_IDLE:
+      retval = _("Idle");
+      break;
+    case NETSTATUS_STATE_TX:
+      retval = _("Sending");
+      break;
+    case NETSTATUS_STATE_RX:
+      retval = _("Receiving");
+      break;
+    case NETSTATUS_STATE_TX_RX:
+      retval = _("Sending/Receiving");
+      break;
+    case NETSTATUS_STATE_ERROR:
+      retval = _("Error");
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+    }
+
+  return retval;
+}
+
+GList *
+netstatus_list_insert_unique (GList *list,
+                             char  *str)
+{
+  GList *l;
+
+  g_return_val_if_fail (str != NULL, list);
+
+  for (l = list; l; l = l->next)
+    if (!strcmp (str, l->data))
+      return list;
+
+  return g_list_prepend (list, str);
+}
diff --git a/src/plugins/netstatus/netstatus-util.h b/src/plugins/netstatus/netstatus-util.h
new file mode 100644 (file)
index 0000000..b717e15
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ * Copyright (C) 2004 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * 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.
+
+ * Authors:
+ *      Mark McLoughlin <mark@skynet.ie>
+ */
+
+#ifndef __NETSTATUS_UTIL_H__
+#define __NETSTATUS_UTIL_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define NETSTATUS_ERROR        (netstatus_error_quark ())
+#define NETSTATUS_TYPE_G_ERROR (netstatus_g_error_get_type ())
+#define NETSTATUS_TYPE_STATS   (netstatus_stats_get_type ())
+
+typedef enum {
+  NETSTATUS_STATE_DISCONNECTED = 0,
+  NETSTATUS_STATE_IDLE = 1,
+  NETSTATUS_STATE_TX = 2,
+  NETSTATUS_STATE_RX = 3,
+  NETSTATUS_STATE_TX_RX = 4,
+  NETSTATUS_STATE_ERROR = 5,
+  NETSTATUS_STATE_LAST = 6
+} NetstatusState;
+
+typedef enum {
+  NETSTATUS_ERROR_NONE             = 0,
+  NETSTATUS_ERROR_ICONS            = 1, /* Can't locate the icon files */
+  NETSTATUS_ERROR_SOCKET           = 2, /* Can't open socket */
+  NETSTATUS_ERROR_STATISTICS       = 3, /* Can't find statistics on the interface */
+  NETSTATUS_ERROR_IOCTL_IFFLAGS    = 4, /* SIOCGIFFLAGS failed */
+  NETSTATUS_ERROR_IOCTL_IFCONF     = 5, /* SIOCGIFCONF failed */
+  NETSTATUS_ERROR_NO_INTERFACES    = 6, /* No interfaces found */
+  NETSTATUS_ERROR_WIRELESS_DETAILS = 7  /* Error finding wireless details
+                                         * (not an error if iface isn't wireless)
+                                        */
+} NetstatusError;
+
+typedef enum {
+  NETSTATUS_DEBUG_NONE    = 0,
+  NETSTATUS_DEBUG_POLLING = 1 << 0
+} NetstatusDebugFlags;
+
+typedef struct
+{
+  gulong in_packets;
+  gulong out_packets;
+  gulong in_bytes;
+  gulong out_bytes;
+} NetstatusStats;
+
+GQuark               netstatus_error_quark                (void);
+GType                netstatus_g_error_get_type           (void);
+GType                netstatus_stats_get_type             (void);
+void                 netstatus_adopt_error                (GError         *error,
+                                                          NetstatusError  code);
+
+G_CONST_RETURN char *netstatus_get_state_string           (NetstatusState  state);
+
+GList               *netstatus_list_insert_unique         (GList          *list,
+                                                          char           *str);
+
+void                 netstatus_connect_signal_while_alive (gpointer        object,
+                                                          const char     *detailed_signal,
+                                                          GCallback       func,
+                                                          gpointer        func_data,
+                                                          gpointer        alive_object);
+
+#ifdef G_ENABLE_DEBUG
+
+#include <stdio.h>
+
+extern NetstatusDebugFlags _netstatus_debug_flags;
+
+#ifdef G_HAVE_ISO_VARARGS
+#  define dprintf(type, ...) G_STMT_START {                   \
+        if (_netstatus_debug_flags & NETSTATUS_DEBUG_##type)  \
+                fprintf (stderr, __VA_ARGS__);                \
+        } G_STMT_END
+#elif defined(G_HAVE_GNUC_VARARGS)
+#  define dprintf(type, args...) G_STMT_START {               \
+        if (_netstatus_debug_flags & NETSTATUS_DEBUG_##type)  \
+                fprintf (stderr, args);                       \
+        } G_STMT_END
+#endif
+
+void netstatus_setup_debug_flags (void);
+
+#else /* if !defined (G_ENABLE_DEBUG) */
+
+#ifdef G_HAVE_ISO_VARARGS
+#  define dprintf(...)
+#elif defined(G_HAVE_GNUC_VARARGS)
+#  define dprintf(args...)
+#endif
+
+#define netstatus_setup_debug_flags()
+
+#endif /* G_ENABLE_DEBUG */
+
+G_END_DECLS
+
+#endif /* __NETSTATUS_UTIL_H__ */
diff --git a/src/plugins/netstatus/netstatus.c b/src/plugins/netstatus/netstatus.c
new file mode 100644 (file)
index 0000000..263e416
--- /dev/null
@@ -0,0 +1,130 @@
+#include <gtk/gtk.h>
+#include <stdlib.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "panel.h"
+#include "misc.h"
+#include "plugin.h"
+
+//#define DEBUG
+#include "dbg.h"
+
+#include "netstatus-icon.h"
+
+typedef struct {
+    char *iface;
+    GtkWidget *mainw;
+} netstatus;
+
+
+static void
+netstatus_destructor(plugin *p)
+{
+    netstatus *ns = (netstatus *)p->priv;
+
+    ENTER;
+    gtk_widget_destroy(ns->mainw);
+    g_free( ns->iface );
+    g_free(ns);
+    RET();
+}
+
+static  int
+_get_line(FILE *fp, line *s)
+{
+    gchar *tmp, *tmp2;
+
+    ENTER;
+    s->type = LINE_NONE;
+    if (!fp)
+        RET(s->type);
+    while (fgets(s->str, s->len, fp)) {
+        g_strstrip(s->str);
+
+        if (s->str[0] == '#' || s->str[0] == 0) {
+            continue;
+        }
+        if (!g_ascii_strcasecmp(s->str, "}")) {
+            s->type = LINE_BLOCK_END;
+            break;
+        }
+
+        s->t[0] = s->str;
+        for (tmp = s->str; isalnum(*tmp); tmp++);
+        for (tmp2 = tmp; isspace(*tmp2); tmp2++);
+        if (*tmp2 == '=') {
+            for (++tmp2; isspace(*tmp2); tmp2++);
+            s->t[1] = tmp2;
+            *tmp = 0;
+            s->type = LINE_VAR;
+        } else if  (*tmp2 == '{') {
+            *tmp = 0;
+            s->type = LINE_BLOCK_START;
+        } else {
+            ERR( "parser: unknown token: '%c'\n", *tmp2);
+        }
+        break;
+    }
+    RET(s->type);
+}
+
+static int
+netstatus_constructor(plugin *p)
+{
+    netstatus *ns;
+    line s;
+    int w, h;
+    NetstatusIface* iface;
+
+    ENTER;
+    s.len = 256;  
+    ns = g_new0(netstatus, 1);
+    g_return_val_if_fail(ns != NULL, 0);
+    p->priv = ns;
+    while (_get_line(p->fp, &s) != LINE_BLOCK_END) {
+        if (s.type == LINE_NONE) {
+            ERR( "netstatus: illegal token %s\n", s.str);
+            goto error;
+        }
+        if (s.type == LINE_VAR) {
+            if (!g_ascii_strcasecmp(s.t[0], "iface"))
+                ns->iface = g_strdup(s.t[1]);
+            else {
+                ERR( "netstatus: unknown var %s\n", s.t[0]);
+                goto error;
+            }
+        } else {
+            ERR( "netstatus: illegal in this context %s\n", s.str);
+            goto error;
+        }
+    }
+
+    iface = netstatus_iface_new(ns->iface);
+    ns->mainw = netstatus_icon_new( iface );
+    gtk_widget_set_size_request( ns->mainw, 24, 24 );
+
+    gtk_widget_show_all(ns->mainw);
+
+    gtk_container_add(GTK_CONTAINER(p->pwid), ns->mainw);
+
+    RET(1);
+
+ error:
+    netstatus_destructor(p);
+    RET(0);
+}
+
+
+plugin_class netstatus_plugin_class = {
+    fname: NULL,
+    count: 0,
+
+    type : "netstatus",
+    name : "netstatus",
+    version: "1.0",
+    description : "Net status",
+
+    constructor : netstatus_constructor,
+    destructor  : netstatus_destructor,
+};
diff --git a/src/plugins/netstatus/netstatus.schemas.in b/src/plugins/netstatus/netstatus.schemas.in
new file mode 100644 (file)
index 0000000..2389e4a
--- /dev/null
@@ -0,0 +1,43 @@
+<gconfschemafile>
+  <schemalist>    
+
+    <schema>
+      <key>/schemas/apps/netstatus_applet/prefs/interface</key>
+      <owner>netstatus-applet</owner>
+      <type>string</type>
+      <default></default>
+      <locale name="C">
+        <short>Network interface</short>
+        <long>The Network Interface monitored by the Network Monitor.</long>
+      </locale>
+    </schema>
+
+    <!-- Yes, this key is purposely global to all instances of the applet -->
+    <schema>
+      <key>/schemas/apps/netstatus_applet/config_tool</key>
+      <applyto>/apps/netstatus_applet/config_tool</applyto>
+      <owner>netstatus-applet</owner>
+      <type>string</type>
+      <default></default>
+      <locale name="C">
+        <short>Network configuration tool</short>
+        <long>
+         This key specifies the name of the network configuration tool
+         which should be invoked when the "Configure" button in the
+         properties dialog is clicked.
+
+         If the configuration tool can take a parameter of the interface
+         to configure you may use %i in the string and it will be
+         substituted with the interface name before invoking the
+         configuration tool.
+
+         For example, gnome-system-tool's network-admin tool takes
+          the interface name through a --configure parameter. Thus,
+          you could set the value of this key to be:
+                  "network-admin --configure %i".
+       </long>
+      </locale>
+    </schema>
+                 
+  </schemalist>
+</gconfschemafile>