a1b9b906fc25d2c6178c4b1d261a14f158d4cbbc
[dhcpcd-ui] / main.c
1 /*
2  * dhcpcd-gtk
3  * Copyright 2009 Roy Marples <roy@marples.name>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 /* TODO: Animate the icon from carrier -> address
28  * maybe use network-idle -> network-transmit ->
29  * network-receive -> network-transmit-receive */
30
31 #include <locale.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include <libnotify/notify.h>
36
37 #include "dhcpcd-gtk.h"
38 #include "menu.h"
39
40 DBusGProxy *dbus = NULL;
41 GSList *interfaces = NULL;
42
43 static GtkStatusIcon *status_icon;
44 static gint ani_timer;
45 static int ani_counter;
46 static gboolean online;
47 static gboolean carrier;
48 static char **interface_order;
49 static NotifyNotification *nn;
50
51 const char *const up_reasons[] = {
52         "BOUND",
53         "RENEW",
54         "REBIND",
55         "REBOOT",
56         "IPV4LL",
57         "INFORM",
58         "TIMEOUT",
59         NULL
60 };
61
62 const char *const down_reasons[] = {
63         "EXPIRE",
64         "FAIL",
65         "NAK",
66         "NOCARRIER",
67         "STOP",
68         NULL
69 };
70
71 static gboolean
72 ignore_if_msg(const struct if_msg *ifm)
73 {
74         if (g_strcmp0(ifm->reason, "STOP") == 0 ||
75             g_strcmp0(ifm->reason, "RELEASE") == 0)
76                 return TRUE;
77         return FALSE;
78 }
79
80 static struct if_msg *
81 find_if_msg(const char *iface)
82 {
83         GSList *gl;
84         struct if_msg *ifm;
85
86         for (gl = interfaces; gl; gl = gl->next) {
87                 ifm = (struct if_msg *)gl->data;
88                 if (g_strcmp0(ifm->ifname, iface) == 0)
89                         return ifm;
90         }
91         return NULL;
92 }
93
94 static void
95 free_if_ap(struct if_ap *ifa)
96 {
97         g_free(ifa->ifname);
98         g_free(ifa->bssid);
99         g_free(ifa->flags);
100         g_free(ifa->ssid);
101         g_free(ifa);
102 }
103
104 static void
105 free_if_msg(struct if_msg *ifm)
106 {
107         GSList *gl;
108
109         g_free(ifm->ifname);
110         g_free(ifm->reason);
111         g_free(ifm->ssid);
112         for (gl = ifm->scan_results; gl; gl = gl->next)
113                 free_if_ap((struct if_ap *)gl->data);
114         g_slist_free(ifm->scan_results);
115         g_free(ifm);
116 }
117
118 static void
119 error_exit(const char *msg, GError *error)
120 {
121         GtkWidget *dialog;
122
123         if (error) {
124                 g_critical("%s: %s", msg, error->message);
125                 dialog = gtk_message_dialog_new(NULL, 0,
126                     GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
127                     "%s: %s", msg, error->message);
128         } else {
129                 g_critical("%s", msg);
130                 dialog = gtk_message_dialog_new(NULL, 0,
131                     GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", msg);
132         }
133         gtk_dialog_run(GTK_DIALOG(dialog));
134         gtk_widget_destroy(dialog);
135         if (gtk_main_level())
136                 gtk_main_quit();
137         else
138                 exit(EXIT_FAILURE);
139 }
140
141 static GSList *
142 get_scan_results(struct if_msg *ifm)
143 {
144         GType otype;
145         GError *error;
146         GPtrArray *array;
147         GHashTable *config;
148         GSList *list = NULL;
149         struct if_ap *ifa;
150         guint i;
151         GValue *val;
152
153         otype = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
154         otype = dbus_g_type_get_collection("GPtrArray", otype);
155
156         error = NULL;
157         if (!dbus_g_proxy_call(dbus, "ScanResults", &error,
158                 G_TYPE_STRING, ifm->ifname, G_TYPE_INVALID,
159                 otype, &array, G_TYPE_INVALID))
160                 error_exit(_("ScanResults"), error);
161
162         for (i = 0; i < array->len; i++) {
163                 config = g_ptr_array_index(array, i);
164                 val = g_hash_table_lookup(config, "BSSID");
165                 if (val == NULL)
166                         continue;
167                 ifa = g_malloc0(sizeof(*ifa));
168                 ifa->ifname = g_strdup(ifm->ifname);
169                 ifa->bssid = g_strdup(g_value_get_string(val));
170                 val = g_hash_table_lookup(config, "Frequency");
171                 if (val)
172                         ifa->frequency = g_value_get_int(val);
173                 val = g_hash_table_lookup(config, "Quality");
174                 if (val)
175                         ifa->quality = g_value_get_int(val);
176                 val = g_hash_table_lookup(config, "Noise");
177                 if (val)
178                         ifa->noise = g_value_get_int(val);
179                 val = g_hash_table_lookup(config, "Level");
180                 if (val)
181                         ifa->level = g_value_get_int(val);
182                 val = g_hash_table_lookup(config, "Flags");
183                 if (val)
184                         ifa->flags = g_strdup(g_value_get_string(val));
185                 val = g_hash_table_lookup(config, "SSID");
186                 if (val)
187                         ifa->ssid = g_strdup(g_value_get_string(val));
188                 list = g_slist_append(list, ifa);
189         }
190         return list;
191 }
192
193 static struct if_msg *
194 make_if_msg(GHashTable *config)
195 {
196         GValue *val;
197         struct if_msg *ifm;
198
199         val = g_hash_table_lookup(config, "Interface");
200         if (val == NULL)
201                 return NULL;
202         ifm = g_malloc0(sizeof(*ifm));
203         ifm->ifname = g_strdup(g_value_get_string(val));
204         val = g_hash_table_lookup(config, "Reason");
205         if (val)
206                 ifm->reason = g_strdup(g_value_get_string(val));
207         val = g_hash_table_lookup(config, "Wireless");
208         if (val)
209                 ifm->wireless = g_value_get_boolean(val);
210         if (ifm->wireless) {
211                 val = g_hash_table_lookup(config, "SSID");
212                 if (val)
213                         ifm->ssid = g_strdup(g_value_get_string(val));
214         }
215         val = g_hash_table_lookup(config, "IPAddress");
216         if (val)
217                 ifm->ip.s_addr = g_value_get_uint(val);
218         val = g_hash_table_lookup(config, "SubnetCIDR");
219         if (val)
220                 ifm->cidr = g_value_get_uchar(val);
221         val = g_hash_table_lookup(config, "InterfaceOrder");
222         if (val) {
223                 g_strfreev(interface_order);
224                 interface_order = g_strsplit(g_value_get_string(val), " ", 0);
225         }
226         return ifm;
227 }
228
229 static gboolean
230 if_up(const struct if_msg *ifm)
231 {
232         const char *const *r;
233
234         for (r = up_reasons; *r; r++)
235                 if (g_strcmp0(*r, ifm->reason) == 0)
236                         return TRUE;
237         return FALSE;
238 }
239
240 static char *
241 print_if_msg(const struct if_msg *ifm)
242 {
243         char *msg, *p;
244         const char *reason = NULL;
245         size_t len;
246         gboolean showip, showssid;
247     
248         showip = TRUE;
249         showssid = FALSE;
250         if (if_up(ifm))
251                 reason = N_("Acquired address");
252         else {
253                 if (g_strcmp0(ifm->reason, "EXPIRE") == 0)
254                         reason = N_("Failed to renew");
255                 else if (g_strcmp0(ifm->reason, "CARRIER") == 0) {
256                         if (ifm->wireless) {
257                                 reason = N_("Asssociated with");
258                                 if (ifm->ssid != NULL)
259                                         showssid = TRUE;
260                         } else
261                                 reason = N_("Cable plugged in");
262                         showip = FALSE;
263                 } else if (g_strcmp0(ifm->reason, "NOCARRIER") == 0) {
264                         if (ifm->wireless) {
265                                 if (ifm->ssid != NULL || ifm->ip.s_addr != 0) {
266                                         reason = N_("Disassociated from");
267                                         showssid = TRUE;
268                                 } else
269                                         reason = N_("Not associated");
270                         } else
271                                 reason = N_("Cable unplugged");
272                         showip = FALSE;
273                 }
274         }
275         if (reason == NULL)
276                 reason = ifm->reason;
277         
278         len = strlen(ifm->ifname) + 3;
279         len += strlen(reason) + 1;
280         if (ifm->ip.s_addr != 0) {
281                 len += 16; /* 000. * 4 */
282                 if (ifm->cidr != 0)
283                         len += 3; /* /32 */
284         }
285         if (showssid)
286                 len += strlen(ifm->ssid) + 1;
287         msg = p = g_malloc(len);
288         p += g_snprintf(msg, len, "%s: %s", ifm->ifname, reason);
289         if (showssid)
290                 p += g_snprintf(p, len - (p - msg), " %s", ifm->ssid);
291         if (ifm->ip.s_addr != 0 && showip) {
292                 p += g_snprintf(p, len - (p - msg), " %s", inet_ntoa(ifm->ip));
293                 if (ifm->cidr != 0)
294                         g_snprintf(p, len - (p - msg), "/%d", ifm->cidr);
295         }
296         return msg;
297 }
298
299 static gint
300 if_msg_comparer(gconstpointer a, gconstpointer b)
301 {
302         const struct if_msg *ifa, *ifb;
303         const char *const *order;
304
305         ifa = (const struct if_msg *)a;
306         ifb = (const struct if_msg *)b;
307         for (order = (const char *const *)interface_order; *order; order++) {
308                 if (g_strcmp0(*order, ifa->ifname) == 0)
309                         return -1;
310                 if (g_strcmp0(*order, ifb->ifname) == 0)
311                         return 1;
312         }
313         return 0;
314 }
315
316 static gboolean
317 animate_carrier(_unused gpointer data)
318 {
319         const char *icon;
320         
321         if (ani_timer == 0)
322                 return FALSE;
323
324         switch(ani_counter++) {
325         case 0:
326                 icon = "network-transmit";
327                 break;
328         case 1:
329                 icon = "network-receive";
330                 break;
331         default:
332                 icon = "network-idle";
333                 ani_counter = 0;
334                 break;
335         }
336         gtk_status_icon_set_from_icon_name(status_icon, icon);
337         return TRUE;
338 }
339
340 static gboolean
341 animate_online(_unused gpointer data)
342 {
343         const char *icon;
344         
345         if (ani_timer == 0)
346                 return FALSE;
347
348         if (ani_counter++ > 6) {
349                 ani_timer = 0;
350                 ani_counter = 0;
351                 return FALSE;
352         }
353
354         if (ani_counter % 2 == 0)
355                 icon = "network-idle";
356         else
357                 icon = "network-transmit-receive";
358         gtk_status_icon_set_from_icon_name(status_icon, icon);
359         return TRUE;
360 }
361
362 static void
363 update_online(void)
364 {
365         gboolean ison, iscarrier;
366         char *msg, *msgs, *tmp;
367         const GSList *gl;
368         const struct if_msg *ifm;
369
370         ison = iscarrier = FALSE;
371         msgs = NULL;
372         for (gl = interfaces; gl; gl = gl->next) {
373                 ifm = (const struct if_msg *)gl->data;
374                 if (if_up(ifm))
375                         ison = iscarrier = TRUE;
376                 if (!iscarrier && g_strcmp0(ifm->reason, "CARRIER") == 0)
377                         iscarrier = TRUE;
378                 msg = print_if_msg(ifm);
379                 if (msgs) {
380                         tmp = g_strconcat(msgs, "\n", msg, NULL);
381                         g_free(msgs);
382                         g_free(msg);
383                         msgs = tmp;
384                 } else
385                         msgs = msg;
386         }
387
388         if (online != ison || carrier != iscarrier) {
389                 online = ison;
390                 if (ani_timer != 0) {
391                         g_source_remove(ani_timer);
392                         ani_timer = 0;
393                         ani_counter = 0;
394                 }
395                 if (ison) {
396                         animate_online(NULL);
397                         ani_timer = g_timeout_add(300, animate_online, NULL);
398                 } else if (iscarrier) {
399                         animate_carrier(NULL);
400                         ani_timer = g_timeout_add(500, animate_carrier, NULL);
401                 } else {
402                         gtk_status_icon_set_from_icon_name(status_icon,
403                             "network-offline");
404                 }
405         }
406         gtk_status_icon_set_tooltip(status_icon, msgs);
407         g_free(msgs);
408 }
409
410 void
411 notify_close(void)
412 {
413         if (nn != NULL)
414                 notify_notification_close(nn, NULL);
415 }
416
417 static void
418 notify_closed(void)
419 {
420         nn = NULL;
421 }
422
423 static void
424 notify(const char *title, const char *msg, const char *icon)
425 {
426         char **msgs, **m;
427
428         msgs = g_strsplit(msg, "\n", 0);
429         for (m = msgs; *m; m++)
430                 g_message("%s", *m);
431         g_strfreev(msgs);
432         if (nn != NULL)
433                 notify_notification_close(nn, NULL);
434         if (gtk_status_icon_get_visible(status_icon))
435                 nn = notify_notification_new_with_status_icon(title,
436                     msg, icon, status_icon);
437         else
438                 nn = notify_notification_new(title, msg, icon, NULL);
439         notify_notification_set_timeout(nn, 5000);
440         g_signal_connect(nn, "closed", G_CALLBACK(notify_closed), NULL);
441         notify_notification_show(nn, NULL);
442 }
443
444 static void
445 dhcpcd_event(_unused DBusGProxy *proxy, GHashTable *config, _unused void *data)
446 {
447         struct if_msg *ifm, *ifp;
448         gboolean rem;
449         GSList *gl;
450         char *msg, *title;
451         const char *act, *net;
452         const char *const *r;
453         in_addr_t ipn;
454
455         ifm = make_if_msg(config);
456         if (ifm == NULL)
457                 return;
458
459         rem = ignore_if_msg(ifm);
460         ifp = NULL;
461         for (gl = interfaces; gl; gl = gl->next) {
462                 ifp = (struct if_msg *)gl->data;
463                 if (g_strcmp0(ifp->ifname, ifm->ifname) == 0) {
464                         ifm->scan_results = ifp->scan_results;
465                         ifp->scan_results = NULL;
466                         free_if_msg(ifp);
467                         if (rem)
468                                 interfaces =
469                                         g_slist_delete_link(interfaces, gl);
470                         else
471                                 gl->data = ifm;
472                         break;
473                 }
474         }
475         if (ifp == NULL && !rem)
476                 interfaces = g_slist_prepend(interfaces, ifm);
477         interfaces = g_slist_sort(interfaces, if_msg_comparer);
478         update_online();
479
480         /* We should ignore renew and stop so we don't annoy the user */
481         if (g_strcmp0(ifm->reason, "RENEW") == 0 ||
482             g_strcmp0(ifm->reason, "STOP") == 0)
483                 return;
484
485         msg = print_if_msg(ifm);
486         title = NULL;
487         if (if_up(ifm))
488                 act = N_("Connected to ");
489         else
490                 act = NULL;
491         for (r = down_reasons; *r; r++) {
492                 if (g_strcmp0(*r, ifm->reason) == 0) {
493                         act = N_("Disconnected from ");
494                         break;
495                 }
496         }
497         if (act && ifm->ip.s_addr) {
498                 ipn = htonl(ifm->ip.s_addr);
499                 if (IN_LINKLOCAL(ipn))
500                         net = N_("private network");
501                 else if (IN_PRIVATE(ipn))
502                         net = N_("LAN");
503                 else
504                         net = N_("internet");
505                 title = g_strconcat(act, net, NULL);
506         }
507
508         if (title) {
509                 notify(title, msg, GTK_STOCK_NETWORK);
510                 g_free(title);
511         } else
512                 notify(N_("Interface event"), msg, GTK_STOCK_NETWORK);
513         g_free(msg);
514 }
515
516 static void
517 foreach_make_ifm(_unused gpointer key, gpointer value, _unused gpointer data)
518 {
519         struct if_msg *ifm;
520
521         ifm = make_if_msg((GHashTable *)value);
522         if (ignore_if_msg(ifm))
523                 g_free(ifm);
524         else if (ifm)
525                 interfaces = g_slist_prepend(interfaces, ifm);
526 }
527
528 static void
529 dhcpcd_get_interfaces()
530 {
531         GHashTable *ifs;
532         GError *error = NULL;
533         GType otype;
534         GSList *gl, *gsl;
535         GPtrArray *array;
536         struct if_msg *ifm;
537
538         otype = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
539         otype = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, otype);
540         if (!dbus_g_proxy_call(dbus, "GetInterfaces", &error,
541                 G_TYPE_INVALID,
542                 otype, &ifs, G_TYPE_INVALID))
543                 error_exit("GetInterfaces", error);
544         g_hash_table_foreach(ifs, foreach_make_ifm, NULL);
545         g_hash_table_unref(ifs);
546
547         /* Each interface config only remembers the last order when
548          * that interface was configured, so get the real order now. */
549         g_strfreev(interface_order);
550         interface_order = NULL;
551         if (!dbus_g_proxy_call(dbus, "ListInterfaces", &error,
552                 G_TYPE_INVALID,
553                 G_TYPE_STRV, &interface_order, G_TYPE_INVALID))
554                 error_exit("ListInterfaces", error);
555         interfaces = g_slist_sort(interfaces, if_msg_comparer);
556
557         otype = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
558         otype = dbus_g_type_get_collection("GPtrArray", otype);
559         for (gl = interfaces; gl; gl = gl->next) {
560                 ifm = (struct if_msg *)gl->data;
561                 if (!ifm->wireless)
562                         continue;
563                 if (!dbus_g_proxy_call(dbus, "ScanResults", &error,
564                         G_TYPE_STRING, ifm->ifname, G_TYPE_INVALID,
565                         otype, &array, G_TYPE_INVALID)) 
566                 {
567                         g_message("ScanResults: %s", error->message);
568                         g_clear_error(&error);
569                         continue;
570                 }
571                 for (gsl = ifm->scan_results; gsl; gsl = gsl->next)
572                         g_free(gsl->data);
573                 g_slist_free(ifm->scan_results);
574                 ifm->scan_results = get_scan_results(ifm);
575         }
576
577         update_online();
578 }
579
580 static void
581 check_status(const char *status)
582 {
583         static char *last = NULL;
584         GSList *gl;
585         char *version;
586         const char *msg;
587         gboolean refresh;
588         GError *error = NULL;
589
590         g_message("Status changed to %s", status);
591         if (g_strcmp0(status, "down") == 0) {
592                 for (gl = interfaces; gl; gl = gl->next)
593                         free_if_msg((struct if_msg *)gl->data);
594                 g_slist_free(interfaces);
595                 interfaces = NULL;
596                 update_online();
597                 msg = N_(last ?
598                     "Connection to dhcpcd lost" : "dhcpcd not running");
599                 gtk_status_icon_set_tooltip(status_icon, msg);
600                 notify(_("No network"), msg, GTK_STOCK_NETWORK);
601         }
602
603         refresh = FALSE;
604         if (last == NULL) {
605                 if (g_strcmp0(status, "down") != 0)
606                         refresh = TRUE;
607         } else {
608                 if (g_strcmp0(status, last) == 0)
609                         return;
610                 if (g_strcmp0(last, "down") == 0)
611                         refresh = TRUE;
612                 g_free(last);
613         }
614         last = g_strdup(status);
615
616         if (!refresh)
617                 return;
618         if (!dbus_g_proxy_call(dbus, "GetDhcpcdVersion", &error,
619                 G_TYPE_INVALID,
620                 G_TYPE_STRING, &version, G_TYPE_INVALID))
621                 error_exit(_("GetDhcpcdVersion"), error);
622         g_message(_("Connected to %s-%s"), "dhcpcd", version);
623         g_free(version);
624         dhcpcd_get_interfaces();
625 }
626
627 static void
628 dhcpcd_status(_unused DBusGProxy *proxy, const char *status,
629     _unused void *data)
630 {
631         check_status(status);
632 }
633
634 static void
635 dhcpcd_scan_results(_unused DBusGProxy *proxy, const char *iface,
636     _unused void *data)
637 {
638         struct if_msg *ifm;
639         struct if_ap *ifa, *ifa2;
640         GSList *gl, *aps, *l;
641         char *txt, *ntxt;
642
643         ifm = find_if_msg(iface);
644         if (ifm == NULL)
645                 return;
646         g_message(_("%s: Received scan results"), ifm->ifname);
647         aps = get_scan_results(ifm);
648         txt = NULL;
649         for (gl = aps; gl; gl = gl->next) {
650                 ifa = (struct if_ap *)gl->data;
651                 for (l = ifm->scan_results; l; l = l->next) {
652                         ifa2 = (struct if_ap *)l->data;
653                         if (g_strcmp0(ifa->ssid, ifa2->ssid) == 0)
654                                 break;
655                 }
656                 if (l == NULL) {
657                         if (txt == NULL)
658                                 txt = g_strdup(ifa->ssid);
659                         else {
660                                 ntxt = g_strconcat(txt, "\n", ifa->ssid, NULL);
661                                 g_free(txt);
662                                 txt = ntxt;
663                         }
664                 }
665         }
666         for (gl = ifm->scan_results; gl; gl = gl->next)
667                 free_if_ap((struct if_ap *)gl->data);
668         g_slist_free(ifm->scan_results);
669         ifm->scan_results = aps;
670         if (txt != NULL) {
671                 notify(N_("Found new AP"), txt, GTK_STOCK_NETWORK);
672                 g_free(txt);
673         }
674 }
675
676 int
677 main(int argc, char *argv[])
678 {
679         DBusGConnection *bus;
680         GError *error = NULL;
681         char *version = NULL;
682         GType otype;
683         int tries = 5;
684                 
685         setlocale(LC_ALL, "");
686         bindtextdomain(PACKAGE, NULL);
687         bind_textdomain_codeset(PACKAGE, "UTF-8");
688         textdomain(PACKAGE); 
689
690         gtk_init(&argc, &argv);
691         g_set_application_name("dhcpcd Monitor");
692         status_icon = gtk_status_icon_new_from_icon_name("network-offline");
693         if (status_icon == NULL)
694                 status_icon =
695                         gtk_status_icon_new_from_stock(GTK_STOCK_DISCONNECT);
696         //network_offline = gtk_status_icon_get_pixbuf(status_icon);
697         
698         gtk_status_icon_set_tooltip(status_icon,
699             _("Connecting to dhcpcd ..."));
700         gtk_status_icon_set_visible(status_icon, TRUE);
701
702         notify_init(PACKAGE);
703
704         g_message(_("Connecting to dbus ..."));
705         bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
706         if (bus == NULL || error != NULL)
707                 error_exit(_("Could not connect to system bus"), error);
708         dbus = dbus_g_proxy_new_for_name(bus,
709             DHCPCD_SERVICE,
710             DHCPCD_PATH,
711             DHCPCD_SERVICE);
712
713         g_message(_("Connecting to dhcpcd-dbus ..."));
714         while (--tries > 0) {
715                 g_clear_error(&error);
716                 if (dbus_g_proxy_call_with_timeout(dbus, "GetVersion", 500,
717                         &error, G_TYPE_INVALID,
718                         G_TYPE_STRING, &version, G_TYPE_INVALID))
719                         break;
720         }
721         if (tries == 0)
722                 error_exit(_("GetVersion"), error);
723         g_message(_("Connected to %s-%s"), "dhcpcd-dbus", version);
724         g_free(version);
725
726         gtk_status_icon_set_tooltip(status_icon, _("Triggering dhcpcd ..."));
727         online = FALSE;
728         menu_init(status_icon);
729
730         if (!dbus_g_proxy_call(dbus, "GetStatus", &error,
731                 G_TYPE_INVALID,
732                 G_TYPE_STRING, &version, G_TYPE_INVALID))
733                 error_exit(_("GetStatus"), error);
734         check_status(version);
735         g_free(version);
736
737         otype = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
738         dbus_g_proxy_add_signal(dbus, "Event",
739             otype, G_TYPE_INVALID);
740         dbus_g_proxy_connect_signal(dbus, "Event",
741             G_CALLBACK(dhcpcd_event), bus, NULL);
742         dbus_g_proxy_add_signal(dbus, "StatusChanged",
743             G_TYPE_STRING, G_TYPE_INVALID);
744         dbus_g_proxy_connect_signal(dbus, "StatusChanged",
745             G_CALLBACK(dhcpcd_status), bus, NULL);
746         dbus_g_proxy_add_signal(dbus, "ScanResults",
747             G_TYPE_STRING, G_TYPE_INVALID);
748         dbus_g_proxy_connect_signal(dbus, "ScanResults",
749             G_CALLBACK(dhcpcd_scan_results), bus, NULL);
750
751         gtk_main();
752         return 0;
753 }