X-Git-Url: https://roy.marples.name/git diff --git a/main.c b/main.c index 1b6e522..edb4db6 100644 --- a/main.c +++ b/main.c @@ -28,49 +28,25 @@ * maybe use network-idle -> network-transmit -> * network-receive -> network-transmit-receive */ -#include - +#include #include #include -#include -#include #include -#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;