Use a more KNF style.
[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 GList *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         GList *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,
126                     0,
127                     GTK_MESSAGE_ERROR,
128                     GTK_BUTTONS_CLOSE,
129                     "%s: %s",
130                     msg,
131                     error->message);
132         } else {
133                 g_critical("%s", msg);
134                 dialog = gtk_message_dialog_new(NULL,
135                     0,
136                     GTK_MESSAGE_ERROR,
137                     GTK_BUTTONS_CLOSE,
138                     "%s",
139                     msg);
140         }
141         gtk_dialog_run(GTK_DIALOG(dialog));
142         gtk_widget_destroy(dialog);
143         if (gtk_main_level())
144                 gtk_main_quit();
145         else
146                 exit(EXIT_FAILURE);
147 }
148
149 static GSList *
150 get_scan_results(struct if_msg *ifm)
151 {
152         GType otype;
153         GError *error;
154         GPtrArray *array;
155         GHashTable *config;
156         GSList *list = NULL;
157         struct if_ap *ifa;
158         guint i;
159         GValue *val;
160
161         otype = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
162         otype = dbus_g_type_get_collection("GPtrArray", otype);
163
164         if (!dbus_g_proxy_call(dbus, "ScanResults", &error,
165                 G_TYPE_STRING, ifm->ifname, G_TYPE_INVALID,
166                 otype, &array, G_TYPE_INVALID))
167                 error_exit(_("ScanResults"), error);
168
169         for (i = 0; i < array->len; i++) {
170                 config = g_ptr_array_index(array, i);
171                 val = g_hash_table_lookup(config, "BSSID");
172                 if (val == NULL)
173                         continue;
174                 ifa = g_malloc0(sizeof(*ifa));
175                 ifa->ifname = g_strdup(ifm->ifname);
176                 ifa->bssid = g_strdup(g_value_get_string(val));
177                 val = g_hash_table_lookup(config, "Frequency");
178                 if (val)
179                         ifa->frequency = g_value_get_int(val);
180                 val = g_hash_table_lookup(config, "Quality");
181                 if (val)
182                         ifa->quality = g_value_get_int(val);
183                 val = g_hash_table_lookup(config, "Noise");
184                 if (val)
185                         ifa->noise = g_value_get_int(val);
186                 val = g_hash_table_lookup(config, "Level");
187                 if (val)
188                         ifa->level = g_value_get_int(val);
189                 val = g_hash_table_lookup(config, "Flags");
190                 if (val)
191                         ifa->flags = g_strdup(g_value_get_string(val));
192                 val = g_hash_table_lookup(config, "SSID");
193                 if (val)
194                         ifa->ssid = g_strdup(g_value_get_string(val));
195                 list = g_slist_append(list, ifa);
196         }
197         return list;
198 }
199
200 static struct if_msg *
201 make_if_msg(GHashTable *config)
202 {
203         GValue *val;
204         struct if_msg *ifm;
205
206         val = g_hash_table_lookup(config, "Interface");
207         if (val == NULL)
208                 return NULL;
209         ifm = g_malloc0(sizeof(*ifm));
210         ifm->ifname = g_strdup(g_value_get_string(val));
211         val = g_hash_table_lookup(config, "Reason");
212         if (val)
213                 ifm->reason = g_strdup(g_value_get_string(val));
214         val = g_hash_table_lookup(config, "Wireless");
215         if (val)
216                 ifm->wireless = g_value_get_boolean(val);
217         if (ifm->wireless) {
218                 val = g_hash_table_lookup(config, "SSID");
219                 if (val)
220                         ifm->ssid = g_strdup(g_value_get_string(val));
221         }
222         val = g_hash_table_lookup(config, "IPAddress");
223         if (val)
224                 ifm->ip.s_addr = g_value_get_uint(val);
225         val = g_hash_table_lookup(config, "SubnetCIDR");
226         if (val)
227                 ifm->cidr = g_value_get_uchar(val);
228         val = g_hash_table_lookup(config, "InterfaceOrder");
229         if (val) {
230                 g_strfreev(interface_order);
231                 interface_order = g_strsplit(g_value_get_string(val), " ", 0);
232         }
233         return ifm;
234 }
235
236 static gboolean
237 if_up(const struct if_msg *ifm)
238 {
239         const char *const *r;
240
241         for (r = up_reasons; *r; r++)
242                 if (g_strcmp0(*r, ifm->reason) == 0)
243                         return TRUE;
244         return FALSE;
245 }
246
247 static char *
248 print_if_msg(const struct if_msg *ifm)
249 {
250         char *msg, *p;
251         const char *reason = NULL;
252         size_t len;
253         gboolean showip, showssid;
254     
255         showip = TRUE;
256         showssid = FALSE;
257         if (if_up(ifm))
258                 reason = N_("Acquired address");
259         else {
260                 if (g_strcmp0(ifm->reason, "EXPIRE") == 0)
261                         reason = N_("Failed to renew");
262                 else if (g_strcmp0(ifm->reason, "CARRIER") == 0) {
263                         if (ifm->wireless) {
264                                 reason = N_("Asssociated with");
265                                 if (ifm->ssid != NULL)
266                                         showssid = TRUE;
267                         } else
268                                 reason = N_("Cable plugged in");
269                         showip = FALSE;
270                 } else if (g_strcmp0(ifm->reason, "NOCARRIER") == 0) {
271                         if (ifm->wireless) {
272                                 if (ifm->ssid != NULL || ifm->ip.s_addr != 0) {
273                                         reason = N_("Disassociated from");
274                                         showssid = TRUE;
275                                 } else
276                                         reason = N_("Not associated");
277                         } else
278                                 reason = N_("Cable unplugged");
279                         showip = FALSE;
280                 }
281         }
282         if (reason == NULL)
283                 reason = ifm->reason;
284         
285         len = strlen(ifm->ifname) + 3;
286         len += strlen(reason) + 1;
287         if (ifm->ip.s_addr != 0) {
288                 len += 16; /* 000. * 4 */
289                 if (ifm->cidr != 0)
290                         len += 3; /* /32 */
291         }
292         if (showssid)
293                 len += strlen(ifm->ssid) + 1;
294         msg = p = g_malloc(len);
295         p += g_snprintf(msg, len, "%s: %s", ifm->ifname, reason);
296         if (showssid)
297                 p += g_snprintf(p, len - (p - msg), " %s", ifm->ssid);
298         if (ifm->ip.s_addr != 0 && showip) {
299                 p += g_snprintf(p, len - (p - msg), " %s", inet_ntoa(ifm->ip));
300                 if (ifm->cidr != 0)
301                         g_snprintf(p, len - (p - msg), "/%d", ifm->cidr);
302         }
303         return msg;
304 }
305
306 static gint
307 if_msg_comparer(gconstpointer a, gconstpointer b)
308 {
309         const struct if_msg *ifa, *ifb;
310         const char *const *order;
311
312         ifa = (const struct if_msg *)a;
313         ifb = (const struct if_msg *)b;
314         for (order = (const char *const *)interface_order; *order; order++) {
315                 if (g_strcmp0(*order, ifa->ifname) == 0)
316                         return -1;
317                 if (g_strcmp0(*order, ifb->ifname) == 0)
318                         return 1;
319         }
320         return 0;
321 }
322
323 static gboolean
324 animate_carrier(_unused gpointer data)
325 {
326         if (ani_timer == 0)
327                 return FALSE;
328
329         switch(ani_counter++) {
330         case 0:
331                 gtk_status_icon_set_from_icon_name(status_icon, "network-transmit");
332                 break;
333         case 1:
334                 gtk_status_icon_set_from_icon_name(status_icon, "network-receive");
335                 break;
336         default:
337                 gtk_status_icon_set_from_icon_name(status_icon, "network-idle");
338                 ani_counter = 0;
339                 break;
340         }
341         return TRUE;
342 }
343
344 static gboolean
345 animate_online(_unused gpointer data)
346 {
347         if (ani_timer == 0)
348                 return FALSE;
349
350         if (ani_counter++ > 6) {
351                 ani_timer = 0;
352                 ani_counter = 0;
353                 return FALSE;
354         }
355
356         if (ani_counter % 2 == 0)
357                 gtk_status_icon_set_from_icon_name(status_icon, "network-idle");
358         else
359                 gtk_status_icon_set_from_icon_name(status_icon, "network-transmit-receive");
360         return TRUE;
361 }
362
363 static void
364 update_online(void)
365 {
366         gboolean ison, iscarrier;
367         char *msg, *msgs, *tmp;
368         const GList *gl;
369         const struct if_msg *ifm;
370
371         ison = iscarrier = FALSE;
372         msgs = NULL;
373         for (gl = interfaces; gl; gl = gl->next) {
374                 ifm = (const struct if_msg *)gl->data;
375                 if (if_up(ifm))
376                         ison = iscarrier = TRUE;
377                 if (!iscarrier && g_strcmp0(ifm->reason, "CARRIER") == 0)
378                         iscarrier = TRUE;
379                 msg = print_if_msg(ifm);
380                 if (msgs) {
381                         tmp = g_strconcat(msgs, "\n", msg, NULL);
382                         g_free(msgs);
383                         g_free(msg);
384                         msgs = tmp;
385                 } else
386                         msgs = msg;
387         }
388
389         if (online != ison || carrier != iscarrier) {
390                 online = ison;
391                 if (ani_timer != 0) {
392                         g_source_remove(ani_timer);
393                         ani_timer = 0;
394                         ani_counter = 0;
395                 }
396                 if (ison) {
397                         animate_online(NULL);
398                         ani_timer = g_timeout_add(300, animate_online, NULL);
399                 } else if (iscarrier) {
400                         animate_carrier(NULL);
401                         ani_timer = g_timeout_add(500, animate_carrier, NULL);
402                 } else {
403                         gtk_status_icon_set_from_icon_name(status_icon,
404                             "network-offline");
405                 }
406         }
407         gtk_status_icon_set_tooltip(status_icon, msgs);
408         g_free(msgs);
409 }
410
411 void
412 notify_close(void)
413 {
414         if (nn != NULL)
415                 notify_notification_close(nn, NULL);
416 }
417
418 static void
419 notify_closed(void)
420 {
421         nn = NULL;
422 }
423
424 static void
425 notify(const char *title, const char *msg, const char *icon)
426 {
427         char **msgs, **m;
428
429         msgs = g_strsplit(msg, "\n", 0);
430         for (m = msgs; *m; m++)
431                 g_message("%s", *m);
432         g_strfreev(msgs);
433         if (nn != NULL)
434                 notify_notification_close(nn, NULL);
435         if (gtk_status_icon_get_visible(status_icon))
436                 nn = notify_notification_new_with_status_icon(title,
437                     msg,
438                     icon,
439                     status_icon);
440         else
441                 nn = notify_notification_new(title, msg, icon, NULL);
442         notify_notification_set_timeout(nn, 5000);
443         g_signal_connect(nn, "closed", G_CALLBACK(notify_closed), NULL);
444         notify_notification_show(nn, NULL);
445 }
446
447 static void
448 dhcpcd_event(_unused DBusGProxy *proxy, GHashTable *config, _unused void *data)
449 {
450         struct if_msg *ifm, *ifp;
451         gboolean rem;
452         GList *gl;
453         char *msg, *title;
454         const char *act, *net;
455         const char *const *r;
456         in_addr_t ipn;
457
458         ifm = make_if_msg(config);
459         if (ifm == NULL)
460                 return;
461
462         rem = ignore_if_msg(ifm);
463         ifp = NULL;
464         for (gl = interfaces; gl; gl = gl->next) {
465                 ifp = (struct if_msg *)gl->data;
466                 if (g_strcmp0(ifp->ifname, ifm->ifname) == 0) {
467                         ifm->scan_results = ifp->scan_results;
468                         ifp->scan_results = NULL;
469                         free_if_msg(ifp);
470                         if (rem)
471                                 interfaces = g_list_delete_link(interfaces, gl);
472                         else
473                                 gl->data = ifm;
474                         break;
475                 }
476         }
477         if (ifp == NULL && !rem)
478                 interfaces = g_list_prepend(interfaces, ifm);
479         interfaces = g_list_sort(interfaces, if_msg_comparer);
480         update_online();
481
482         /* We should ignore renew and stop so we don't annoy the user */
483         if (g_strcmp0(ifm->reason, "RENEW") == 0 ||
484             g_strcmp0(ifm->reason, "STOP") == 0)
485                 return;
486
487         msg = print_if_msg(ifm);
488         title = NULL;
489         if (if_up(ifm))
490                 act = N_("Connected to ");
491         else
492                 act = NULL;
493         for (r = down_reasons; *r; r++) {
494                 if (g_strcmp0(*r, ifm->reason) == 0) {
495                         act = N_("Disconnected from ");
496                         break;
497                 }
498         }
499         if (act && ifm->ip.s_addr) {
500                 ipn = htonl(ifm->ip.s_addr);
501                 if (IN_LINKLOCAL(ipn))
502                         net = N_("private network");
503                 else if (IN_PRIVATE(ipn))
504                         net = N_("LAN");
505                 else
506                         net = N_("internet");
507                 title = g_strconcat(act, net, NULL);
508         }
509
510         if (title) {
511                 notify(title, msg, GTK_STOCK_NETWORK);
512                 g_free(title);
513         } else
514                 notify(N_("Interface event"), msg, GTK_STOCK_NETWORK);
515         g_free(msg);
516 }
517
518 static void
519 foreach_make_ifm(_unused gpointer key, gpointer value, _unused gpointer data)
520 {
521         struct if_msg *ifm;
522
523         ifm = make_if_msg((GHashTable *)value);
524         if (ignore_if_msg(ifm))
525                 g_free(ifm);
526         else if (ifm)
527                 interfaces = g_list_prepend(interfaces, ifm);
528 }
529
530 static void
531 dhcpcd_get_interfaces()
532 {
533         GHashTable *ifs;
534         GError *error = NULL;
535         GType otype;
536         GList *gl;
537         GSList *gsl;
538         GPtrArray *array;
539         struct if_msg *ifm;
540
541         otype = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
542         otype = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, otype);
543         if (!dbus_g_proxy_call(dbus, "GetInterfaces", &error,
544                 G_TYPE_INVALID,
545                 otype, &ifs, G_TYPE_INVALID))
546                 error_exit("GetInterfaces", error);
547         g_hash_table_foreach(ifs, foreach_make_ifm, NULL);
548         g_hash_table_unref(ifs);
549
550         /* Each interface config only remembers the last order when
551          * that interface was configured, so get the real order now. */
552         g_strfreev(interface_order);
553         interface_order = NULL;
554         if (!dbus_g_proxy_call(dbus, "ListInterfaces", &error,
555                 G_TYPE_INVALID,
556                 G_TYPE_STRV, &interface_order, G_TYPE_INVALID))
557                 error_exit("ListInterfaces", error);
558         interfaces = g_list_sort(interfaces, if_msg_comparer);
559
560         otype = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
561         otype = dbus_g_type_get_collection("GPtrArray", otype);
562         for (gl = interfaces; gl; gl = gl->next) {
563                 ifm = (struct if_msg *)gl->data;
564                 if (!ifm->wireless)
565                         continue;
566                 if (!dbus_g_proxy_call(dbus, "ScanResults", &error,
567                         G_TYPE_STRING, ifm->ifname, G_TYPE_INVALID,
568                         otype, &array, G_TYPE_INVALID)) 
569                 {
570                         g_message("ScanResults: %s", error->message);
571                         g_clear_error(&error);
572                         continue;
573                 }
574                 for (gsl = ifm->scan_results; gsl; gsl = gsl->next)
575                         g_free(gsl->data);
576                 g_slist_free(ifm->scan_results);
577                 ifm->scan_results = get_scan_results(ifm);
578         }
579
580         update_online();
581 }
582
583 static void
584 check_status(const char *status)
585 {
586         static char *last = NULL;
587         GList *gl;
588         char *version;
589         const char *msg;
590         gboolean refresh;
591         GError *error = NULL;
592
593         g_message("Status changed to %s", status);
594         if (g_strcmp0(status, "down") == 0) {
595                 for (gl = interfaces; gl; gl = gl->next)
596                         free_if_msg((struct if_msg *)gl->data);
597                 g_list_free(interfaces);
598                 interfaces = NULL;
599                 update_online();
600                 msg = N_(last? "Connection to dhcpcd lost" : "dhcpcd not running");
601                 gtk_status_icon_set_tooltip(status_icon, msg);
602                 notify(_("No network"), msg, GTK_STOCK_NETWORK);
603         }
604
605         refresh = FALSE;
606         if (last == NULL) {
607                 if (g_strcmp0(status, "down") != 0)
608                         refresh = TRUE;
609         } else {
610                 if (g_strcmp0(status, last) == 0)
611                         return;
612                 if (g_strcmp0(last, "down") == 0)
613                         refresh = TRUE;
614                 g_free(last);
615         }
616         last = g_strdup(status);
617
618         if (!refresh)
619                 return;
620         if (!dbus_g_proxy_call(dbus, "GetDhcpcdVersion", &error,
621                 G_TYPE_INVALID,
622                 G_TYPE_STRING, &version, G_TYPE_INVALID))
623                 error_exit(_("GetDhcpcdVersion"), error);
624         g_message(_("Connected to %s-%s"), "dhcpcd", version);
625         g_free(version);
626         dhcpcd_get_interfaces();
627 }
628
629 static void
630 dhcpcd_status(_unused DBusGProxy *proxy, const char *status, _unused void *data)
631 {
632         check_status(status);
633 }
634
635 static void
636 dhcpcd_scan_results(_unused DBusGProxy *proxy, const char *iface, _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                 
686         setlocale(LC_ALL, "");
687         bindtextdomain(PACKAGE, NULL);
688         bind_textdomain_codeset(PACKAGE, "UTF-8");
689         textdomain(PACKAGE); 
690
691         gtk_init(&argc, &argv);
692         g_set_application_name("dhcpcd Monitor");
693         status_icon = gtk_status_icon_new_from_icon_name("network-offline");
694         if (status_icon == NULL)
695                 status_icon = 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, _("Connecting to dhcpcd ..."));
699         gtk_status_icon_set_visible(status_icon, TRUE);
700
701         notify_init(PACKAGE);
702
703         g_message(_("Connecting to dbus ..."));
704         bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
705         if (bus == NULL || error != NULL)
706                 error_exit(_("Could not connect to system bus"), error);
707         dbus = dbus_g_proxy_new_for_name(bus,
708             DHCPCD_SERVICE,
709             DHCPCD_PATH,
710             DHCPCD_SERVICE);
711
712         g_message(_("Connecting to dhcpcd-dbus ..."));
713         while (--tries > 0) {
714                 g_clear_error(&error);
715                 if (dbus_g_proxy_call_with_timeout(dbus,
716                         "GetVersion",
717                         500,
718                         &error,
719                         G_TYPE_INVALID,
720                         G_TYPE_STRING,
721                         &version,
722                         G_TYPE_INVALID))
723                         break;
724         }
725         if (tries == 0)
726                 error_exit(_("GetVersion"), error);
727         g_message(_("Connected to %s-%s"), "dhcpcd-dbus", version);
728         g_free(version);
729
730         gtk_status_icon_set_tooltip(status_icon, _("Triggering dhcpcd ..."));
731         online = FALSE;
732         menu_init(status_icon);
733
734         if (!dbus_g_proxy_call(dbus, "GetStatus", &error,
735                 G_TYPE_INVALID,
736                 G_TYPE_STRING, &version, G_TYPE_INVALID))
737                 error_exit(_("GetStatus"), error);
738         check_status(version);
739         g_free(version);
740
741         otype = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
742         dbus_g_proxy_add_signal(dbus, "Event",
743             otype, G_TYPE_INVALID);
744         dbus_g_proxy_connect_signal(dbus, "Event",
745             G_CALLBACK(dhcpcd_event),
746             bus, NULL);
747         dbus_g_proxy_add_signal(dbus, "StatusChanged",
748             G_TYPE_STRING, G_TYPE_INVALID);
749         dbus_g_proxy_connect_signal(dbus, "StatusChanged",
750             G_CALLBACK(dhcpcd_status),
751             bus, NULL);
752         dbus_g_proxy_add_signal(dbus, "ScanResults",
753             G_TYPE_STRING, G_TYPE_INVALID);
754         dbus_g_proxy_connect_signal(dbus, "ScanResults",
755             G_CALLBACK(dhcpcd_scan_results),
756             bus, NULL);
757
758         gtk_main();
759         return 0;
760 }