Today there was another Linux meeting in SL. Tofu Linden’s presence was much appreciated, but it turns out that the file upload dialog that will be added to the Linux client will be the GTK2 one. While I welcome Linux client improvements a lot (Thanks, Tofu!), I just happen to dislike the GTK dialog quite a lot.
So I went and hacked in my own.
Update: added link to source
Now, while SL is unfortunately closed source, that doesn’t mean I can’t mess with it a bit. Thanks to the way libraries work in Linux, it’s possible to preload a library and override a function or two provided by some other library.
SL already has a rudimentary upload system. If you try to upload an image, it looks for a file called “upload.tga”, and if it’s there it tries to upload it. Uploading a bunch of files like this is a pain though. Now, before it can upload the file it must open it and read the data from it, so if I could catch this moment and stick a dialog in there, the situation could perhaps be improved.
First, I tried to find a good function to override. Attempts to ltrace the executable were unfortunately unsuccessful. If I attached ltrace to the running process, SL crashed almost immediately. Trying to ltrace it from the beginning resulted in it running really slowly, and I’m not that patient. So I decided to try something else.
Most Linux distributions come with a very helpful command, “nm”, which lists an object’s symbols. By using this we can tell which functions the SL binary calls. So I ran nm on it, and searched for functions that had “open” in the name, as SL would have to open the file before it could upload it.
dale@alice ~/SL/main/bin $ nm do-not-directly-run-secondlife-bin | grep open
091d80ec T _Z10open_offerRKSt6vectorI6LLUUIDSaIS0_EE
0964ef10 T _Z10shell_openPKc
08768cb4 T _Z11is_openableN11LLAssetType5ETypeE
0992d5b2 T _Z12open_circuitP15LLMessageSystemPPv
0887a71c T _Z12open_textureRK6LLUUIDRK12LLStringBaseIcEiS1_
(lots of other junk)
09a1c1b8 T jpeg_open_backing_store
Here we have two promising functions, “apr_file_open”, and “fopen”. By writing and compiling a little C library I experimentally determined that it was “apr_file_open”. The way this is done is by writing a function with the same name, return value and arguments as the one we want to replace. Then, we compile the result and preload it, and our code runs instead of the original. Since simply replacing the function would break SL, I also call the original version from my replacement.
The code is simple: The function checks whether the file SL is about to open ends in “/upload.tga”. If it does, then my replacement function calls an external script, passes it the full filename as an argument, and after it returns calls the original apr_file_open function.
The script, in turn, calls kdialog, a handy program that among other things can be made to display a KDE file dialog, then output the selected filename on stdout. If you don’t like KDE, there are other programs of this kind you could use instead, like zenity.
Now things work like this:
- SL tries to open upload.tga
- I detect this, and call my script
- The script runs the file dialog, then uses convert from ImageMagick to convert the selected file to TGA
- The script returns
- My apr_file_open replacement calls the original function
- SL now opens upload.tga, which has the contents of the file the user selected
This is still not done, as it only handles image uploads so far, but I think it’s a pretty good start.
Here’s the source code. This is a bit improved from what I posted on the Linux forum. It’s got comments, and should be a bit easier to understand.
Comments and suggestions are welcome.