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