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