Fixed network setup scripts
[mtetherd] / plugin.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 <glib/gprintf.h>
28 #include <gtk/gtk.h>
29 #include <hildon/hildon.h>
30 #include "plugin.h"
31 #include "hal.h"
32 #include "net.h"
33 #include "util.h"
34
35 #define MTETHERD_STATUS_PLUGIN_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE(obj, TYPE_MTETHERD_STATUS_PLUGIN, MTetherDStatusPluginPrivate))
36
37 struct _MTetherDStatusPluginPrivate {
38         GtkWidget *enable_button;
39         gpointer devices;
40         gboolean usb_plugged;
41         gboolean usbnet_state;
42         FILE *log_fp;
43         guint log_handler;
44 };
45
46 #ifndef IMAGE_DIR
47 #define IMAGE_DIR "/usr/share/pixmaps"
48 #endif
49 #ifndef BIN_DIR
50 #define BIN_DIR "/usr/bin"
51 #endif
52 #ifndef SBIN_DIR
53 #define SBIN_DIR "/usr/sbin"
54 #endif
55 #ifndef TMP_DIR
56 #define TMP_DIR "/tmp"
57 #endif
58
59 // The UDI contains the MAC address and is thus unsuitable for
60 // loaded status checking, so we just use the interface name
61 static const char *USBNET_INTERFACE = "usb0";
62 static const char *WAN_INTERFACE = "gprs0";
63 const char *MTETHERD_LOG_DOMAIN = "mtetherd";
64
65 HD_DEFINE_PLUGIN_MODULE(MTetherDStatusPlugin, mtetherd_status_plugin, HD_TYPE_STATUS_MENU_ITEM);
66
67 static void mtetherd_status_plugin_class_finalize(MTetherDStatusPluginClass *klass) { }
68
69 static void mtetherd_status_plugin_finalize(GObject *object) {
70         g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, "Destroying mtetherd status plugin");
71
72         MTetherDStatusPlugin *plugin = MTETHERD_STATUS_PLUGIN(object);
73
74         if (plugin && plugin->priv) {
75                 mtetherd_hal_finalize(plugin);
76                 mtetherd_device_list_free(plugin->priv->devices);
77                 if (plugin->priv->log_fp) {
78                         g_log_remove_handler(MTETHERD_LOG_DOMAIN, plugin->priv->log_handler);
79                         fclose(plugin->priv->log_fp);
80                 }
81         }
82 }
83
84 static void mtetherd_status_plugin_class_init(MTetherDStatusPluginClass *klass) {
85         GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
86
87         if (gobject_class) {
88                 gobject_class->finalize = mtetherd_status_plugin_finalize;
89                 g_type_class_add_private(klass, sizeof(MTetherDStatusPluginPrivate));
90         }
91 }
92
93 static void mtetherd_status_plugin_enable_button_set_text(MTetherDStatusPlugin *plugin) {
94         if (plugin && plugin->priv && plugin->priv->enable_button) {
95                 if (plugin->priv->usbnet_state) {
96                         hildon_button_set_text(HILDON_BUTTON(plugin->priv->enable_button), "USB networking", "Enabled");
97                 } else {
98                         hildon_button_set_text(HILDON_BUTTON(plugin->priv->enable_button), "USB networking", "Disabled");
99                 }
100         }
101 }
102
103 static void mtetherd_status_plugin_enable_button_clicked(GtkWidget *button, gpointer data) {
104         MTetherDStatusPlugin *plugin = MTETHERD_STATUS_PLUGIN(data);
105
106         if (plugin && plugin->priv && button == plugin->priv->enable_button) {
107                 const char *arg;
108                 if (plugin->priv->usbnet_state) {
109                         arg = SBIN_DIR "/mtetherd-usbnet-disable.sh";
110                 } else {
111                         arg = SBIN_DIR "/mtetherd-usbnet-enable.sh";
112                 }
113                 if (arg) {
114                         g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Launching %s", arg);
115                         const char *command[] = { BIN_DIR "/sudo", arg, NULL };
116                         if (!mtetherd_launch_script(command)) {
117                                 g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Error launching USB networking script");
118                         }
119                 }
120         }
121 }
122
123 static void mtetherd_status_plugin_usb_plugged_show(MTetherDStatusPlugin *plugin) {
124         if (plugin && plugin->priv) {
125                 if (plugin->priv->usb_plugged) {
126                         gtk_widget_show(GTK_WIDGET(plugin));
127                 } else {
128                         gtk_widget_hide(GTK_WIDGET(plugin));
129                 }
130         }
131 }
132
133 static void mtetherd_status_plugin_log(const gchar *domain, GLogLevelFlags level, const gchar *message, gpointer data) {
134         MTetherDStatusPlugin *plugin = MTETHERD_STATUS_PLUGIN(data);
135
136         if (plugin && plugin->priv && plugin->priv->log_fp) {
137                 char *levelstr;
138                 switch (level) {
139                         case G_LOG_LEVEL_ERROR:
140                                 levelstr = "** Error **";
141                                 break;
142                         case G_LOG_LEVEL_CRITICAL:
143                                 levelstr = "** CRITICAL **";
144                                 break;
145                         case G_LOG_LEVEL_WARNING:
146                                 levelstr = "** Warning **";
147                                 break;
148                         case G_LOG_LEVEL_MESSAGE:
149                                 levelstr = "-- Notice --";
150                                 break;
151                         case G_LOG_LEVEL_INFO:
152                                 levelstr = "-- Info --";
153                                 break;
154                         case G_LOG_LEVEL_DEBUG:
155                                 levelstr = "(Debug)";
156                                 break;
157                         case G_LOG_FLAG_RECURSION:
158                                 levelstr = "** RECURSION **";
159                                 break;
160                         case G_LOG_FLAG_FATAL:
161                                 levelstr = "** FATAL **";
162                                 break;
163                         default:
164                                 levelstr = "";
165                                 break;
166                 }
167                 g_fprintf(plugin->priv->log_fp, "mtetherd: %s %s\n", levelstr, message);
168                 fflush(plugin->priv->log_fp);
169         }
170 }
171
172 static void mtetherd_status_plugin_init(MTetherDStatusPlugin *plugin) {
173         plugin->priv = MTETHERD_STATUS_PLUGIN_GET_PRIVATE(plugin);
174
175         if (plugin->priv) {
176                 plugin->priv->log_fp = fopen(TMP_DIR "/mtetherd-status.log", "a");
177                 if (plugin->priv->log_fp) {
178                         plugin->priv->log_handler = g_log_set_handler(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_MASK, mtetherd_status_plugin_log, plugin);
179                 }
180                 
181                 plugin->priv->usbnet_state = FALSE;
182                 plugin->priv->enable_button = hildon_button_new(HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT, HILDON_BUTTON_ARRANGEMENT_VERTICAL);
183                 if (plugin->priv->enable_button) {
184                         GError *err = NULL;
185                         GdkPixbuf *icon = gdk_pixbuf_new_from_file(IMAGE_DIR "/mtetherd-net-icon.png", &err);
186                         if (err) {
187                                 g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Can't load mtetherd icon: %s", err->message);
188                                 g_error_free(err);
189                                 err = NULL;
190                         }
191                         if (icon) {
192                                 GtkWidget *image = gtk_image_new_from_pixbuf(icon);
193                                 hildon_button_set_image(HILDON_BUTTON(plugin->priv->enable_button), image);
194                                 hildon_button_set_image_position(HILDON_BUTTON(plugin->priv->enable_button), GTK_POS_LEFT);
195                                 gtk_button_set_alignment(GTK_BUTTON(plugin->priv->enable_button), 0, 0.5);
196                                 g_object_unref(icon);
197                         }
198                         mtetherd_status_plugin_enable_button_set_text(plugin);
199                         g_signal_connect(plugin->priv->enable_button, "clicked", G_CALLBACK(mtetherd_status_plugin_enable_button_clicked), plugin);
200                         gtk_container_add(GTK_CONTAINER(plugin), plugin->priv->enable_button);
201                         gtk_widget_show_all(plugin->priv->enable_button);
202                 }
203         
204                 if (mtetherd_hal_init(plugin)) {
205                         plugin->priv->devices = mtetherd_device_list_new();
206                         mtetherd_hal_device_scan(plugin);
207                         // Set initial button status
208                         mtetherd_status_plugin_usb_plugged(plugin);
209                 } else {
210                         // For debugging
211                         plugin->priv->usb_plugged = TRUE;
212                         mtetherd_status_plugin_usb_plugged_show(plugin);
213                 }
214         }
215
216         //hildon_banner_show_informationf(GTK_WIDGET(plugin), NULL, "Initialized mtetherd status plugin");
217         g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, "Initialized mtetherd status plugin");
218 }
219
220 void mtetherd_status_plugin_device_added(MTetherDStatusPlugin *plugin, MTetherDDevice *device) {
221         g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "mtetherd_status_plugin_device_added(%p, %p)", plugin, device);
222         gboolean added = FALSE;
223         if (plugin && plugin->priv) {
224                 const gchar *interface = mtetherd_device_get_interface(device);
225                 g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "interface=%s", interface);
226                 if (mtetherd_device_ok(interface)) {
227                         g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "ok");
228                         if (mtetherd_device_list_add(plugin->priv->devices, device)) {
229                                 if (g_strcmp0(USBNET_INTERFACE, interface) == 0) {
230                                         g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "is USB");
231                                         plugin->priv->usbnet_state = TRUE;
232                                         mtetherd_status_plugin_enable_button_set_text(plugin);
233                                 }
234                                 hildon_banner_show_informationf(GTK_WIDGET(plugin), NULL, "Starting network on %s", interface);
235                                 g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Launching %s", SBIN_DIR "/mtetherd-net-setup.sh");
236                                 gchar *addr = mtetherd_device_get_addr(device);
237                                 gchar *netmask = mtetherd_device_get_netmask(device);
238                                 gchar *dhcp_start = mtetherd_device_get_dhcp_start(device);
239                                 gchar *dhcp_end = mtetherd_device_get_dhcp_end(device);
240                                 g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "interface=%s wan=%s addr=%s netmask=%s dhcp_start=%s dhcp_end=%s", interface, WAN_INTERFACE, addr, netmask, dhcp_start, dhcp_end);
241                                 const char *command[] = { BIN_DIR "/sudo", SBIN_DIR "/mtetherd-net-setup.sh", interface, WAN_INTERFACE, addr, netmask, dhcp_start, dhcp_end, NULL };
242                                 if (!mtetherd_launch_script(command)) {
243                                         g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Error launching USB networking setup script");
244                                 }
245                                 g_free(addr);
246                                 g_free(netmask);
247                                 g_free(dhcp_start);
248                                 g_free(dhcp_end);
249                                 g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "done");
250                                 added = TRUE;
251                         } else {
252                                 g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Error adding network interface to list: Maximum number of devices exceeded");
253                         }
254                 }
255         }
256         if (!added) {
257                 g_object_unref(G_OBJECT(device));
258         }
259 }
260
261 void mtetherd_status_plugin_device_removed(MTetherDStatusPlugin *plugin, const gchar *udi) {
262         g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "mtetherd_status_plugin_device_removed(%s)", udi);
263         if (plugin && plugin->priv) {
264                 MTetherDDevice *device = mtetherd_device_list_find(plugin->priv->devices, udi);
265                 if (device) {
266                         g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "device=%p", device);
267                         const gchar *interface = mtetherd_device_get_interface(device);
268                         g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "interface=%s", interface);
269                         if (g_strcmp0(USBNET_INTERFACE, interface) == 0) {
270                                 g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "is USB");
271                                 plugin->priv->usbnet_state = FALSE;
272                                 mtetherd_status_plugin_enable_button_set_text(plugin);
273                         }
274                         hildon_banner_show_informationf(GTK_WIDGET(plugin), NULL, "Shutting down network on %s", interface);
275                         g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Launching %s", SBIN_DIR "/mtetherd-net-shutdown.sh");
276                         // TODO: Check if this is the last interface to be shut down and pass WAN_INTERFACE after interface if yes
277                         const char *command[] = { BIN_DIR "/sudo", SBIN_DIR "/mtetherd-net-shutdown.sh", interface, NULL };
278                         if (!mtetherd_launch_script(command)) {
279                                 g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Error launching USB networking shutdown script");
280                         }
281                         g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "done");
282                 }
283                 if (!mtetherd_device_list_remove(plugin->priv->devices, udi)) {
284                         g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Device %s not found in list, nothing removed", udi);
285                 } else {
286                         g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Device %s removed from list", udi);
287                 }
288         }
289 }
290
291 void mtetherd_status_plugin_usb_plugged(MTetherDStatusPlugin *plugin) {
292         plugin->priv->usb_plugged = mtetherd_usb_state(plugin);
293         g_log(MTETHERD_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "USB plugged status: %s", plugin->priv->usb_plugged ? "on" : "off");
294         mtetherd_status_plugin_usb_plugged_show(plugin);
295 }
296