Fix for portrait mode support in CSSU
[tor-status] / src / status-area-applet-tor.vala
1 /* This file is part of status-area-applet-tor.
2  *
3  * Copyright (C) 2010-2011 Philipp Zabel
4  *
5  * status-area-applet-tor is free software: you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as published
7  * by the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * status-area-applet-tor is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with status-area-applet-tor. If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 [Compact]
20 class ProxyBackup {
21         public bool use_http_proxy;
22         public string http_host;
23         public string socks_host;
24         public string secure_host;
25         public int http_port;
26         public int socks_port;
27         public int secure_port;
28         public string mode;
29 }
30
31 class TorStatusMenuItem : HD.StatusMenuItem {
32         private const string STATUSMENU_TOR_LIBOSSO_SERVICE_NAME = "tor_status_menu_item";
33
34         private const int STATUS_MENU_ICON_SIZE = 48;
35         private const int STATUS_AREA_ICON_SIZE = 18;
36
37         private const string GCONF_DIR_TOR         = "/apps/maemo/tor";
38         private const string GCONF_KEY_TOR_ENABLED = GCONF_DIR_TOR + "/enabled";
39         private const string GCONF_KEY_BRIDGES     = GCONF_DIR_TOR + "/bridges";
40         private const string GCONF_KEY_EXITNODES   = GCONF_DIR_TOR + "/exit_nodes";
41
42         private const string GCONF_DIR_PROXY_HTTP         = "/system/http_proxy";
43         private const string GCONF_KEY_PROXY_HTTP_ENABLED = GCONF_DIR_PROXY_HTTP + "/use_http_proxy";
44         private const string GCONF_KEY_PROXY_HTTP_HOST    = GCONF_DIR_PROXY_HTTP + "/host";
45         private const string GCONF_KEY_PROXY_HTTP_PORT    = GCONF_DIR_PROXY_HTTP + "/port";
46
47         private const string GCONF_DIR_PROXY             = "/system/proxy";
48         private const string GCONF_KEY_PROXY_MODE        = GCONF_DIR_PROXY + "/mode";
49         private const string GCONF_KEY_PROXY_SOCKS_HOST  = GCONF_DIR_PROXY + "/socks_host";
50         private const string GCONF_KEY_PROXY_SOCKS_PORT  = GCONF_DIR_PROXY + "/socks_port";
51         private const string GCONF_KEY_PROXY_SECURE_HOST = GCONF_DIR_PROXY + "/secure_host";
52         private const string GCONF_KEY_PROXY_SECURE_PORT = GCONF_DIR_PROXY + "/secure_port";
53
54         // Widgets
55         Hildon.Button button;
56         Gtk.Label log_label;
57
58         // Icons
59         Gdk.Pixbuf icon_connecting;
60         Gdk.Pixbuf icon_connected;
61         Gtk.Image icon_enabled;
62         Gtk.Image icon_disabled;
63
64         // ConIc, GConf and Osso context
65         Osso.Context osso;
66         GConf.Client gconf;
67         ConIc.Connection conic;
68         bool conic_connected;
69
70         // Internal state
71         bool tor_enabled;
72         bool tor_connected;
73         Pid tor_pid;
74         int tor_stdout;
75         Pid polipo_pid;
76         ProxyBackup backup;
77         string tor_log;
78         TorControl.Connection tor_control;
79         string password;
80
81         /**
82          * Update status area icon and status menu button value
83          */
84         private bool update_status () {
85                 try {
86                         if (tor_enabled && tor_connected && icon_connected == null) {
87                                 var icon_theme = Gtk.IconTheme.get_default ();
88                                 var pixbuf = icon_theme.load_icon ("statusarea_tor_connected",
89                                                                    STATUS_AREA_ICON_SIZE,
90                                                                    Gtk.IconLookupFlags.NO_SVG);
91                                 icon_connected = pixbuf;
92                         }
93                         if (tor_enabled && !tor_connected && icon_connecting == null) {
94                                 var icon_theme = Gtk.IconTheme.get_default ();
95                                 var pixbuf = icon_theme.load_icon ("statusarea_tor_connecting",
96                                                                    STATUS_AREA_ICON_SIZE,
97                                                                    Gtk.IconLookupFlags.NO_SVG);
98                                 icon_connecting = pixbuf;
99                         }
100                         if (tor_enabled && icon_enabled == null) {
101                                 var icon_theme = Gtk.IconTheme.get_default();
102                                 var pixbuf = icon_theme.load_icon ("statusarea_tor_enabled",
103                                                                    STATUS_MENU_ICON_SIZE,
104                                                                    Gtk.IconLookupFlags.NO_SVG);
105                                 icon_enabled = new Gtk.Image.from_pixbuf (pixbuf);
106                         }
107                         if (!tor_enabled && icon_disabled == null) {
108                                 var icon_theme = Gtk.IconTheme.get_default();
109                                 var pixbuf = icon_theme.load_icon ("statusarea_tor_disabled",
110                                                                    STATUS_MENU_ICON_SIZE,
111                                                                    Gtk.IconLookupFlags.NO_SVG);
112                                 icon_disabled = new Gtk.Image.from_pixbuf (pixbuf);
113                         }
114                 } catch (Error e) {
115                         critical (e.message);
116                         var icon_theme = Gtk.IconTheme.get_default ();
117                         icon_theme.rescan_if_needed ();
118                         Timeout.add_seconds (1, update_status);
119                         return false;
120                 }
121
122                 if (conic_connected && tor_enabled) {
123                         set_status_area_icon (tor_connected ? icon_connected : icon_connecting);
124                         button.set_value (tor_connected ? _("Connected") : _("Connecting ..."));
125                 } else {
126                         set_status_area_icon (null);
127                         button.set_value (tor_enabled ? _("Disconnected") : _("Disabled"));
128                 }
129                 button.set_image (tor_enabled ? icon_enabled : icon_disabled);
130
131                 return false;
132         }
133
134         /**
135          * Callback for Tor daemon line output
136          */
137         private bool tor_io_func (IOChannel source, IOCondition condition) {
138
139                 if ((condition & (IOCondition.IN | IOCondition.PRI)) != 0) {
140                         string line = null;
141                         size_t length;
142                         try {
143                                 /* var status = */ source.read_line (out line, out length, null);
144
145                                 tor_log += line;
146                                 if (log_label != null)
147                                         log_label.label = tor_log;
148
149                                 if ("[notice]" in line) {
150                                         if ("Bootstrapped 100%" in line) {
151                                                 tor_connected = true;
152                                                 proxy_setup ();
153                                                 update_status ();
154                                         }
155                                         if ("Opening Control listener on 127.0.0.1:9051" in line) {
156                                                 tor_control = new TorControl.Connection ();
157                                                 tor_control_auth.begin ();
158                                         }
159                                 } else {
160                                         // FIXME
161                                         Hildon.Banner.show_information (null, null, "DEBUG: %s".printf (line));
162                                 }
163                         } catch (Error e) {
164                                 // FIXME
165                                 Hildon.Banner.show_information (null, null, "Error: %s".printf (e.message));
166                         }
167                 }
168                 if ((condition & (IOCondition.ERR | IOCondition.HUP | IOCondition.NVAL)) != 0) {
169                         return false;
170                 }
171                 return true;
172         }
173
174         /**
175          * Authenticate with Tor on the control channel
176          */
177         private async void tor_control_auth () throws Error {
178                 yield tor_control.authenticate_async (password);
179
180                 var bridges = gconf.get_list (GCONF_KEY_BRIDGES, GConf.ValueType.STRING);
181
182                 if (bridges.length () > 0) {
183                         // Enable bridge relays
184                         tor_control.set_conf_list ("Bridge", bridges);
185                         tor_control.set_conf_bool ("UseBridges", true);
186
187                         bool use = yield tor_control.get_conf_bool_async ("UseBridges");
188                         if (!use) {
189                                 Hildon.Banner.show_information (null, null,
190                                                                 "Failed to set up bridge relays");
191                         }
192                 }
193
194                 var exits = gconf.get_list (GCONF_KEY_EXITNODES, GConf.ValueType.STRING);
195
196                 if (exits.length () > 0) {
197                         // Enable strict exit nodes
198                         tor_control.set_conf_list ("ExitNodes", exits);
199                         tor_control.set_conf_bool ("StrictExitNodes", true);
200
201                         bool strict = yield tor_control.get_conf_bool_async ("StrictExitNodes");
202                         if (!strict) {
203                                 Hildon.Banner.show_information (null, null,
204                                                                 "Failed to set up strict exit nodes");
205                         }
206                 }
207         }
208
209         /**
210          * Start Tor and setup proxy settings
211          */
212         private void start_tor () {
213                 try {
214                         if (tor_pid == (Pid) 0) {
215                                 string[] tor_hash_argv = {
216                                         "/usr/sbin/tor",
217                                         "--hash-password", "",
218                                         null
219                                 };
220                                 var tv = TimeVal ();
221                                 Random.set_seed ((uint32) tv.tv_usec);
222                                 password = "tor-status-%8x".printf (Random.next_int ());
223                                 tor_hash_argv[2] = password;
224                                 string hash;
225                                 Process.spawn_sync ("/tmp", tor_hash_argv, null, 0, null, out hash);
226                                 hash = hash.str ("\n16:").offset (1).replace ("\n", "");
227
228                                 if (hash == null) {
229                                         Hildon.Banner.show_information (null, null,
230                                                                         "Failed to get hash");
231                                         return;
232                                 }
233
234                                 string[] tor_argv = {
235                                         "/usr/sbin/tor",
236                                         "--ControlPort", "9051",
237                                         "--HashedControlPassword", "",
238                                         null
239                                 };
240                                 tor_argv[4] = hash;
241                                 Process.spawn_async_with_pipes ("/tmp",
242                                                                 tor_argv,
243                                                                 null,
244                                                                 SpawnFlags.SEARCH_PATH,
245                                                                 null,
246                                                                 out tor_pid,
247                                                                 null,
248                                                                 out tor_stdout);
249
250                                 var channel = new IOChannel.unix_new (tor_stdout);
251                                 channel.add_watch (IOCondition.IN | IOCondition.PRI | IOCondition.ERR | IOCondition.HUP | IOCondition.NVAL, tor_io_func);
252                         }
253                         if (polipo_pid == (Pid) 0) {
254                                 Process.spawn_async_with_pipes ("/tmp",
255                                                                 { "/usr/bin/polipo" },
256                                                                 null,
257                                                                 SpawnFlags.SEARCH_PATH,
258                                                                 null,
259                                                                 out polipo_pid);
260                         }
261
262                         /* --> proxy settings and will be set up and tor_connected will
263                          * be set to true once Tor signals 100%
264                          */
265                 } catch (SpawnError e) {
266                         Hildon.Banner.show_information (null, null, "DEBUG: Failed to spawn polipo and tor: %s".printf (e.message));
267                         return;
268                 }
269
270                 tor_log = "";
271                 if (log_label != null)
272                         log_label.label = tor_log;
273                 update_status ();
274         }
275
276         /**
277          * Stop Tor and revert proxy settings
278          */
279         private void stop_tor () {
280                 proxy_restore ();
281                 tor_connected = false;
282                 if (polipo_pid != (Pid) 0) {
283                         Process.close_pid (polipo_pid);
284                         Posix.kill ((Posix.pid_t) polipo_pid, Posix.SIGKILL);
285                         polipo_pid = (Pid) 0;
286                 }
287                 if (tor_pid != (Pid) 0) {
288                         Process.close_pid (tor_pid);
289                         Posix.kill ((Posix.pid_t) tor_pid, Posix.SIGKILL);
290                         tor_pid = (Pid) 0;
291                 }
292
293                 update_status ();
294         }
295
296         /**
297          * Setup proxy settings to route through the Tor network
298          */
299         private void proxy_setup () {
300                 if (backup == null) try {
301                         backup = new ProxyBackup ();
302                         backup.use_http_proxy = gconf.get_bool (GCONF_KEY_PROXY_HTTP_ENABLED);
303
304                         backup.http_host = gconf.get_string (GCONF_KEY_PROXY_HTTP_HOST);
305                         backup.socks_host = gconf.get_string (GCONF_KEY_PROXY_SOCKS_HOST);
306                         backup.secure_host = gconf.get_string (GCONF_KEY_PROXY_SECURE_HOST);
307                         backup.http_port = gconf.get_int (GCONF_KEY_PROXY_HTTP_PORT);
308                         backup.socks_port = gconf.get_int (GCONF_KEY_PROXY_SOCKS_PORT);
309                         backup.secure_port = gconf.get_int (GCONF_KEY_PROXY_SECURE_PORT);
310
311                         backup.mode = gconf.get_string (GCONF_KEY_PROXY_MODE);
312                 } catch (Error e) {
313                         critical ("Error saving proxy settings: %s", e.message);
314                         backup = new ProxyBackup ();
315                         backup.use_http_proxy = false;
316
317                         backup.http_host = "";
318                         backup.socks_host = "";
319                         backup.secure_host = "";
320                         backup.http_port = 8080;
321                         backup.socks_port = 0;
322                         backup.secure_port = 0;
323
324                         backup.mode = "none";
325                 }
326                 try {
327                 //      Hildon.Banner.show_information (null, null, "DEBUG: Proxy setup");
328                         gconf.set_bool (GCONF_KEY_PROXY_HTTP_ENABLED, true);
329
330                         gconf.set_string (GCONF_KEY_PROXY_HTTP_HOST, "127.0.0.1");
331                         gconf.set_string (GCONF_KEY_PROXY_SOCKS_HOST, "127.0.0.1");
332                         gconf.set_string (GCONF_KEY_PROXY_SECURE_HOST, "127.0.0.1");
333                         gconf.set_int (GCONF_KEY_PROXY_HTTP_PORT, 8118);
334                         gconf.set_int (GCONF_KEY_PROXY_SOCKS_PORT, 9050);
335                         gconf.set_int (GCONF_KEY_PROXY_SECURE_PORT, 8118);
336
337                         gconf.set_string (GCONF_KEY_PROXY_MODE, "manual");
338                 } catch (Error e) {
339                         critical ("Error changing proxy settings: %s", e.message);
340                 }
341         }
342
343         /**
344          * Revert proxy settings
345          */
346         private void proxy_restore () {
347                 if (backup != null) try {
348                 //      Hildon.Banner.show_information (null, null, "DEBUG: Restoring proxy settings");
349                         gconf.set_bool (GCONF_KEY_PROXY_HTTP_ENABLED, backup.use_http_proxy);
350
351                         gconf.set_string (GCONF_KEY_PROXY_HTTP_HOST, backup.http_host);
352                         gconf.set_string (GCONF_KEY_PROXY_SOCKS_HOST, backup.socks_host);
353                         gconf.set_string (GCONF_KEY_PROXY_SECURE_HOST, backup.secure_host);
354                         gconf.set_int (GCONF_KEY_PROXY_HTTP_PORT, backup.http_port);
355                         gconf.set_int (GCONF_KEY_PROXY_SOCKS_PORT, backup.socks_port);
356                         gconf.set_int (GCONF_KEY_PROXY_SECURE_PORT, backup.secure_port);
357
358                         gconf.set_string (GCONF_KEY_PROXY_MODE, backup.mode);
359                         backup = null;
360                 } catch (Error e) {
361                         critical ("Error restoring proxy: %s", e.message);
362                 }
363         }
364
365         /**
366          * Show the bridge relay configuration dialog
367          */
368         private void bridges_clicked_cb () {
369                 var dialog = new BridgeDialog ();
370                 dialog.show ();
371         }
372
373         /**
374          * Show the exit node configuration dialog
375          */
376         private void exit_nodes_clicked_cb () {
377                 var dialog = new ExitNodeDialog (tor_control);
378                 dialog.show ();
379         }
380
381         /**
382          * Check whether the IP address consists of four numbers in the 0..255 range
383          */
384         bool is_valid_ip_address (string address) {
385                 string[] ip = address.split (".");
386
387                 if (ip.length != 4)
388                         return false;
389
390                 for (int i = 0; i < ip.length; i++) {
391                         int n = ip[i].to_int ();
392                         if (n < 0 || n > 255)
393                                 return false;
394                 }
395
396                 return true;
397         }
398
399         /**
400          * Show the Tor log dialog
401          */
402         private void show_tor_log () {
403                 var dialog = new Gtk.Dialog ();
404                 var content = (Gtk.VBox) dialog.get_content_area ();
405                 content.set_size_request (-1, 5*70);
406
407                 dialog.set_title (_("Log"));
408
409                 var pannable = new Hildon.PannableArea ();
410                 pannable.mov_mode = Hildon.MovementMode.BOTH;
411                 log_label = new Gtk.Label (tor_log);
412                 log_label.set_alignment (0, 0);
413                 pannable.add_with_viewport (log_label);
414                 content.pack_start (pannable, true, true, 0);
415
416                 dialog.response.connect (() => {
417                         log_label = null;
418                 });
419
420                 dialog.show_all ();
421         }
422
423         /**
424          * Callback for the status menu button clicked signal
425          */
426         private const int RESPONSE_LOG = 1;
427         private void button_clicked_cb () {
428                 var dialog = new Gtk.Dialog ();
429                 var content = (Gtk.VBox) dialog.get_content_area ();
430
431                 dialog.set_title (_("Tor: anonymity online"));
432
433                 var check = new Hildon.CheckButton (Hildon.SizeType.FINGER_HEIGHT);
434                 check.set_label (_("Enable onion routing"));
435                 check.set_active (tor_enabled);
436                 content.pack_start (check, true, true, 0);
437
438                 var button = new Hildon.Button.with_text (Hildon.SizeType.FINGER_HEIGHT,
439                                                           Hildon.ButtonArrangement.VERTICAL,
440                                                           _("Bridge relays"),
441                                                           get_bridge_list ());
442                 button.set_style (Hildon.ButtonStyle.PICKER);
443                 button.set_alignment (0, 0.5f, 0, 0.5f);
444                 button.clicked.connect (bridges_clicked_cb);
445                 content.pack_start (button, true, true, 0);
446
447                 button = new Hildon.Button.with_text (Hildon.SizeType.FINGER_HEIGHT,
448                                                       Hildon.ButtonArrangement.VERTICAL,
449                                                       _("Restrict exit nodes"),
450                                                       get_exit_node_list ());
451                 button.set_style (Hildon.ButtonStyle.PICKER);
452                 button.set_alignment (0, 0.5f, 0, 0.5f);
453                 button.clicked.connect (exit_nodes_clicked_cb);
454                 content.pack_start (button, true, true, 0);
455
456                 dialog.add_button (_("Log"), RESPONSE_LOG);
457
458                 dialog.add_button (_("Save"), Gtk.ResponseType.ACCEPT);
459                 dialog.response.connect ((response_id) => {
460                         if (response_id == RESPONSE_LOG) {
461                                 show_tor_log ();
462                                 return;
463                         }
464                         if (response_id == Gtk.ResponseType.ACCEPT) {
465                                 if (!tor_enabled && check.get_active ()) try {
466                                         gconf.set_bool (GCONF_KEY_TOR_ENABLED, true);
467
468                                         // Enabled by user interaction, so connect if needed
469                                         if (!conic_connected)
470                                                 conic.connect (ConIc.ConnectFlags.NONE);
471                                 } catch (Error e) {
472                                         Hildon.Banner.show_information (null, null, "Failed to enable GConf key");
473                                 } else if (tor_enabled && !check.get_active ()) try {
474                                         gconf.set_bool (GCONF_KEY_TOR_ENABLED, false);
475                                 } catch (Error e) {
476                                         Hildon.Banner.show_information (null, null, "Failed to disable GConf key");
477                                 }
478                         }
479                         dialog.destroy ();
480                 });
481
482                 dialog.show_all ();
483         }
484
485         private string get_bridge_list () {
486                 string list = null;
487                 var bridges = new SList<string> ();
488                 try {
489                         bridges = gconf.get_list (GCONF_KEY_BRIDGES, GConf.ValueType.STRING);
490                 } catch (Error e) {
491                         critical ("Error loading bridges: %s", e.message);
492                 }
493                 foreach (string bridge in bridges) {
494                         if (list == null)
495                                 list = bridge;
496                         else
497                                 list += ", " + bridge;
498                 }
499                 if (list == null)
500                         list = _("None");
501
502                 return list;
503         }
504
505         private string get_exit_node_list () {
506                 string list = null;
507                 var exits = new SList<string> ();
508                 try {
509                         exits = gconf.get_list (GCONF_KEY_EXITNODES, GConf.ValueType.STRING);
510                 } catch (Error e) {
511                         error ("Error loading exit nodes: %s", e.message);
512                 }
513                 foreach (string exit in exits) {
514                         if (list == null)
515                                 list = exit;
516                         else
517                                 list += ", " + exit;
518                 }
519                 if (list == null)
520                         list = _("None");
521
522                 return list;
523         }
524
525         /**
526          * Callback for GConf change notification on the tor_enabled key
527          */
528         private void tor_enabled_changed_cb (GConf.Client gc, uint cxnid, GConf.Entry entry) {
529                 if (entry.key == GCONF_KEY_TOR_ENABLED) {
530                         bool old_tor_enabled = tor_enabled;
531                         tor_enabled = entry.get_value ().get_bool ();
532                         if (old_tor_enabled == tor_enabled)
533                                 return;
534
535                         if (tor_enabled) {
536                                 // Start Tor immediately if a connection is already available
537                                 if (conic_connected)
538                                         start_tor ();
539                         } else {
540                                 stop_tor ();
541                                 if (conic_connected)
542                                         conic.disconnect ();
543                         }
544                 }
545         }
546
547         /**
548          * Callback for the ConIc connection-event signal
549          */
550         private void conic_connection_event_cb (ConIc.Connection conic, ConIc.ConnectionEvent event) {
551                 var status = event.get_status ();
552                 switch (status) {
553                 case ConIc.ConnectionStatus.CONNECTED:
554                         conic_connected = true;
555                         if (tor_enabled) {
556                                 start_tor ();
557                         } else {
558                                 update_status ();
559                         }
560                         break;
561                 case ConIc.ConnectionStatus.DISCONNECTING:
562                         conic_connected = false;
563                         stop_tor ();
564                         break;
565                 case ConIc.ConnectionStatus.DISCONNECTED:
566                 case ConIc.ConnectionStatus.NETWORK_UP:
567                         // ignore
568                         break;
569                 }
570
571                 var error = event.get_error ();
572                 switch (error) {
573                 case ConIc.ConnectionError.CONNECTION_FAILED:
574                         Hildon.Banner.show_information (null, null, "DEBUG: ConIc connection failed");
575                         break;
576                 case ConIc.ConnectionError.USER_CANCELED:
577                         Hildon.Banner.show_information (null, null, "DEBUG: ConIc user canceled");
578                         break;
579                 case ConIc.ConnectionError.NONE:
580                 case ConIc.ConnectionError.INVALID_IAP:
581                         // ignore
582                         break;
583                 }
584         }
585
586         private void create_widgets () {
587                 // Status menu button
588                 button = new Hildon.Button.with_text (Hildon.SizeType.FINGER_HEIGHT,
589                                                       Hildon.ButtonArrangement.VERTICAL,
590                                                       _("The Onion Router"),
591                                                       tor_enabled ? _("Enabled") : _("Disabled"));
592                 button.set_alignment (0.0f, 0.5f, 1.0f, 1.0f);
593                 button.set_style (Hildon.ButtonStyle.PICKER);
594                 button.clicked.connect (button_clicked_cb);
595
596                 add (button);
597
598                 log_label = null;
599
600                 // Status area icon
601                 update_status ();
602
603                 show_all ();
604         }
605
606         construct {
607                 // Gettext hook-up
608                 Intl.setlocale (LocaleCategory.ALL, "");
609                 Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
610                 Intl.textdomain (Config.GETTEXT_PACKAGE);
611
612                 // GConf hook-up
613                 gconf = GConf.Client.get_default ();
614                 try {
615                         tor_enabled = gconf.get_bool (GCONF_KEY_TOR_ENABLED);
616
617                         // Request change notifications for the tor_enabled key
618                         gconf.add_dir (GCONF_DIR_TOR, GConf.ClientPreloadType.ONELEVEL);
619                         gconf.notify_add (GCONF_KEY_TOR_ENABLED, tor_enabled_changed_cb);
620                 } catch (Error e) {
621                         critical ("Failed to get GConf setting: %s", e.message);
622                 }
623                 tor_connected = false;
624
625                 // ConIc hook-up
626                 conic = new ConIc.Connection ();
627                 if (conic == null) {
628                         Hildon.Banner.show_information (null, null, "DEBUG: ConIc hook-up failed");
629                 }
630                 conic_connected = false;
631                 conic.automatic_connection_events = true;
632                 if (tor_enabled)
633                         conic.connect (ConIc.ConnectFlags.AUTOMATICALLY_TRIGGERED);
634                 conic.connection_event.connect (conic_connection_event_cb);
635
636                 // Osso hook-up
637                 osso = new Osso.Context (STATUSMENU_TOR_LIBOSSO_SERVICE_NAME,
638                                          Config.VERSION,
639                                          true,
640                                          null);
641
642                 create_widgets ();
643         }
644 }
645
646 /**
647  * Vala code can't use the HD_DEFINE_PLUGIN_MODULE macro, but it handles
648  * most of the class registration issues itself. Only this code from
649  * HD_PLUGIN_MODULE_SYMBOLS_CODE has to be has to be included manually
650  * to register with hildon-desktop:
651  */
652 [ModuleInit]
653 public void hd_plugin_module_load (TypeModule plugin) {
654         // [ModuleInit] registers types automatically
655         ((HD.PluginModule) plugin).add_type (typeof (TorStatusMenuItem));
656 }
657
658 public void hd_plugin_module_unload (HD.PluginModule plugin) {
659 }