4d7ec067a89a14f9cadbf42179a4c470a816a923
[mtetherd] / status.c
1 /*
2   mtetherd
3   (c) 2010 Gregor Riepl <onitake@gmail.com>
4   
5   Tethering utility for Maemo
6   
7   This program is free software: you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation, either version 3 of the License, or
10   (at your option) any later version.
11   
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16   
17   You should have received a copy of the GNU General Public License
18   along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <pwd.h>
26 #include <sys/types.h>
27 #include <gtk/gtk.h>
28 #include <hildon/hildon.h>
29 #include <dbus/dbus-glib-lowlevel.h>
30 #include <libhal.h>
31
32 #include "status.h"
33
34 #define MTETHERD_STATUS_PLUGIN_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE(obj, TYPE_MTETHERD_STATUS_PLUGIN, MTetherDStatusPluginPrivate))
35
36 struct _MTetherDStatusPluginPrivate {
37         GtkWidget *enable_button;
38         gboolean usb_on;
39         gboolean net_on;
40         DBusGConnection *dbus_connection;
41         LibHalContext *hal_context;
42 };
43
44 static const char *USBDEV_PATH = "/org/freedesktop/Hal/devices/usb_device_1d6b_2_musb_hdrc";
45 static const char *USBNET_MODULE = "g_ether";
46
47 #ifndef IMAGE_DIR
48 #define IMAGE_DIR "/usr/share/pixmaps"
49 #endif
50 #ifndef SBIN_DIR
51 #define SBIN_DIR "/usr/sbin"
52 #endif
53
54 HD_DEFINE_PLUGIN_MODULE(MTetherDStatusPlugin, mtetherd_status_plugin, HD_TYPE_STATUS_MENU_ITEM);
55
56 static void mtetherd_status_plugin_class_finalize(MTetherDStatusPluginClass *klass) { }
57
58 static void mtetherd_status_plugin_finalize(GObject *object) {
59         g_message("Destroying mtetherd status plugin");
60
61         MTetherDStatusPlugin *plugin = MTETHERD_STATUS_PLUGIN(object);
62
63         if (plugin && plugin->priv) {
64                 if (plugin->priv->hal_context) {
65                         libhal_ctx_shutdown(plugin->priv->hal_context, NULL);
66                         libhal_ctx_free(plugin->priv->hal_context);
67                 }
68                 if (plugin->priv->dbus_connection) {
69                         dbus_g_connection_unref(plugin->priv->dbus_connection);
70                 }
71         }
72 }
73
74 static void mtetherd_status_plugin_class_init(MTetherDStatusPluginClass *klass) {
75         GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
76
77         gobject_class->finalize = mtetherd_status_plugin_finalize;
78         g_type_class_add_private(klass, sizeof(MTetherDStatusPluginPrivate));
79 }
80
81 static gboolean get_usbnet_enabled(MTetherDStatusPlugin *plugin) {
82         g_message("Scanning /proc/modules");
83         //hildon_banner_show_informationf(GTK_WIDGET(plugin), NULL, "Scanning /proc/modules");
84
85         FILE *fp = fopen("/proc/modules", "r");
86         if (!fp) {
87                 return FALSE;
88         }
89         gboolean found = FALSE;
90         char *line = NULL;
91         while (!found && getline(&line, NULL, fp) != -1) {
92                 g_message("Checking if '%s' contains g_ether...", line);
93                 if (strncmp(line, USBNET_MODULE, sizeof(USBNET_MODULE) - 1) == 0) {
94                         hildon_banner_show_informationf(GTK_WIDGET(plugin), NULL, "Found g_ether");
95                         found = TRUE;
96                 }
97                 free(line);
98                 line = NULL;
99         }
100         fclose(fp);
101         return found;
102 }
103
104 static gboolean launch_usbnet_script(gboolean enable) {
105         const char *arg;
106         if (enable) {
107                 arg = SBIN_DIR "mtetherd-usbnet-enable.sh";
108         } else {
109                 arg = SBIN_DIR "mtetherd-usbnet-disable.sh";
110         }
111         g_debug("Launching %s", arg);
112         const char *command[] = { "/usr/bin/sudo", arg, NULL };
113         pid_t pid = fork();
114         if (pid == 0) {
115                 if (execv(command[0], (char **const) command) == -1) {
116                         exit(1);
117                 }
118         } else if (pid == -1) {
119                 // error forking
120                 return FALSE;
121         }
122         // launch ok
123         return TRUE;
124 }
125
126 static void enable_button_set_text(GtkWidget *button, gboolean enabled) {
127         if (enabled) {
128                 hildon_button_set_text(HILDON_BUTTON(button), "Toggle USB Networking", "Enabled");
129         } else {
130                 hildon_button_set_text(HILDON_BUTTON(button), "Toggle USB Networking", "Disabled");
131         }
132 }
133
134 static void enable_button_clicked(GtkWidget *button, gpointer data) {
135         MTetherDStatusPlugin *plugin = MTETHERD_STATUS_PLUGIN(data);
136
137         if (plugin && plugin->priv && button == plugin->priv->enable_button) {
138                 if (plugin->priv->net_on) {
139                         if (!launch_usbnet_script(FALSE)) {
140                                 g_error("Error starting USB networking");
141                         }
142                 } else {
143                         if (!launch_usbnet_script(TRUE)) {
144                                 g_error("Error starting USB networking");
145                         }
146                 }
147         }
148 }
149
150 static void mtetherd_status_plugin_usb_plugged_show(MTetherDStatusPlugin *plugin) {
151         if (plugin) {
152                 if (plugin->priv && plugin->priv->hal_context) {
153                         DBusError derr;
154                         dbus_error_init(&derr);
155                         dbus_bool_t plugged = libhal_device_get_property_bool(plugin->priv->hal_context, USBDEV_PATH, "button.state.value", &derr);
156                         if (dbus_error_is_set(&derr)) {
157                                 g_warning("Error getting USB plugged status (%s): %s", derr.name, derr.message);
158                                 hildon_banner_show_informationf(GTK_WIDGET(plugin), NULL, "Error getting USB plugged status (%s): %s", derr.name, derr.message);
159                                 dbus_error_free(&derr);
160                         } else {
161                                 plugin->priv->usb_on = plugged;
162                                 if (plugin->priv->usb_on) {
163                                         gtk_widget_show(GTK_WIDGET(plugin));
164                                 } else {
165                                         gtk_widget_hide(GTK_WIDGET(plugin));
166                                 }
167                         }
168                 } else {
169                         // DEBUG
170                         //gtk_widget_show(GTK_WIDGET(plugin));
171                 }
172         }
173 }
174
175 static void mtetherd_status_plugin_mapped(GtkWidget *widget, gpointer data) {
176         hildon_banner_show_informationf(widget, NULL, "Plugin mapped");
177         MTetherDStatusPlugin *plugin = MTETHERD_STATUS_PLUGIN(widget);
178         
179         if (plugin && plugin->priv) {
180                 plugin->priv->net_on = get_usbnet_enabled(plugin);
181                 if (plugin->priv->enable_button) {
182                         enable_button_set_text(plugin->priv->enable_button, plugin->priv->net_on);
183                 }
184         }
185 }
186
187 static gboolean mtetherd_status_plugin_event(GtkWidget *widget, GdkEvent *event, gpointer user_data) {
188         g_message("Got event %d", event->type);
189         return FALSE;
190 }
191
192 static void mtetherd_status_plugin_device_condition(LibHalContext *ctx, const char *udi, const char *condition, const char *detail) {
193         MTetherDStatusPlugin *plugin = MTETHERD_STATUS_PLUGIN(libhal_ctx_get_user_data(ctx));
194         
195         if (plugin) {
196                 g_message("Got HAL condition %s on %s: %s", condition, udi, detail);
197                 //hildon_banner_show_informationf(GTK_WIDGET(plugin), NULL, "Got HAL condition %s on %s: %s", condition, udi, detail);
198                 if (strcmp(USBDEV_CONDITION, "ButtonPressed") == 0) {
199                         if (strcmp(USBDEV_PATH, udi) == 0) {
200                                 mtetherd_status_plugin_usb_plugged_show(plugin);
201                         }
202                 } else if (strcmp("DeviceAdded", condition) == 0) {
203                         if (strcmp(USBDEV_PATH, detail) == 0) {
204                                 plugin->priv->net_on = TRUE;
205                                 enable_button_set_text(plugin->priv->enable_button, plugin->priv->net_on);
206                         }
207                 } else if (strcmp("DeviceRemoved", condition) == 0) {
208                         if (strcmp(USBDEV_PATH, detail) == 0) {
209                                 plugin->priv->net_on = FALSE;
210                                 enable_button_set_text(plugin->priv->enable_button, plugin->priv->net_on);
211                         }
212                 }
213         }
214 }
215
216 static void mtetherd_status_plugin_init(MTetherDStatusPlugin *plugin) {
217         plugin->priv = MTETHERD_STATUS_PLUGIN_GET_PRIVATE(plugin);
218
219         plugin->priv->usb_on = FALSE;
220         plugin->priv->net_on = FALSE;
221         
222         plugin->priv->enable_button = hildon_button_new(HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT, HILDON_BUTTON_ARRANGEMENT_VERTICAL);
223         if (plugin->priv->enable_button) {
224                 GError *err = NULL;
225                 GdkPixbuf *icon = gdk_pixbuf_new_from_file(IMAGE_DIR "/mtetherd-net-icon.png", &err);
226                 if (err) {
227                         g_warning("Can't load mtetherd icon: %s", err->message);
228                         hildon_banner_show_informationf(GTK_WIDGET(plugin), NULL, "Can't load mtetherd icon: %s", err->message);
229                         g_error_free(err);
230                         err = NULL;
231                 }
232                 if (icon) {
233                         GtkWidget *image = gtk_image_new_from_pixbuf(icon);
234                         hildon_button_set_image(HILDON_BUTTON(plugin->priv->enable_button), image);
235                         hildon_button_set_image_position(HILDON_BUTTON(plugin->priv->enable_button), GTK_POS_LEFT);
236                         g_object_unref(icon);
237                 }
238                 gboolean enabled = get_usbnet_enabled(plugin);
239                 enable_button_set_text(plugin->priv->enable_button, enabled);
240                 g_signal_connect(plugin->priv->enable_button, "clicked", G_CALLBACK(enable_button_clicked), plugin);
241                 gtk_container_add(GTK_CONTAINER(plugin), plugin->priv->enable_button);
242                 gtk_widget_show_all(plugin->priv->enable_button);
243         }
244         //g_signal_connect(plugin, "expose-event", G_CALLBACK(mtetherd_status_plugin_event), NULL);
245
246         //hildon_banner_show_informationf(GTK_WIDGET(plugin), NULL, "Initialized mtetherd status plugin");
247         GError *err = NULL;
248         plugin->priv->dbus_connection = hd_status_plugin_item_get_dbus_g_connection(HD_STATUS_PLUGIN_ITEM(plugin), DBUS_BUS_SYSTEM, &err);
249         if (err) {
250                 g_warning("Can't open DBUS connection: %s", err->message);
251                 hildon_banner_show_informationf(GTK_WIDGET(plugin), NULL, "Error opening DBUS connection: %s", err->message);
252                 g_error_free(err);
253                 err = NULL;
254         } else {
255                 g_message("Got DBUS Glib connection: %p", plugin->priv->dbus_connection);
256         }
257         if (plugin->priv->dbus_connection) {
258                 plugin->priv->hal_context = libhal_ctx_new();
259                 if (plugin->priv->hal_context) {
260                         if (libhal_ctx_set_dbus_connection(plugin->priv->hal_context, dbus_g_connection_get_connection(plugin->priv->dbus_connection))) {
261                                 if (!libhal_ctx_set_user_data(plugin->priv->hal_context, plugin)) {
262                                         g_warning("Can't set user data of HAL context");
263                                         hildon_banner_show_informationf(GTK_WIDGET(plugin), NULL, "Can't set user data of HAL context");
264                                 }
265                                 if (!libhal_ctx_set_device_condition(plugin->priv->hal_context, mtetherd_status_plugin_device_condition)) {
266                                         g_warning("Error assigning device condition callback");
267                                         hildon_banner_show_informationf(GTK_WIDGET(plugin), NULL, "Error assigning device condition callback");
268                                 }
269                                 DBusError derr;
270                                 dbus_error_init(&derr);
271                                 if (!libhal_ctx_init(plugin->priv->hal_context, &derr)) {
272                                         if (dbus_error_is_set(&derr)) {
273                                                 g_warning("Error initializing HAL context (%s): %s", derr.name, derr.message);
274                                                 hildon_banner_show_informationf(GTK_WIDGET(plugin), NULL, "Error initializing HAL context (%s): %s", derr.name, derr.message);
275                                                 dbus_error_free(&derr);
276                                         } else {
277                                                 g_warning("Error initializing HAL context: unknown error");
278                                                 //hildon_banner_show_informationf(GTK_WIDGET(plugin), NULL, "Error initializing HAL context: unknown error");
279                                         }
280                                         libhal_ctx_free(plugin->priv->hal_context);
281                                         plugin->priv->hal_context = NULL;
282                                 }
283                         } else {
284                                 g_warning("Can't set DBUS connection of HAL context");
285                                 hildon_banner_show_informationf(GTK_WIDGET(plugin), NULL, "Can't set DBUS connection of HAL context");
286                                 libhal_ctx_free(plugin->priv->hal_context);
287                                 plugin->priv->hal_context = NULL;
288                         }
289                 } else {
290                         g_warning("Can't allocate HAL context");
291                         hildon_banner_show_informationf(GTK_WIDGET(plugin), NULL, "Can't allocate HAL context");
292                 }
293         }
294
295         mtetherd_status_plugin_usb_plugged_show(plugin);
296 }
297