Although the patch is not upstream, here's a quick post mortem on how it evolved.
Setting the stage
As a newbie in Gnome-development, I used this info on the Gnome Wiki to get a head start. I preferred Eclipse over anjuta because I'm already familiar with it. I had to install the following Ubuntu packages for being able to compile Network Manager:
autotools libtool libgtk-3-dev libclutter-1.0-dev libgda-4.0-dev libgconf2-dev intltool gtk-doc-tools libdbus-glib-1-dev libgudev-1.0-dev libnl-dev uuid-dev libnss3-dev ppp-dev libgnome-keyring-dev libnotify-dev
Getting & building the Network Manager and Network Manager applet (nm-applet) from source is described on their wiki. For installing to a workspace directory, I used this configure line with Network Manager:
./autogen.sh --prefix=/home/dom/workspace/NetworkManager --sysconfdir=/etc --localstatedir=/var
Telling nm-applet to link against the custom Network Manager required these build steps:
export PKG_CONFIG_PATH=/home/dom/git/NetworkManager:/home/dom/workspace/NetworkManager/lib/pkgconfig./autogen.sh --prefix=/home/dom/workspace/nm-applet --sysconfdir=/etc --localstatedir=/var
For running the modified versions, the Ubuntu-packaged ones have to be killed before.
Finding the hooks
After successfully running my custom-build versions I could start hacking. The mounting was to be done as the current session user (to be able to use the stored credentials). As the Network Manager daemon runs as root, I looked at the nm-applet source. At first I was looking for a single point of code where the connection events (connect/disconnect) occur. As far as I can tell, there is none (in the applet). So I dived into the connection-type-specific sources, which is applet-device-wifi.c for WiFi.
I isolated the wireless_device_state_changed function to be the most reliable place for getting the WiFi connect/disconnect events. For testing, I triggered shell scripts that would already mount/unmount network drives.
Mounting & unmounting the drives
While the shell scripts were an easy solution, they're not quite easy to maintain with a GUI, and not easy to package. So in the next step, I replaced the scripts with using the gvfs API directly.
The scripts would work with a URI, such as smb://server/share (passed to the gvfs-mount command). The hardest part was finding a way to mount such a URI using the API: gvfs contains quite some layers of abstraction, and only GFile provides a way of creating an object using such a URI. It figured out that g_file_mount_enclosing_volume was the function I was looking for. For unmounting, finding g_file_find_enclosing_mount and g_mount_unmount_with_operation were rather easy now.
So I could now mount fixed network drives upon WiFi connect.
GUIifaction...
Mounting fixed drives was nice for my own use, but for real live the next TODO was enhancing the connection editor with appropriate settings. Using glade, the interface was quickly built. Integrating it into the applet was a matter of copy & paste (I used the IPv4 page as copy-base, as it also provides a table).
The only thing that took a while was the dropdown for the supported protocols within the table.
... and the quest for persistent settings
I now had a table view that could edit the network drives to be auto-mounted - now I had to persist the settings. To keep things simple, I decided to not store individual columns, but assemble them into the URIs that are required for mounting. So each row is basically just one string - and the table itself is an array of strings. nm-applet does not store the connection configurations itself, but passes them to the Network Manager daemon via dbus to have them stored there (which makes a lot of sense).
So I had to pass the array of URI strings via dbus to Network Manager, where I had to take them and persist them with the other configuration settings. This is where I really missed collection data types and built-in serialization that Java or C#/.NET provide... it cost me hours finding the right dbus data type and getting all the tiny code fragments right.
Now I could edit network drives in the GUI, they would be mounted on connect and unmounted on disconnect.
Making it human
So it worked now, but it requires an advanced user to actually use the connection editor. Thinking a while on a more intuitive solution, I came up with capturing manual mount events and then asking if they should be persisted. Implementing this was fun: Everything worked as expected quite quickly.
But wait: Why do I have to enter the WPA key every time I added/removed a network drive this way?
Solving this took really long: In the connection editor, the network drives are persisted with the other settings - I could just "backpack" them. Modifying them outside the connection editor meant I had to write code for persisting them on my own - which was really straightforward in the first place.
The network credentials, though, are stored in some special way - they have to fetched separately via dbus. If the network settings are saved without fetching and re-adding the credentials, they're overwritten. The code for getting this right required a callback chain that is not trivial. And as soon as it worked, I started receiving segfaults. It was only with the support of gicmo, an experienced Gnome coder, that I was able to use gdb ("thread apply all bt full") and valgrind to identify the memory leak.
This is also the reason the patch only works with WiFi-connections at the moment: For every other connection type, it has to be determined if there are secret settings stored this way. If so, fetching and re-adding those has to be implemented.
The result
Here's some screenshots of how the patch looks like:
No comments:
Post a Comment