We finally work with PSK/WEPKEY_0 entry and we now save our config.
[dhcpcd-ui] / main.c
diff --git a/main.c b/main.c
index 1b6e522dbb41f210bd56ece496c6ed6b7b1357ad..edb4db6fedf0d939368a6131a1dfd0abfe57b444 100644 (file)
--- a/main.c
+++ b/main.c
  * maybe use network-idle -> network-transmit ->
  * network-receive -> network-transmit-receive */
 
-#include <arpa/inet.h>
-
+#include <locale.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include <dbus/dbus-glib.h>
-#include <gtk/gtk.h>
 #include <libnotify/notify.h>
 
-#include "config.h"
+#include "dhcpcd-gtk.h"
 #include "menu.h"
 
-/* Work out if we have a private address or not
- * 10/8
- * 172.16/12
- * 192.168/16
- */
-#ifndef IN_PRIVATE
-# define IN_PRIVATE(addr) (((addr & IN_CLASSA_NET) == 0x0a000000) || \
-                          ((addr & 0xfff00000)    == 0xac100000) || \
-                          ((addr & IN_CLASSB_NET) == 0xc0a80000))
-#endif
-#ifndef IN_LINKLOCAL
-# define IN_LINKLOCAL(addr) ((addr & IN_CLASSB_NET) == 0xa9fe0000)
-#endif
-
-struct if_msg {
-       char *name;
-       char *reason;
-       struct in_addr ip;
-       unsigned char cidr;
-       gboolean wireless;
-       char *ssid;
-};
+DBusGProxy *dbus = NULL;
+GList *interfaces = NULL;
 
-static DBusGProxy *bus_proxy;
 static GtkStatusIcon *status_icon;
-static GList *interfaces;
+static gint ani_timer;
+static int ani_counter;
 static gboolean online;
 static gboolean carrier;
-static NotifyNotification *nn;
-
 static char **interface_order;
+static NotifyNotification *nn;
 
 const char *const up_reasons[] = {
        "BOUND",
@@ -92,9 +68,6 @@ const char *const down_reasons[] = {
        NULL
 };
 
-/* Should be in a header */
-void notify_close(void);
-
 static gboolean
 ignore_if_msg(const struct if_msg *ifm)
 {
@@ -104,12 +77,41 @@ ignore_if_msg(const struct if_msg *ifm)
        return FALSE;
 }
 
+static struct if_msg *
+find_if_msg(const char *iface)
+{
+       GList *gl;
+       struct if_msg *ifm;
+
+       for (gl = interfaces; gl; gl = gl->next) {
+               ifm = (struct if_msg *)gl->data;
+               if (g_strcmp0(ifm->ifname, iface) == 0)
+                       return ifm;
+       }
+       return NULL;
+}
+
+static void
+free_if_ap(struct if_ap *ifa)
+{
+       g_free(ifa->ifname);
+       g_free(ifa->bssid);
+       g_free(ifa->flags);
+       g_free(ifa->ssid);
+       g_free(ifa);
+}
+
 static void
 free_if_msg(struct if_msg *ifm)
 {
-       g_free(ifm->name);
+       GSList *gl;
+
+       g_free(ifm->ifname);
        g_free(ifm->reason);
        g_free(ifm->ssid);
+       for (gl = ifm->scan_results; gl; gl = gl->next)
+               free_if_ap((struct if_ap *)gl->data);
+       g_slist_free(ifm->scan_results);
        g_free(ifm);
 }
 
@@ -144,6 +146,57 @@ error_exit(const char *msg, GError *error)
                exit(EXIT_FAILURE);
 }
 
