We finally work with PSK/WEPKEY_0 entry and we now save our config.
[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(char **buffer)
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         if (buffer)
409                 *buffer = msgs;
410         else
411                 g_free(msgs);
412 }
413
414 void
415 notify_close(void)
416 {
417         if (nn != NULL)
418                 notify_notification_close(nn, NULL);
419 }
420
421 static void
422 notify_closed(void)
423 {
424         nn = NULL;
425 }
426
427 static void
428 notify(const char *title, const char *msg, const char *icon)
429 {
430         char **msgs, **m;
431
432         msgs = g_strsplit(msg, "\n", 0);
433         for (m = msgs; *m; m++)
434                 g_message("%s", *m);
435         g_strfreev(msgs);
436         if (nn != NULL)
437                 notify_notification_close(nn, NULL);
438         if (gtk_status_icon_get_visible(status_icon))
439                 nn = notify_notification_new_with_status_icon(title,
440                                                               msg,
441                                                               icon,
442                                                               status_icon);
443         else
444                 nn = notify_notification_new(title, msg, icon, NULL);
445         notify_notification_set_timeout(nn, 5000);
446         g_signal_connect(nn, "closed", G_CALLBACK(notify_closed), NULL);
447         notify_notification_show(nn, NULL);
448 }
449
450 static void
451 dhcpcd_event(_unused DBusGProxy *proxy, GHashTable *config, _unused void *data)
452 {
453         struct if_msg *ifm, *ifp;
454         gboolean rem;
455         GList *gl;
456         char *msg, *title;
457         const char *act, *net;
458         const char *const *r;
459         in_addr_t ipn;
460
461         ifm = make_if_msg(config);
462         if (ifm == NULL)
463                 return;
464
465         rem = ignore_if_msg(ifm);
466         ifp = NULL;
467         for (gl = interfaces; gl; gl = gl->next) {
468                 ifp = (struct if_msg *)gl->data;
469                 if (g_strcmp0(ifp->ifname, ifm->ifname) == 0) {
470                         ifm->scan_results = ifp->scan_results;
471                         ifp->scan_results = NULL;
472                         free_if_msg(ifp);
473                         if (rem)
474                                 interfaces = g_list_delete_link(interfaces, gl);
475                         else
476                                 gl->data = ifm;
477                         break;
478                 }
479         }
480         if (ifp == NULL && !rem)
481                 interfaces = g_list_prepend(interfaces, ifm);
482         interfaces = g_list_sort(interfaces, if_msg_comparer);
483         update_online(NULL);
484
485         /* We should ignore renew and stop so we don't annoy the user */
486         if (g_strcmp0(ifm->reason, "RENEW") == 0 ||
487             g_strcmp0(ifm->reason, "STOP") == 0)
488                 return;
489
490         msg = print_if_msg(ifm);
491         title = NULL;
492         if (if_up(ifm))
493                 act = N_("Connected to ");
494         else
495                 act = NULL;
496         for (r = down_reasons; *r; r++) {
497                 if (g_strcmp0(*r, ifm->reason) == 0) {
498                         act = N_("Disconnected from ");
499                         break;
500                 }
501         }
502         if (act && ifm->ip.s_addr) {
503                 ipn = htonl(ifm->ip.s_addr);
504                 if (IN_LINKLOCAL(ipn))
505                         net = N_("private network");
506                 else if (IN_PRIVATE(ipn))
507                         net = N_("LAN");
508                 else
509                         net = N_("internet");
510                 title = g_strconcat(act, net, NULL);
511         }
512
513         if (title) {
514                 notify(title, msg, GTK_STOCK_NETWORK);
515                 g_free(title);
516         } else
517                 notify(N_("Interface event"), msg, GTK_STOCK_NETWORK);
518         g_free(msg);
519 }
520
521 static void
522 foreach_make_ifm(_unused gpointer key, gpointer value, _unused gpointer data)
523 {
524         struct if_msg *ifm;
525
526         ifm = make_if_msg((GHashTable *)value);
527         if (ignore_if_msg(ifm))
528                 g_free(ifm);
529         else if (ifm)
530                 interfaces = g_list_prepend(interfaces, ifm);
531 }
532
533 static void
534 dhcpcd_get_interfaces()
535 {
536         GHashTable *ifs;
537         GError *error = NULL;
538         GType otype;
539         char *msg;
540         GList *gl;
541         GSList *gsl;
542         GPtrArray *array;
543         struct if_msg *ifm;
544
545         otype = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
546         otype = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, otype);
547         if (!dbus_g_proxy_call(dbus, "GetInterfaces", &error,
548                                G_TYPE_INVALID,
549                                otype, &ifs, G_TYPE_INVALID))
550                 error_exit("GetInterfaces", error);
551         g_hash_table_foreach(ifs, foreach_make_ifm, NULL);
552         g_hash_table_unref(ifs);
553
554         /* Each interface config only remembers the last order when
555          * that interface was configured, so get the real order now. */
556         g_strfreev(interface_order);
557         interface_order = NULL;
558         if (!dbus_g_proxy_call(dbus, "ListInterfaces", &error,
559                                G_TYPE_INVALID,
560                                G_TYPE_STRV, &interface_order, G_TYPE_INVALID))
561                 error_exit("ListInterfaces", error);
562         interfaces = g_list_sort(interfaces, if_msg_comparer);
563
564         otype = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
565         otype = dbus_g_type_get_collection("GPtrArray", otype);
566         for (gl = interfaces; gl; gl = gl->next) {
567                 ifm = (struct if_msg *)gl->data;
568                 if (!ifm->wireless)
569                         continue;
570                 if (!dbus_g_proxy_call(dbus, "ScanResults", &error,
571                                        G_TYPE_STRING, ifm->ifname, G_TYPE_INVALID,
572                                        otype, &array, G_TYPE_INVALID)) 
573                 {
574                         g_message("ScanResults: %s", error->message);
575                         g_clear_error(&error);
576                         continue;
577                 }
578                 for (gsl = ifm->scan_results; gsl; gsl = gsl->next)
579                         g_free(gsl->data);
580                 g_slist_free(ifm->scan_results);
581                 ifm->scan_results = get_scan_results(ifm);
582         }
583
584         msg = NULL;
585         update_online(&msg);
586         // GTK+ 2.16 msg = gtk_status_icon_get_tooltip_text(status_icon);
587         if (msg != NULL) {
588                 notify(N_("Interface status"), msg, GTK_STOCK_NETWORK);
589                 g_free(msg);
590         }
591 }
592
593 static void
594 check_status(const char *status)
595 {
596         static char *last = NULL;
597         GList *gl;
598         char *version;
599         const char *msg;
600         gboolean refresh;
601         GError *error = NULL;
602
603         g_message("Status changed to %s", status);
604         if (g_strcmp0(status, "down") == 0) {
605                 for (gl = interfaces; gl; gl = gl->next)
606                         free_if_msg((struct if_msg *)gl->data);
607                 g_list_free(interfaces);
608                 interfaces = NULL;
609                 update_online(NULL);
610                 msg = N_(last? "Connection to dhcpcd lost" : "dhcpcd not running");
611                 gtk_status_icon_set_tooltip(status_icon, msg);
612                 notify(_("No network"), msg, GTK_STOCK_NETWORK);
613         }
614
615         refresh = FALSE;
616         if (last == NULL) {
617                 if (g_strcmp0(status, "down") != 0)
618                         refresh = TRUE;
619         } else {
620                 if (g_strcmp0(status, last) == 0)
621                         return;
622                 if (g_strcmp0(last, "down") == 0)
623                         refresh = TRUE;
624                 g_free(last);
625         }
626         last = g_strdup(status);
627
628         if (!refresh)
629                 return;
630         if (!dbus_g_proxy_call(dbus, "GetDhcpcdVersion", &error,
631                                G_TYPE_INVALID,
632                                G_TYPE_STRING, &version, G_TYPE_INVALID))
633                 error_exit(_("GetDhcpcdVersion"), error);
634         g_message(_("Connected to %s-%s"), "dhcpcd", version);
635         g_free(version);
636         dhcpcd_get_interfaces();
637 }
638
639 static void
640 dhcpcd_status(_unused DBusGProxy *proxy, const char *status, _unused void *data)
641 {
642         check_status(status);
643 }
644
645 static void
646 dhcpcd_scan_results(_unused DBusGProxy *proxy, const char *iface, _unused void *data)
647 {
648         struct if_msg *ifm;
649         struct if_ap *ifa, *ifa2;
650         GSList *gl, *aps, *l;
651         char *txt, *ntxt;
652
653         ifm = find_if_msg(iface);
654         if (ifm == NULL)
655                 return;
656         g_message(_("%s: Received scan results"), ifm->ifname);
657         aps = get_scan_results(ifm);
658         txt = NULL;
659         for (gl = aps; gl; gl = gl->next) {
660                 ifa = (struct if_ap *)gl->data;
661                 for (l = ifm->scan_results; l; l = l->next) {
662                         ifa2 = (struct if_ap *)l->data;
663                         if (g_strcmp0(ifa->ssid, ifa2->ssid) == 0)
664                                 break;
665                 }
666                 if (l == NULL) {
667                         if (txt == NULL)
668                                 txt = g_strdup(ifa->ssid);
669                         else {
670                                 ntxt =  g_strconcat(txt, "\n", ifa->ssid, NULL);
671                                 g_free(txt);
672                                 txt = ntxt;
673                         }
674                 }
675         }
676         for (gl = ifm->scan_results; gl; gl = gl->next)
677                 free_if_ap((struct if_ap *)gl->data);
678         g_slist_free(ifm->scan_results);
679         ifm->scan_results = aps;
680         if (txt != NULL) {
681                 notify(N_("Found new AP"), txt, GTK_STOCK_NETWORK);
682                 g_free(txt);
683         }
684 }
685
686 int
687 main(int argc, char *argv[])
688 {
689         DBusGConnection *bus;
690         GError *error = NULL;
691         char *version = NULL;
692         GType otype;
693         int tries = 5;
694
695                 
696         setlocale(LC_ALL, "");
697         bindtextdomain(PACKAGE, NULL);
698         bind_textdomain_codeset(PACKAGE, "UTF-8");
699         textdomain(PACKAGE); 
700
701         gtk_init(&argc, &argv);
702         g_set_application_name("dhcpcd Monitor");
703         status_icon = gtk_status_icon_new_from_icon_name("network-offline");
704         if (status_icon == NULL)
705                 status_icon = gtk_status_icon_new_from_stock(GTK_STOCK_DISCONNECT);
706         //network_offline = gtk_status_icon_get_pixbuf(status_icon);
707         
708         gtk_status_icon_set_tooltip(status_icon, _("Connecting to dhcpcd ..."));
709         gtk_status_icon_set_visible(status_icon, TRUE);
710
711         notify_init(PACKAGE);
712
713         g_message(_("Connecting to dbus ..."));
714         bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
715         if (bus == NULL || error != NULL)
716                 error_exit(_("Could not connect to system bus"), error);
717         dbus = dbus_g_proxy_new_for_name(bus,
718                                               DHCPCD_SERVICE,
719                                               DHCPCD_PATH,
720                                               DHCPCD_SERVICE);
721
722         g_message(_("Connecting to dhcpcd-dbus ..."));
723         while (--tries > 0) {
724                 g_clear_error(&error);
725                 if (dbus_g_proxy_call_with_timeout(dbus,
726                                                    "GetVersion",
727                                                    500,
728                                                    &error,
729                                                    G_TYPE_INVALID,
730                                                    G_TYPE_STRING,
731                                                    &version,
732                                                    G_TYPE_INVALID))
733                         break;
734         }
735         if (tries == 0)
736                 error_exit(_("GetVersion"), error);
737         g_message(_("Connected to %s-%s"), "dhcpcd-dbus", version);
738         g_free(version);
739
740         gtk_status_icon_set_tooltip(status_icon, _("Triggering dhcpcd ..."));
741         online = FALSE;
742         menu_init(status_icon);
743
744         if (!dbus_g_proxy_call(dbus, "GetStatus", &error,
745                                G_TYPE_INVALID,
746                                G_TYPE_STRING, &version, G_TYPE_INVALID))
747                 error_exit(_("GetStatus"), error);
748         check_status(version);
749         g_free(version);
750
751         otype = dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
752         dbus_g_proxy_add_signal(dbus, "Event",
753                                 otype, G_TYPE_INVALID);
754         dbus_g_proxy_connect_signal(dbus, "Event",
755                                     G_CALLBACK(dhcpcd_event),
756                                     bus, NULL);
757         dbus_g_proxy_add_signal(dbus, "StatusChanged",
758                                 G_TYPE_STRING, G_TYPE_INVALID);
759         dbus_g_proxy_connect_signal(dbus, "StatusChanged",
760                                     G_CALLBACK(dhcpcd_status),
761                                     bus, NULL);
762         dbus_g_proxy_add_signal(dbus, "ScanResults",
763                                 G_TYPE_STRING, G_TYPE_INVALID);
764         dbus_g_proxy_connect_signal(dbus, "ScanResults",
765                                     G_CALLBACK(dhcpcd_scan_results),
766                                     bus, NULL);
767
768         gtk_main();
769         return 0;
770 }