+static GSList *
+get_scan_results(struct if_msg *ifm)
+{
+       GType otype;
+       GError *error;
+       GPtrArray *array;
+       GHashTable *config;
+       GSList *list = NULL;
+       struct if_ap *ifa;
+       guint i;
+       GValue *val;
+
+       otype = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
+       otype = dbus_g_type_get_collection("GPtrArray", otype);
+
+       if (!dbus_g_proxy_call(dbus, "ScanResults", &error,
+                              G_TYPE_STRING, ifm->ifname, G_TYPE_INVALID,
+                              otype, &array, G_TYPE_INVALID))
+               error_exit(_("ScanResults"), error);
+
+       for (i = 0; i < array->len; i++) {
+               config = g_ptr_array_index(array, i);
+               val = g_hash_table_lookup(config, "BSSID");
+               if (val == NULL)
+                       continue;
+               ifa = g_malloc0(sizeof(*ifa));
+               ifa->ifname = g_strdup(ifm->ifname);
+               ifa->bssid = g_strdup(g_value_get_string(val));
+               val = g_hash_table_lookup(config, "Frequency");
+               if (val)
+                       ifa->frequency = g_value_get_int(val);
+               val = g_hash_table_lookup(config, "Quality");
+               if (val)
+                       ifa->quality = g_value_get_int(val);
+               val = g_hash_table_lookup(config, "Noise");
+               if (val)
+                       ifa->noise = g_value_get_int(val);
+               val = g_hash_table_lookup(config, "Level");
+               if (val)
+                       ifa->level = g_value_get_int(val);
+               val = g_hash_table_lookup(config, "Flags");
+               if (val)
+                       ifa->flags = g_strdup(g_value_get_string(val));
+               val = g_hash_table_lookup(config, "SSID");
+               if (val)
+                       ifa->ssid = g_strdup(g_value_get_string(val));
+               list = g_slist_append(list, ifa);
+       }
+       return list;
+}
+
 static struct if_msg *
 make_if_msg(GHashTable *config)
 {
@@ -154,7 +207,7 @@ make_if_msg(GHashTable *config)
        if (val == NULL)
                return NULL;
        ifm = g_malloc0(sizeof(*ifm));
-       ifm->name = g_strdup(g_value_get_string(val));
+       ifm->ifname = g_strdup(g_value_get_string(val));
        val = g_hash_table_lookup(config, "Reason");
        if (val)
                ifm->reason = g_strdup(g_value_get_string(val));
@@ -202,34 +255,34 @@ print_if_msg(const struct if_msg *ifm)
        showip = TRUE;
        showssid = FALSE;
        if (if_up(ifm))
-               reason = "Acquired address";
+               reason = N_("Acquired address");
        else {
                if (g_strcmp0(ifm->reason, "EXPIRE") == 0)
-                       reason = "Failed to renew";
+                       reason = N_("Failed to renew");
                else if (g_strcmp0(ifm->reason, "CARRIER") == 0) {
                        if (ifm->wireless) {
-                               reason = "Asssociated with";
+                               reason = N_("Asssociated with");
                                if (ifm->ssid != NULL)
                                        showssid = TRUE;
                        } else
-                               reason = "Cable plugged in";
+                               reason = N_("Cable plugged in");
                        showip = FALSE;
                } else if (g_strcmp0(ifm->reason, "NOCARRIER") == 0) {
                        if (ifm->wireless) {
                                if (ifm->ssid != NULL || ifm->ip.s_addr != 0) {
-                                       reason = "Lost association with";
+                                       reason = N_("Disassociated from");
                                        showssid = TRUE;
                                } else
-                                   reason = "Not associated";
+                                   reason = N_("Not associated");
                        } else
-                               reason = "Cable unplugged";
+                               reason = N_("Cable unplugged");
                        showip = FALSE;
                }
        }
        if (reason == NULL)
                reason = ifm->reason;
        
-       len = strlen(ifm->name) + 3;
+       len = strlen(ifm->ifname) + 3;
        len += strlen(reason) + 1;
        if (ifm->ip.s_addr != 0) {
                len += 16; /* 000. * 4 */
@@ -239,7 +292,7 @@ print_if_msg(const struct if_msg *ifm)
        if (showssid)
                len += strlen(ifm->ssid) + 1;
        msg = p = g_malloc(len);
-       p += g_snprintf(msg, len, "%s: %s", ifm->name, reason);
+       p += g_snprintf(msg, len, "%s: %s", ifm->ifname, reason);
        if (showssid)
                p += g_snprintf(p, len - (p - msg), " %s", ifm->ssid);
        if (ifm->ip.s_addr != 0 && showip) {
@@ -259,20 +312,59 @@ if_msg_comparer(gconstpointer a, gconstpointer b)
        ifa = (const struct if_msg *)a;
        ifb = (const struct if_msg *)b;
        for (order = (const char *const *)interface_order; *order; order++) {
-               if (g_strcmp0(*order, ifa->name) == 0)
+               if (g_strcmp0(*order, ifa->ifname) == 0)
                        return -1;
-               if (g_strcmp0(*order, ifb->name) == 0)
+               if (g_strcmp0(*order, ifb->ifname) == 0)
                        return 1;
        }
        return 0;
 }
 
+static gboolean
+animate_carrier(_unused gpointer data)
+{
+       if (ani_timer == 0)
+               return FALSE;
+
+       switch(ani_counter++) {
+       case 0:
+               gtk_status_icon_set_from_icon_name(status_icon, "network-transmit");
+               break;
+       case 1:
+               gtk_status_icon_set_from_icon_name(status_icon, "network-receive");
+               break;
+       default:
+               gtk_status_icon_set_from_icon_name(status_icon, "network-idle");
+               ani_counter = 0;
+               break;
+       }
+       return TRUE;
+}
+
+static gboolean
+animate_online(_unused gpointer data)
+{
+       if (ani_timer == 0)
+               return FALSE;
+
+       if (ani_counter++ > 6) {
+               ani_timer = 0;
+               ani_counter = 0;
+               return FALSE;
+       }
+
+       if (ani_counter % 2 == 0)
+               gtk_status_icon_set_from_icon_name(status_icon, "network-idle");
+       else
+               gtk_status_icon_set_from_icon_name(status_icon, "network-transmit-receive");
+       return TRUE;
+}
+
 static void
 update_online(char **buffer)
 {
        gboolean ison, iscarrier;
        char *msg, *msgs, *tmp;
-       const char *icon;
        const GList *gl;
        const struct if_msg *ifm;
 
@@ -296,13 +388,21 @@ update_online(char **buffer)
 
        if (online != ison || carrier != iscarrier) {
                online = ison;
-               if (ison)
-                       icon = "network-transmit-receive";
-               else if (iscarrier)
-                       icon = "network-transmit";
-               else
-                       icon = "network-offline";
-               gtk_status_icon_set_from_icon_name(status_icon, icon);
+               if (ani_timer != 0) {
+                       g_source_remove(ani_timer);
+                       ani_timer = 0;
+                       ani_counter = 0;
+               }
+               if (ison) {
+                       animate_online(NULL);
+                       ani_timer = g_timeout_add(300, animate_online, NULL);
+               } else if (iscarrier) {
+                       animate_carrier(NULL);
+                       ani_timer = g_timeout_add(500, animate_carrier, NULL);
+               } else {
+                       gtk_status_icon_set_from_icon_name(status_icon,
+                                                          "network-offline");
+               }
        }
        gtk_status_icon_set_tooltip(status_icon, msgs);
        if (buffer)
@@ -366,7 +466,9 @@ dhcpcd_event(_unused DBusGProxy *proxy, GHashTable *config, _unused void *data)
        ifp = NULL;
        for (gl = interfaces; gl; gl = gl->next) {
                ifp = (struct if_msg *)gl->data;
-               if (g_strcmp0(ifp->name, ifm->name) == 0) {
+               if (g_strcmp0(ifp->ifname, ifm->ifname) == 0) {
+                       ifm->scan_results = ifp->scan_results;
+                       ifp->scan_results = NULL;
                        free_if_msg(ifp);
                        if (rem)
                                interfaces = g_list_delete_link(interfaces, gl);
@@ -388,23 +490,23 @@ dhcpcd_event(_unused DBusGProxy *proxy, GHashTable *config, _unused void *data)
        msg = print_if_msg(ifm);
        title = NULL;
        if (if_up(ifm))
-               act = "Connected to ";
+               act = N_("Connected to ");
        else
                act = NULL;
        for (r = down_reasons; *r; r++) {
                if (g_strcmp0(*r, ifm->reason) == 0) {
-                       act = "Disconnected from ";
+                       act = N_("Disconnected from ");
                        break;
                }
        }
        if (act && ifm->ip.s_addr) {
                ipn = htonl(ifm->ip.s_addr);
                if (IN_LINKLOCAL(ipn))
-                       net = "private network";
+                       net = N_("private network");
                else if (IN_PRIVATE(ipn))
-                       net = "LAN";
+                       net = N_("LAN");
                else
-                       net = "internet";
+                       net = N_("internet");
                title = g_strconcat(act, net, NULL);
        }
 
@@ -412,7 +514,7 @@ dhcpcd_event(_unused DBusGProxy *proxy, GHashTable *config, _unused void *data)
                notify(title, msg, GTK_STOCK_NETWORK);
                g_free(title);
        } else
-               notify("Interface event", msg, GTK_STOCK_NETWORK);
+               notify(N_("Interface event"), msg, GTK_STOCK_NETWORK);
        g_free(msg);
 }
 
@@ -435,10 +537,14 @@ dhcpcd_get_interfaces()
        GError *error = NULL;
        GType otype;
        char *msg;
+       GList *gl;
+       GSList *gsl;
+       GPtrArray *array;
+       struct if_msg *ifm;
 
        otype = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
        otype = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, otype);
-       if (!dbus_g_proxy_call(bus_proxy, "GetInterfaces", &error,
+       if (!dbus_g_proxy_call(dbus, "GetInterfaces", &error,
                               G_TYPE_INVALID,
                               otype, &ifs, G_TYPE_INVALID))
                error_exit("GetInterfaces", error);
@@ -449,16 +555,37 @@ dhcpcd_get_interfaces()
         * that interface was configured, so get the real order now. */
        g_strfreev(interface_order);
        interface_order = NULL;
-       if (!dbus_g_proxy_call(bus_proxy, "ListInterfaces", &error,
+       if (!dbus_g_proxy_call(dbus, "ListInterfaces", &error,
                               G_TYPE_INVALID,
                               G_TYPE_STRV, &interface_order, G_TYPE_INVALID))
                error_exit("ListInterfaces", error);
        interfaces = g_list_sort(interfaces, if_msg_comparer);
+
+       otype = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
+       otype = dbus_g_type_get_collection("GPtrArray", otype);
+       for (gl = interfaces; gl; gl = gl->next) {
+               ifm = (struct if_msg *)gl->data;
+               if (!ifm->wireless)
+                       continue;
+               if (!dbus_g_proxy_call(dbus, "ScanResults", &error,
+                                      G_TYPE_STRING, ifm->ifname, G_TYPE_INVALID,
+                                      otype, &array, G_TYPE_INVALID)) 
+               {
+                       g_message("ScanResults: %s", error->message);
+                       g_clear_error(&error);
+                       continue;
+               }
+               for (gsl = ifm->scan_results; gsl; gsl = gsl->next)
+                       g_free(gsl->data);
+               g_slist_free(ifm->scan_results);
+               ifm->scan_results = get_scan_results(ifm);
+       }
+
        msg = NULL;
        update_online(&msg);
        // GTK+ 2.16 msg = gtk_status_icon_get_tooltip_text(status_icon);
        if (msg != NULL) {
-               notify("Interface status", msg, GTK_STOCK_NETWORK);
+               notify(N_("Interface status"), msg, GTK_STOCK_NETWORK);
                g_free(msg);
        }
 }
@@ -473,16 +600,16 @@ check_status(const char *status)
        gboolean refresh;
        GError *error = NULL;
 
-       g_message("status changed to %s", status);
+       g_message("Status changed to %s", status);
        if (g_strcmp0(status, "down") == 0) {
                for (gl = interfaces; gl; gl = gl->next)
                        free_if_msg((struct if_msg *)gl->data);
                g_list_free(interfaces);
                interfaces = NULL;
                update_online(NULL);
-               msg = last? "Connection to dhcpcd lost" : "dhcpcd not running";
+               msg = N_(last? "Connection to dhcpcd lost" : "dhcpcd not running");
                gtk_status_icon_set_tooltip(status_icon, msg);
-               notify("No network", msg, GTK_STOCK_NETWORK);
+               notify(_("No network"), msg, GTK_STOCK_NETWORK);
        }
 
        refresh = FALSE;
@@ -500,11 +627,11 @@ check_status(const char *status)
 
        if (!refresh)
                return;
-       if (!dbus_g_proxy_call(bus_proxy, "GetDhcpcdVersion", &error,
+       if (!dbus_g_proxy_call(dbus, "GetDhcpcdVersion", &error,
                               G_TYPE_INVALID,
                               G_TYPE_STRING, &version, G_TYPE_INVALID))
-               error_exit("GetDhcpcdVersion", error);
-       g_message("Connected to dhcpcd-%s", version);
+               error_exit(_("GetDhcpcdVersion"), error);
+       g_message(_("Connected to %s-%s"), "dhcpcd", version);
        g_free(version);
        dhcpcd_get_interfaces();
 }
@@ -515,6 +642,47 @@ dhcpcd_status(_unused DBusGProxy *proxy, const char *status, _unused void *data)
        check_status(status);
 }
 
+static void
+dhcpcd_scan_results(_unused DBusGProxy *proxy, const char *iface, _unused void *data)
+{
+       struct if_msg *ifm;
+       struct if_ap *ifa, *ifa2;
+       GSList *gl, *aps, *l;
+       char *txt, *ntxt;
+
+       ifm = find_if_msg(iface);
+       if (ifm == NULL)
+               return;
+       g_message(_("%s: Received scan results"), ifm->ifname);
+       aps = get_scan_results(ifm);
+       txt = NULL;
+       for (gl = aps; gl; gl = gl->next) {
+               ifa = (struct if_ap *)gl->data;
+               for (l = ifm->scan_results; l; l = l->next) {
+                       ifa2 = (struct if_ap *)l->data;
+                       if (g_strcmp0(ifa->ssid, ifa2->ssid) == 0)
+                               break;
+               }
+               if (l == NULL) {
+                       if (txt == NULL)
+                               txt = g_strdup(ifa->ssid);
+                       else {
+                               ntxt =  g_strconcat(txt, "\n", ifa->ssid, NULL);
+                               g_free(txt);
+                               txt = ntxt;
+                       }
+               }
+       }
+       for (gl = ifm->scan_results; gl; gl = gl->next)
+               free_if_ap((struct if_ap *)gl->data);
+       g_slist_free(ifm->scan_results);
+       ifm->scan_results = aps;
+       if (txt != NULL) {
+               notify(N_("Found new AP"), txt, GTK_STOCK_NETWORK);
+               g_free(txt);
+       }
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -523,30 +691,38 @@ main(int argc, char *argv[])
        char *version = NULL;
        GType otype;
        int tries = 5;
-       
+
+               
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, NULL);
+       bind_textdomain_codeset(PACKAGE, "UTF-8");
+       textdomain(PACKAGE); 
+
        gtk_init(&argc, &argv);
        g_set_application_name("dhcpcd Monitor");
        status_icon = gtk_status_icon_new_from_icon_name("network-offline");
        if (status_icon == NULL)
                status_icon = gtk_status_icon_new_from_stock(GTK_STOCK_DISCONNECT);
+       //network_offline = gtk_status_icon_get_pixbuf(status_icon);
        
-       gtk_status_icon_set_tooltip(status_icon, "Connecting to dhcpcd ...");
+       gtk_status_icon_set_tooltip(status_icon, _("Connecting to dhcpcd ..."));
        gtk_status_icon_set_visible(status_icon, TRUE);
 
        notify_init(PACKAGE);
 
-       g_message("connecting to dbus ...");
+       g_message(_("Connecting to dbus ..."));
        bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
        if (bus == NULL || error != NULL)
-               error_exit("could not connect to system bus", error);
-       bus_proxy = dbus_g_proxy_new_for_name(bus,
+               error_exit(_("Could not connect to system bus"), error);
+       dbus = dbus_g_proxy_new_for_name(bus,
                                              DHCPCD_SERVICE,
                                              DHCPCD_PATH,
                                              DHCPCD_SERVICE);
 
-       g_message("connecting to dhcpcd-dbus ...");
+       g_message(_("Connecting to dhcpcd-dbus ..."));
        while (--tries > 0) {
-               if (dbus_g_proxy_call_with_timeout(bus_proxy,
+               g_clear_error(&error);
+               if (dbus_g_proxy_call_with_timeout(dbus,
                                                   "GetVersion",
                                                   500,
                                                   &error,
@@ -557,32 +733,37 @@ main(int argc, char *argv[])
                        break;
        }
        if (tries == 0)
-               error_exit("GetVersion", error);
-       g_message("Connected to dhcpcd-dbus-%s", version);
+               error_exit(_("GetVersion"), error);
+       g_message(_("Connected to %s-%s"), "dhcpcd-dbus", version);
        g_free(version);
 
-       gtk_status_icon_set_tooltip(status_icon, "Triggering dhcpcd ...");
+       gtk_status_icon_set_tooltip(status_icon, _("Triggering dhcpcd ..."));
        online = FALSE;
        menu_init(status_icon);
 
-       if (!dbus_g_proxy_call(bus_proxy, "GetStatus", &error,
+       if (!dbus_g_proxy_call(dbus, "GetStatus", &error,
                               G_TYPE_INVALID,
                               G_TYPE_STRING, &version, G_TYPE_INVALID))
-               error_exit("GetStatus", error);
+               error_exit(_("GetStatus"), error);
        check_status(version);
        g_free(version);
 
        otype = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
-       dbus_g_proxy_add_signal(bus_proxy, "Event",
+       dbus_g_proxy_add_signal(dbus, "Event",
                                otype, G_TYPE_INVALID);
-       dbus_g_proxy_connect_signal(bus_proxy, "Event",
+       dbus_g_proxy_connect_signal(dbus, "Event",
                                    G_CALLBACK(dhcpcd_event),
-                                   NULL, NULL);
-       dbus_g_proxy_add_signal(bus_proxy, "StatusChanged",
+                                   bus, NULL);
+       dbus_g_proxy_add_signal(dbus, "StatusChanged",
                                G_TYPE_STRING, G_TYPE_INVALID);
-       dbus_g_proxy_connect_signal(bus_proxy, "StatusChanged",
+       dbus_g_proxy_connect_signal(dbus, "StatusChanged",
                                    G_CALLBACK(dhcpcd_status),
-                                   NULL, NULL);
+                                   bus, NULL);
+       dbus_g_proxy_add_signal(dbus, "ScanResults",
+                               G_TYPE_STRING, G_TYPE_INVALID);
+       dbus_g_proxy_connect_signal(dbus, "ScanResults",
+                                   G_CALLBACK(dhcpcd_scan_results),
+                                   bus, NULL);
 
        gtk_main();
        return 0;