<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="FeedCreator 1.7.6(BH)" -->
<rss version="2.0">
    <channel xmlns:g="http://base.google.com/ns/1.0">
        <title>Planet Maemo: category &quot;feed:db85272b5cc4c48c874836930690af4e&quot;</title>
        <description>Blog entries from Maemo community</description>
        <link>http://maemo.org/news/planet-maemo/</link>
        <lastBuildDate>Sun, 05 Apr 2026 10:13:58 +0000</lastBuildDate>
        <generator>FeedCreator 1.7.6(BH)</generator>
        <language>en</language>
        <managingEditor>planet@maemo.org</managingEditor>
        <item>
            <title>Like a Bird on a Wire(shark)...</title>
            <link>http://monkeyiq.blogspot.com/2013/07/like-bird-on-wireshark.html</link>
            <description><![CDATA[
Over recent years, libferris has been using Qt to mount some Web stuff as a filesystem. I have a subclass of QIODevice which acts as an intermediary to allow one to write to a std::ostream and stream that data to the Web, over a POST for example. For those interested, that code is in Ferris/FerrisQt.cpp of the tarball. It's a bit of a shame that Qt heavy web code isn't in KIO or that the two virtual filesystems are not closer linked, but I digress.<br />
<br />
I noticed a little while ago that cp to vimeo://upload didn't work anymore. I had earmarked that for fixing and recently got around to making that happen. It's always fun interacting with these Web APIs. Over the time I've found that Flickr sets the bar for well documented APIs that you can start to use if you have any clue about making GET and POST etc. At one stage google had documented their API in a way that you could never use it. I guess they have fixed that by now, but it did sort out the pretenders from those two could at least sniff HTTP and were determined to win. The vimeo documentation IIRC wasn't too bad when I added support to upload, but the docs have taken a turn for the worst it seems. Oh, one fun tip for the young players, when one API call says "great, thanks, well done, I've accepted your call" and then a subsequent one says "oh, a strange error has happened", you might like to assume that the previous call might not have been so great after all.<br />
<br />
So I started tinkering around, adding oauth to the vimeo signup, and getting the getTicket call to work. Having getTicket working meant that my oauth signed call was accepted too. I then was then faced with the upload of the core data (which is normally done with a rather complex streaming POST), and the final I'm done, make it available call. On vimeo that last call seems to be two calls now, first a VerifyChunks call and then a Complete call.<br />
<br />
So, first things first. To upload you call getTicket which gives you an endpoint that is an HTTP URL to send the actual video data to, as well as an upload ticket to identify the session. If you try to post to that endpoint URL and the POST converts the CGI parameters using multipart/form-data with boundaries into individual Content-Disposition: form-data elements, you loose. You <i>have to have</i> the ticket_id in the URL after the POST text in order to upload. One little trap.<br />
<br />
So then I found that verifyChunks was returning&nbsp;<a href="https://developer.vimeo.com/apis/advanced/methods/vimeo.videos.upload.verifyChunks" target="_blank">Error 709</a> Access to the chunk list failed. And that was after the upload had been replied to with "OK. Thanks for the upload.". Oddly, I also noticed that the upload of video data would hang from time to time. So I let the shark out of the pen again, and found that vimeo would return it's "yep were done, all is well" response to the HTTP POST call at about 38-42kb into the data. Not so great.<br />
<br />
Mangling the vimeo.php test they supply to upload with my oauth and libferris credentials I found that the POST had a header Expect: 100-continue. Right after the headers were sent vimeo gave the nod to continue, and then the POST body was sent. I assume that just ploughing through and giving the headers followed by the body confused the server end and thus it just said "yep, ok, thanks for the upload" and dropped the line. Then of course forgot the ticket_id because there was no data for it, so the verifyChunks got no chunk list and returned the strange error it did. mmm, hindsight!<br />
<br />
So I ended up converting from the POST the newly available PUT method for upload. They call that their "streaming API" even though you can of course stream to a POST endpoint. You just need to frame the parameters and add the MIME tailer to the POST if you want to stream a large file that way. Using PUT I was then able to verify my chunks (or the one single chunk in fact) and the upload complete method worked again.<br />
<br />
In the end I've added oauth to my vimeo mounting, many thanks to the creators of the&nbsp;<a href="http://files.ayoy.net/qoauth/1.0.1/doc/" target="_blank">QOAuth library!</a><br />
<span class="net_nemein_favourites">2 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=1e2f19b9c5d7420f19b11e2902843c791e2c7a7c7a7&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/1e2f19b9c5d7420f19b11e2902843c791e2c7a7c7a7/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=1e2f19b9c5d7420f19b11e2902843c791e2c7a7c7a7&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/1e2f19b9c5d7420f19b11e2902843c791e2c7a7c7a7/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Ben Martin &lt;monkeyiq@users.sourceforge.net&gt;</author>
            <category>feed:db85272b5cc4c48c874836930690af4e</category>
            <pubDate>Sat, 20 Jul 2013 17:10:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-1e2f19b9c5d7420f19b11e2902843c791e2c7a7c7a7</guid>
        </item>
        <item>
            <title>Save Ferris: Show some love for libferris...</title>
            <link>http://monkeyiq.blogspot.com/2013/05/save-ferris-show-some-love-for-libferris.html</link>
            <description><![CDATA[
Libferris has been gaining some KDE love in recent times. There is now a KIO slave to allow you to see <a href="http://monkeyiq.blogspot.com.au/2012/11/libferris-as-kio-slave.html">libferris from KDE</a>, also the ability to get at <a href="http://monkeyiq.blogspot.com.au/2010/05/plasma-libferris-and-google.html">libferris from plasma</a>.<br />
<br />
I've been meaning to update the mounting of some Web services like vimeo for quite some time. I'd also like to expand to allow mounting google+ as a filesystem and add other new Web services.<br />
<br />
In order to manage time so that this can happen quicker, I thought I'd try the waters with a <a href="http://pledgie.com/campaigns/20036">pledgie</a>. I've left this open ended rather than sticking an exact "bounty" on things. I had the idea of trying a pledgie with my recent investigation into the libferris indexing plugins on a small form factor ARM machine. I'd like to be able to spend more time on libferris, and also pay the rent while doing that, so I thought I'd throw the idea out into the public.<br />
<br />
If you've enjoyed the old tricks of mounting XML, Berkeley DB, SQLite, PostgreSQL and other relational databases, flickr, google docs, identica, and others and want to see more then please support <a href="http://pledgie.com/campaigns/20036">the pledgie</a> to speed up continued development. Enjoy libferris!<br />
<br />
<a href="http://www.pledgie.com/campaigns/20036"><img a="" along="" alt="Click here to lend your support to: Save Ferris: Show some love for libferris and help kick it" and="" at="" border="0" development="" donation="" make="" s="" src="http://www.pledgie.com/campaigns/20036.png?skin_name=chrome" www.pledgie.com="" /></a>
<br />
<br /><span class="net_nemein_favourites">0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=1e2b7bf8952051eb7bf11e29d2625794213fdf6fdf6&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/1e2b7bf8952051eb7bf11e29d2625794213fdf6fdf6/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=1e2b7bf8952051eb7bf11e29d2625794213fdf6fdf6&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/1e2b7bf8952051eb7bf11e29d2625794213fdf6fdf6/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Ben Martin &lt;monkeyiq@users.sourceforge.net&gt;</author>
            <category>feed:db85272b5cc4c48c874836930690af4e</category>
            <pubDate>Wed, 08 May 2013 01:57:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-1e2b7bf8952051eb7bf11e29d2625794213fdf6fdf6</guid>
        </item>
        <item>
            <title>Cross platform package building..?</title>
            <link>http://monkeyiq.blogspot.com/2012/12/cross-platform-package-building.html</link>
            <description><![CDATA[
Sorry for the chatter post, but if anybody has recommendations for a tool that can build for win, osx, and lin that would be great. The project is an autofools one, mainly coded in 100s of kloc of C++. Builds like a treat on a Fedora machine, can be beaten unto submission to build on osx, and I assume on a suitably tainted windows machine it will gcc into binaries too. At least it has built on those other platforms in the past.<br />
<br />
I've had great success with OBS, but that was mainly for Linux packages. It seems OBS can do mingw too, but I've not walked the valley of darkness into building for the more closed platforms on OBS before.<br />
<br />
The saucelabs looks pretty cool, but it seems targeted to web code if I am reading it correctly.<br />
<br />
The initial plan is to get 24hr rolling packages for all platforms and have feedback as to which day a github commit has broken the package build. It might be nice to have it for each github commit, but I think it would be easy enough to bisect a break given a 24 hour window unless an armada of contributors rushes at the ship.<br />
<br />
A separate build issue I've been tinkering with in my mind for a while is 
grabbing from a github repo and creating android packages. Different code base for this though, mainly some of my n9 apps, as such, preferably for a 
mixed C++/QML app. But I think for that project I'll wind up taking my 
chisel and hammer and coming back with a cron job. <br />
<br />
<br />
<span class="net_nemein_favourites">1 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=4a88d58a465211e2a82b0398f11a07ca07ca&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/4a88d58a465211e2a82b0398f11a07ca07ca/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>1 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=4a88d58a465211e2a82b0398f11a07ca07ca&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/4a88d58a465211e2a82b0398f11a07ca07ca/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Ben Martin &lt;monkeyiq@users.sourceforge.net&gt;</author>
            <category>feed:db85272b5cc4c48c874836930690af4e</category>
            <pubDate>Fri, 14 Dec 2012 15:53:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-4a88d58a465211e2a82b0398f11a07ca07ca</guid>
        </item>
        <item>
            <title>Off the Record Messaging: A Tutorial</title>
            <link>http://monkeyiq.blogspot.com/2012/07/off-record-messaging-tutorial.html</link>
            <description><![CDATA[
OK, a rather long post about effective digital communication. Hopefully an interesting read to folks who would like to add some code to protect communications but haven't gotten around to that TODO item just yet.<br />
<br />
A commonly used method for sending messages to others when you need
  authentication and privacy is to use an OpenPGP tool such as GNU
  Privacy Guard (GnuPG). For real time communications such as instant
  messaging, IRC, and socket IO, using Off The Record (OTR) messaging
  provides <a href="http://en.wikipedia.org/wiki/Perfect_forward_secrecy">Perfect
  Forward Secrecy</a> and secure identification of the remote party
  without the need for a web of trust.<br />
<br />
In order to operate without a web of trust, <a href="http://www.cypherpunks.ca/otr/">libotr</a> implements the
  Socialist Millionaires' Protocol (SMP). The SMP allows two parties
  to verify that they both know the same secret. The secret might be a
  passphrase or answer to a private joke that two people will easily
  know. The SMP operates fine in the presence of eaves droppers (who
  don't get to learn the secret). Active communications tampering is
  not a problem, though of course it might cause the protocol not to
  complete successfully.<br />
<br />
Because the SMP doesn't rely on the fingerprint of the user's
  private key for authentication, the private key becomes almost an
  implementation detail. Once generated, the user generally doesn't
  need to know about the key or it's fingerprint. The only time a user
  really cares to know is when a key is created because a bit of
  entropy has to go into that process. Of course, an application
  should avoid regenerating keys for no reason because each time the
  key is replaced the user has to use the SMP again to allow remote
  parties to authenticate them.<br />
<br />
In this article I'll show you how to use the current release, libotr
  3.2.0+, to provide OTR messaging. I'll present two examples which
  are both in C++ and use the boost library for socket IO. I have gone
  this was so we can focus on the OTR action and not the details of
  sockets.<br />
<br />
The first example does not use the Socialist Millionaires' Protocol
  (SMP). So the new_fingerprint() callback is essential to
  establishing a secure session. When not using the SMP,
  authentication is performed by comparing the sent fingerprints of
  those you are wishing to communicate with against known good values.
  These known values must be sent beforehand through a secure
  secondary channel, such as a face to face meeting. Once fingerprints
  have been accepted, subsequent OTR communications with the same
  party can be performed without explicit fingerprint verification.<br />
<br />
The second example makes things simpler for the user by using the
  SMP for authentication of the remote party. This way, the
  information exchanged beforehand becomes shared experiences you and
  the other party have had such that a question can be raised that
  only you and they can easily answer.<br />
A central abstraction in using the libotr library is the struct
  s_OtrlMessageAppOps vtable. This is used by libotr to callback into
  your code when something happens such as a cryptographic fingerprint
  being received, or libotr wanting to send a message to the other
  end. The later happens frequently during OTR session establishment.<br />
<br />
If a program monitors it's socket IO using select() or some other
  mainloop abstraction, then having these internal protocol messages
  being sent is not so much of an issue. Alas, for the simple echo
  server I present one must remember that there might be one or more
  internal OTR protocol messages sent from what seems like outside of
  the normal program flow. I'll get back to this point while
  describing the relevant section of the first example.<br />
<br />
Many of the callback functions in s_OtrlMessageAppOps might be
  simple stubs, but you should be aware of inject_message() which will
  be called when libotr itself wants to send something, notify and
  display_otr_message can both provide feedback to the user, the
  new_fingerprint() method is called when a remote key is discovered
  in order to allow you to inform the user and possibly abort the
  session. The gone_secure() method is called to allow you to inform
  the user that they are off the record. When you call libotr
  functions you supply both a pointer to a s_OtrlMessageAppOps
  structure <tt>uiops</tt> and a void* <tt>opdata</tt>. When libotr calls a method
  in uiops it will pass <tt>opdata</tt> back to you.<br />
<br />
Another common three parameters you will pass to libotr functions
  are the accountname, protocol and sender or receiver name. The
  protocol string can be anything as long as both ends of the system
  use the same protocol string. The state data that libotr uses is
  stored in an OtrlUserState object which is created with
  otrl_userstate_create() and passed to many of the libotr functions
  along the way.<br />
<br />
The code below loads a private key or creates a new one if none
 already exists. Because creating a new key is an entropy heavy
 operation, the setupKey() function warns the user that if they are
 erratic it the process might move along a bit quicker. Note that the
 uiops has a callback create_privkey to generate a key if needed. I
 just prefer to make this codepath explicit and out of the main
 callback logic.
<br />
<br />
<pre>&nbsp;bool ok( gcry_error_t et )
{
    return gcry_err_code(et) == GPG_ERR_NO_ERROR;
}

void setupKey( const std::string&amp; filename )
{
    gcry_error_t et;
    
    et = otrl_privkey_read( userstate, filename.c_str() );
    if( !ok(et) )
    {
        cerr &lt;&lt; "can't find existing key, generating a new one!" &lt;&lt; endl;
        cerr &lt;&lt; "this needs a bunch of entropy from your machine... so please" &lt;&lt; endl;
        cerr &lt;&lt; "move the mouse around and slap some keys mindlessly for a while" &lt;&lt; endl;
        cerr &lt;&lt; "a message will be printed when keys have been made..." &lt;&lt; endl;
        et = otrl_privkey_generate( userstate, filename.c_str(),
                                    accountname, protocol );
        if( !ok(et) )
        {
            cerr &lt;&lt; "failed to write new key file at:" &lt;&lt; filename &lt;&lt; endl;
        }
        cerr &lt;&lt; "Have keys!" &lt;&lt; endl;
    }
}</pre>
<br />The main.cpp program implements both the client and server. The
  server mode is selected by passing -s at startup. Firstly, a
  userstate is created, some variables set depending on if we are a
  client or server, and the correct private key is loaded or created.<br />
<br />
<pre>    OTRL_INIT;
    userstate = otrl_userstate_create();

    keyfile = "client.key";
    accountname = "client";
    recipientname = "server";
    if( ServerMode )
    {
        keyfile = "server.key";
        accountname = "server";
        recipientname = "client";
    }
    setupKey( keyfile );
</pre>
<br />
The core logic for the echo client is to read a string from the user, send it to the
  server, grab a reply from the server and show it to the user.
  The start of the client code connects to a given port on localhost
  and reads a string from the user.<br />
<br />
<pre>        VMSG &lt;&lt; "client mode..." &lt;&lt; endl;
        stringstream portss;
        portss &lt;&lt; Port;
        iosockstream stream( "127.0.0.1", portss.str() );
        if (!stream)
        {
            cerr &lt;&lt; "can't connect to server!" &lt;&lt; endl;
            exit(1);
        }

        string s;
        while( true )
        {
            getline(cin,s);
            cerr &lt;&lt; "your raw message:" &lt;&lt; s &lt;&lt; endl;
            cerr &lt;&lt; "send plaintext:" &lt;&lt; colorsend(s) &lt;&lt; endl;</pre>
<pre></pre>
<br />
We certainly do not want to send the raw string <tt>s</tt> over the wire to
  the server though. That would very much be "on the record". So the
  next fragment of the client gets libotr to encrypt the string <tt>s</tt> so
  we can send it off the record to the server. The userstate is the
  value created during program initialization using
  otrl_userstate_create(). The ui_ops is the vtable
  s_OtrlMessageAppOps structure described above, and opdata is the
  value we want libotr to pass back to our methods in ui_ops when it
  uses them. In this case, we use the address of the iostream for the socket as the
  opdata so callbacks can send and receive data on the socket if they
  so desire. The newmessage will point to an off-the-record message
  that the server can decrypt to read the string <tt>s</tt>. The tests on the
  return value for message_sending() ensure that we have a new,
  encrypted off the record message to send instead of the plaintext
  <tt>s</tt>.<br />
<br />
<pre>&nbsp;void* opdata = &amp;stream;
OtrlTLV* tlvs = 0;
gcry_error_t et;
char* newmessage;

void* opdata = &amp;stream;
OtrlTLV* tlvs = 0;
gcry_error_t et;
char* newmessage;

et = otrl_message_sending( userstate, &amp;ui_ops, opdata,
                           accountname, protocol, recipientname,
                           s.c_str(), tlvs, &amp;newmessage,
                           myotr_add_appdata, &amp;ui_ops );
cerr &lt;&lt; "encoded... ok:" &lt;&lt; ok(et) &lt;&lt; endl;
if( !ok(et) )
{
    cerr &lt;&lt; "OTR message_sending() failed!" &lt;&lt; endl;
}
if( ok(et) &amp;&amp; !newmessage )
{
    cerr &lt;&lt; "There was no error, but an OTR message could not be made." &lt;&lt; endl;
    cerr &lt;&lt; "perhaps you need to run some key authentication first..." &lt;&lt; endl;
}
if( newmessage )
{
    VMSG &lt;&lt; "have new OTR message:" &lt;&lt; newmessage &lt;&lt; endl;
    s = newmessage;
}</pre>
<pre>&nbsp;</pre>
Since we have replaced the plaintext <tt>s</tt> with the off the record
  version, we send that to the server using the socket iostream and
  then wait a moment before reading a response. The while loop is
  slightly hairy in that it will block for new messages if we are not
  secure. As I mentioned above, libotr can call the inject_message()
  callback to write a new off the record message to the socket.
  Outgoing messages will be generated and injected during session
  establishment. There is no incoming version of inject_message() so
  the client needs to keep reading these injected messages before it
  tries to send another off the record message. One will find that
  there are many messages exchanged between libotr at each end when
  the string <tt>s</tt> is written to the socket. This only happens the first
  time through to setup the OTR protocol.<br />
<br />
When reading messages from the server, the encrypted string is read
  and passed to otrl_message_receiving(). If the recevied message was
  an OTR message that was sent from the other end by libotr using
  inject_message() then otrl_message_receiving() will indicate to the
  client that it should simply ignore this message. Otherwise a real
  message was encrypted and sent by the server and so the client will
  show the user the decrypted newmessage.<br />
<br />
<br />
<pre>&nbsp;cerr &lt;&lt; "WRITE:" &lt;&lt; s &lt;&lt; endl;
stream &lt;&lt; s &lt;&lt; endl;
usleep( 200 * 1000 );
while( !secure &amp;&amp; stream.peek() != std::iostream::traits_type::eof()
       || secure &amp;&amp; stream.rdbuf()-&gt;available() )
{
    s = "junk";
    VMSG &lt;&lt; "reading data from server" &lt;&lt; endl;
    getline(stream,s);
    VMSG &lt;&lt; "READ:" &lt;&lt; s &lt;&lt; endl;

    int ignore_message = otrl_message_receiving(
        userstate, &amp;ui_ops, opdata,
        accountname, protocol, recipientname,
        s.c_str(),
        &amp;newmessage,
        &amp;tlvs,
        myotr_add_appdata, &amp;ui_ops );

    VMSG &lt;&lt; "ignore:" &lt;&lt; ignore_message &lt;&lt; " newmsg:" &lt;&lt; maybenull(newmessage) &lt;&lt; endl;
    if( ignore_message )
    {
        VMSG &lt;&lt; "libotr told us to ignore this message..." &lt;&lt; endl;
        VMSG &lt;&lt; "available:" &lt;&lt; stream.rdbuf()-&gt;available() &lt;&lt; endl;
        VMSG &lt;&lt; " in_avail:" &lt;&lt; stream.rdbuf()-&gt;in_avail() &lt;&lt; endl;
        
        continue;
    }
    if( newmessage )
        s = newmessage;
    otrl_message_free( newmessage );

    cout &lt;&lt; color( s ) &lt;&lt; endl;
}</pre>
<pre>&nbsp;</pre>
Server mode is handled by a thread which executes server_session()
using the std::iostream for the new socket.<br />
<br />
<pre>if( ServerMode )
{
    VMSG &lt;&lt; "server mode..." &lt;&lt; endl;

    boost::asio::io_service io_service;
    tcp::acceptor a( io_service, tcp::endpoint( tcp::v4(), Port ));
    for (;;)
    {
        h_iosockstream stream(new iosockstream());
        a.accept( *(stream-&gt;rdbuf()) );
        boost::thread t(boost::bind(server_session, stream));
    }
}</pre>
<br />The server implementation would look like the below if OTR messaging
was not being used.<br />
<br />
<pre>void server_session( h_iosockstream streamptr )
{
    iosockstream&amp; stream = *(streamptr.get());
    while( stream )
    {
       std::string s;
       getline( stream,s );
       cout &lt;&lt; "server got:" &lt;&lt; s &lt;&lt; endl;
       stream &lt;&lt; s &lt;&lt; endl;
    }
}</pre>
<pre>&nbsp;</pre>
The OTR server implementation starts out the same way, reading a
  string from the socket. Then our old friend otrl_message_receiving()
  is called to decrypt that message. If ignore_message is set then
  there is nothing to be done and we simply continue to the top of the
  loop to read another string from the client. Also, if we are not yet
  secure, there is no point in trying to send a new OTR message back
  to the client, so we simply continue at the top of the while loop
  again. This way we avoid writing replies to the client when session
  establishment messages are sent by libotr on the client side.<br />
<br />
This might seem a little strange at first, how will we ever become
  secure and start replying to the client if all we do is read from
  them and throw away the messages. The thing to keep in mind is that
  messages sent with inject_message() on the client will be seen by
  libotr when we call otrl_message_receiving() which in turn might
  cause libotr on the server to inject_message() with a reply to this
  session establishment message. Eventually libotr will call the
  gone_secure() OtrlMessageAppOps callback in which we set the global
  variable <tt>secure</tt> to true, this allowing the server to start replying to the
  client as it normally would.<br />
<br />
<pre>void server_session( h_iosockstream streamptr )
{
    iosockstream&amp; stream = *(streamptr.get());
    while( stream )
    {
        gcry_error_t et;
 std::string s;
 VMSG &lt;&lt; "getting more data from the client..." &lt;&lt; endl;
 getline( stream,s );
 VMSG &lt;&lt; "READ:" &lt;&lt; s &lt;&lt; endl;
                    
 void* opdata = &amp;stream;
 OtrlTLV* tlvs = 0;
 char *newmessage = NULL;
 int ignore_message = otrl_message_receiving(
    userstate, &amp;ui_ops, opdata,
    accountname, protocol, recipientname,
    s.c_str(),
    &amp;newmessage,
    &amp;tlvs,
    myotr_add_appdata, &amp;ui_ops );

 VMSG &lt;&lt; "ignore:" &lt;&lt; ignore_message &lt;&lt; " newmsg:" &lt;&lt; maybenull(newmessage) &lt;&lt; endl;
 if( newmessage )
        s = newmessage;
 otrl_message_free( newmessage );
 if( ignore_message )
 {
     VMSG &lt;&lt; "libotr told us to ignore this message..." &lt;&lt; endl;
     continue;
 }
                
 cout &lt;&lt; "ignore:" &lt;&lt; ignore_message &lt;&lt; " server got:" &lt;&lt; s &lt;&lt; endl;
 cout &lt;&lt; "message from client:" &lt;&lt; color(s) &lt;&lt; endl;

 // do not echo back messages when we are establishing the session
 if( !secure )
     continue;</pre>
<pre>&nbsp;</pre>
The remainder of server_session() creates the echo reply message,
  encrypts it with otrl_message_sending() and sends the OTR message
  over the socket.<br />
<br />
<pre>  static int count = 0;
  stringstream zz;
  zz &lt;&lt; "back to you s:" &lt;&lt; s &lt;&lt; " count:" &lt;&lt; count++;
  s = zz.str();
  cout &lt;&lt; "writing...s:" &lt;&lt; s &lt;&lt; endl;
  cerr &lt;&lt; "send plaintext:" &lt;&lt; colorsend(s) &lt;&lt; endl;

  et = otrl_message_sending( userstate, &amp;ui_ops, opdata,
     accountname, protocol, recipientname,
     s.c_str(), tlvs, &amp;newmessage,
     myotr_add_appdata, &amp;ui_ops );
  if( !ok(et) )
  {
     cerr &lt;&lt; "OTR message_sending() failed!" &lt;&lt; endl;
  }
  if( ok(et) &amp;&amp; !newmessage )
  {
     cerr &lt;&lt; "There was no error, but an OTR message could not be made." &lt;&lt; endl;
     cerr &lt;&lt; "perhaps you need to run some key authentication first..." &lt;&lt; endl;
  }
  if( newmessage )
  {
     VMSG &lt;&lt; "have new OTR message:" &lt;&lt; newmessage &lt;&lt; endl;
     s = newmessage;
  }
                
  VMSG &lt;&lt; "writing otr...s:" &lt;&lt; s &lt;&lt; endl;
  stream &lt;&lt; s &lt;&lt; endl;</pre>
<pre>&nbsp;</pre>
As the security of the OTR messaging relies on fingerprints in the
  first example, the new_fingerprint callback presents our fingerprint
  and the remote fingerprint and asks the user if they want to
  continue to establish the session or not. Unforuntately this means
  the user has to eyeball scan the remote fingerprint against an
  expected value they have obtained from the remote party at some
  other time in a secure channel.<br />
<br />
<pre>static void myotr_new_fingerprint( void *opdata, OtrlUserState us,
                                   const char *accountname, const char *protocol,
                                   const char *username, unsigned char fingerprint[20])
{
    cerr &lt;&lt; "myotr_new_fingerprint(top)" &lt;&lt; endl;

    char our_fingerprint[45];
    if( otrl_privkey_fingerprint( us, our_fingerprint, accountname, protocol) )
    {
        cerr &lt;&lt; "myotr_new_fingerprint() our   human fingerprint:" &lt;&lt; embold( our_fingerprint ) &lt;&lt; endl;
    }
    
    cerr &lt;&lt; "myotr_new_fingerprint() their human fingerprint:"
         &lt;&lt; embold( fingerprint_hash_to_human( fingerprint )) &lt;&lt; endl;
    cerr &lt;&lt; "do the fingerprints match at the remote end (enter YES to proceed)" &lt;&lt; endl;
    std::string reply;
    getline( cin, reply );
    if( reply != "YES" )
    {
        cerr &lt;&lt; "You have chosen not to continue to talk to these people... good bye." &lt;&lt; endl;
        exit(0);
    }
}
</pre>
<h2>
Simpler authentication with SMP</h2>
The second example uses the SMP to avoid having to verify
  fingerprints. For good measure, the fingerprints established are
  saved and loaded to/from disk so that subsequent conversations do
  not need any SMP or user fingerprint verification.<br />
<br />
During process startup, fingerprints are read from file if they exist;<br />
<br />
<pre> std::stringstream fn;
 fn &lt;&lt; "fingerprints-" &lt;&lt; accountname;
 gcry_error_t e = otrl_privkey_read_fingerprints( userstate, fn.str().c_str(), 0, 0 );</pre>
<br />
<br />
The otrl_message_sending() and otrl_message_receiving() functions
  both have a parameter <tt>OtrlTLV *tlvs</tt>. The tlvs allow data to be
  sent and received as sideband information that does not effect what
  you send with libotr. The SMP uses the tlvs to communicate the
  information that it needs in order to authenticate.
<br />
In server_session() the main change is a check on the tlvs variable
  after calling otrl_message_receiving().<br />
<br />
<pre> if( tlvs )
 {
    handle_smp( stream, tlvs, userstate, &amp;extended_ui_ops, opdata );
 }</pre>
<pre>&nbsp;</pre>
The client initiates the SMP and has heavier changes to it's code.
  After creating a iosockstream to localhost, the client calls
  run_smp_client() to setup the OTR session and run the SMP to
  authenticate. Apart from the call to run_smp_client() the client
  mainloop while(true) doesn't need to change. This makes sense
  because the SMP is normally only used at session establishment when
  we do not know about the remote key (fingerprint) already.<br />
<br />
In the run_smp_client function, the first <tt>while( !secure...</tt> loop
  will establish an OTR session using fingerprints just like the first
  example. This time we do not stop to ask the user to verify the
  fingerprints, we simply record that a new fingerprint was
  seen. This is done by setting runSMP=true to force the SMP if we are
  using a fingerprint that we didn't already have on disk.<br />
<br />
If runSMP is set then we read a secret from the user and call
   otrl_message_initiate_smp() to get the SMP ball rolling with
   libotr. This leads to the second <tt>while( !secure</tt> loop which will
   stop when we are secure again.<br />
<br />
<pre>void run_smp_client( iosockstream&amp; stream )
{
    void* opdata = &amp;stream;
    OtrlTLV* tlvs = 0;

    // establish session using fingerprints
    stream &lt;&lt; "?OTR?v2?" &lt;&lt; endl;
    usleep( 200 * 1000 );
    while( !secure &amp;&amp; stream.peek() != std::iostream::traits_type::eof() )
        client_read_msg_from_server( stream );

    if( !runSMP )
    {
        return;
    }
    
    VMSG &lt;&lt; "Starting the Socialist Millionaires' Protocol " &lt;&lt; endl
         &lt;&lt; " to work out who the other guy is..." &lt;&lt; endl
         &lt;&lt; endl;
    VMSG &lt;&lt; "please give me a secret that only you and the other guy know..." &lt;&lt; endl;
    std::string s;
    getline( cin, s );
    int add_if_missing = true;
    int addedp = 0;
    ConnContext* smpcontext = otrl_context_find( userstate,
                                                 recipientname, accountname, protocol,
                                                 add_if_missing, &amp;addedp,
                                                 myotr_add_appdata, &amp;ui_ops );

    cerr &lt;&lt; "addedp:" &lt;&lt; addedp &lt;&lt; " smpcontext:" &lt;&lt; smpcontext &lt;&lt; endl;
    if( !smpcontext )
        return;
    otrl_message_initiate_smp( userstate, &amp;ui_ops, opdata, smpcontext,
                               (const unsigned char*)s.c_str(), s.length() );

    // we are only secure if the SMP succeeds
    secure = 0;
    while( !secure &amp;&amp; stream.peek() != std::iostream::traits_type::eof() )
        client_read_msg_from_server( stream );
        
    cerr &lt;&lt; "secure:" &lt;&lt; secure &lt;&lt; endl;
    if( secure == SMP_BAD )
    {
        cerr &lt;&lt; "couldn't authenticate server, exiting..." &lt;&lt; endl;
        exit(1);
    }
}</pre>
<pre>&nbsp;</pre>
The client_read_msg_from_server() function calls
  otrl_message_receiving() and checks if tlvs is set and if so calls
  handle_smp() with that tlvs value.<br />
<br />
As you see from the above, whenever a tlvs is set in the client or
  server then handle_smp() is called. If you look at the UPGRADING
  file in libotr 3.2.0+ you will see a skeleton code in "3.3.4.
  Control Flow and Errors" which the handle_smp() is based on. The
  handle_smp() function uses otrl_tlv_find() on tlvs to check for
  internal OTR messages sent from libotr itself which describe a stage
  in the SMP. handle_smp() is like a primitive state machine working
  through from SMP1 (the server asking for the secret to respond to
  the client's initial request), through to SMP3 and SMP4 which are
  called when the protocol completes with either success or failure
  (same or different secrets).<br />
<br />
<pre>  if( tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2))
  {
    if (nextMsg != OTRL_SMP_EXPECT2)
    {
       cerr &lt;&lt; "smp: spurious SMP2 received, aborting" &lt;&lt; endl;
       otrl_message_abort_smp( userstate, ui_ops, opdata, smpcontext);
       otrl_sm_state_free(smpcontext-&gt;smstate);
    }
    else
    {
       cerr &lt;&lt; embold("SMP2 received, otrl_message_receiving will have sent SMP3") &lt;&lt; endl;
       smpcontext-&gt;smstate-&gt;nextExpected = OTRL_SMP_EXPECT4;
    }
  }</pre>
<pre>&nbsp;</pre>
If the secrets are proven to be the same when the SMP is used it is
  adventagious to save the fingerprints to disk so that future
  communications do not require user fingerprint verificaiton or the
  SMP.<br />
<br />
<pre>if(  tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4) 
  || tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3))
 {
 if( smpcontext-&gt;smstate-&gt;sm_prog_state == OTRL_SMP_PROG_SUCCEEDED )
   {
     std::stringstream fn;
     fn &lt;&lt; "fingerprints-" &lt;&lt; accountname;
     gcry_error_t e = otrl_privkey_write_fingerprints( userstate, fn.str().c_str() );
   }
}</pre>
<br /><pre></pre>
Hopefully you are now in a better position to add libotr support to
   your real time network programs. The full source code to these
   programs as well as the HTML for this post itself is up on <a href="https://github.com/monkeyiq">my
   github</a> page. Remeber, using off the record messaging doesn't
   nessesarily mean you have anything to hide, just that you have
   nothing to show.<br />
<br /><span class="net_nemein_favourites">6 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=5ca8ff2ada5411e188aec9545328246c246c&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/5ca8ff2ada5411e188aec9545328246c246c/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=5ca8ff2ada5411e188aec9545328246c246c&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/5ca8ff2ada5411e188aec9545328246c246c/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Ben Martin &lt;monkeyiq@users.sourceforge.net&gt;</author>
            <category>feed:db85272b5cc4c48c874836930690af4e</category>
            <pubDate>Mon, 30 Jul 2012 06:54:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-5ca8ff2ada5411e188aec9545328246c246c</guid>
        </item>
        <item>
            <title>An ARMs race, with a core i7 in there too for relativity</title>
            <link>http://monkeyiq.blogspot.com/2012/06/arms-race-with-core-i7-in-there-too-for.html</link>
            <description><![CDATA[
After doing some power benchmarking recently (1.2ghz kirkwood with gb net up = 5watts) I decided to work out how fast these arms can do useful work^TM. In the running is a Synology ds212j, DreamPlug running the Freedombox, Nokia n9 mobile phone, and an Intel 2600k just for working out where those relative numbers sit when compared to a desktop machine.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4G1XjG0oOxWJoeZVPG6TR1PhqvH7e_Rsn3mYVahu0THb3KXVDgAwWZecuZN66kyxJ8Hu4pOTIkFEXtZUa7eLSLTmSJU3Qw8ZL2lqQYyIMKhZ9b2ObzTkVSOENOvcwoeXfN_E4wss-R4A/s1600/ciphers-with-i7-too.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4G1XjG0oOxWJoeZVPG6TR1PhqvH7e_Rsn3mYVahu0THb3KXVDgAwWZecuZN66kyxJ8Hu4pOTIkFEXtZUa7eLSLTmSJU3Qw8ZL2lqQYyIMKhZ9b2ObzTkVSOENOvcwoeXfN_E4wss-R4A/s320/ciphers-with-i7-too.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilNa8Rfx6YRKmF-PLBBfS8RmkTem5xFP8wAl5jCRYWrpRONil9Urk72oAnhmpLBDpXM4Fdp0vtRCQHHM-BQMrO92Q1oq-lvNPMNcW17_lUN9fve82Rhtzi8YICFtbv9R5qVefHRXAagzo/s1600/ciphers-with-i7-too.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><br /></a></div>
<br />The above image shows the cipher performance of "openssl speed" across many machines. The 2600k is only single threaded, so could be many times faster in real world use by taking advantage of the cores. One interesting point right off the bat is that the 1.2Ghz kirkwood in the synology NAS is bested by the 1.0ghz CPU of the Nokia n9. Arms is not arms.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9PkJp4qB9fQSMwvrvwD_KT65PibNF_OiPuweke8roCG1WpX4UyJnzH5ScjLimsEISLvJVOBzb6JGt3sdixeGYn9fA9ETkSmcLGBZTNlv-8RC48RnVujp0LX0RohOJid_pMlv2Dp5z6C8/s1600/ciphers-arm-only.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9PkJp4qB9fQSMwvrvwD_KT65PibNF_OiPuweke8roCG1WpX4UyJnzH5ScjLimsEISLvJVOBzb6JGt3sdixeGYn9fA9ETkSmcLGBZTNlv-8RC48RnVujp0LX0RohOJid_pMlv2Dp5z6C8/s320/ciphers-arm-only.png" width="320" /></a></div>
Removing the overload from the Intel i7 2600K from the graph we see that the Dreamplug is very close to the ds212j in terms of performance.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvut_t_r0hqsSXwXpuGTRAv0AKs5jDZ4OSYddPMahH8UVUPlU4EtYhpyznhUOL0bjAVJvGEGLpZzU9PCBqvt7_bxMF83fOpG3cdgVkgm1pqfY_o73yowA0uhSvl9WidVf8UcotnD5pgag/s1600/digests-arm-only.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvut_t_r0hqsSXwXpuGTRAv0AKs5jDZ4OSYddPMahH8UVUPlU4EtYhpyznhUOL0bjAVJvGEGLpZzU9PCBqvt7_bxMF83fOpG3cdgVkgm1pqfY_o73yowA0uhSvl9WidVf8UcotnD5pgag/s320/digests-arm-only.png" width="320" /></a></div>
On the other hand, the digests show a distinct advantage to the Dreamplug setup. Again the n9 has a nice little lead on the others. Since a mobile phone can perform some useful work, one should perhaps also be demanding the NAS also offer handy features as well as just serving data blocks.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYaoSwf3qbk29LpFo0p5kd2hAJfWBh-sht1YMw4yH33umQMmL6w-98GfI9a5ZY7JnETsWhxShOmv0SqY64NnWI00nhtMYztJjcdlV5X2RvlBuBSmNA5wPtkZtrdh3UTM_ZRLPMZsnXh_Q/s1600/rsa-sign.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYaoSwf3qbk29LpFo0p5kd2hAJfWBh-sht1YMw4yH33umQMmL6w-98GfI9a5ZY7JnETsWhxShOmv0SqY64NnWI00nhtMYztJjcdlV5X2RvlBuBSmNA5wPtkZtrdh3UTM_ZRLPMZsnXh_Q/s320/rsa-sign.png" width="320" /></a></div>
<br />
The RSA sign and verify graphs both show the same large slump for the ds212j unit. So for connection heavy workloads there would seem to be a large difference to the throughput you might get for the ARM you choose. On the other hand, the Dreamplug and ds212j both have similar performance on steam ciphers. So if connections are longer term then the difference will be less.<br />
<br />
I would love to add benchmarks for the CuBox and QNAP 2ghz (<span class="boldproname">TS-219PII) NAS units. It would also be interesting to use after market software on the ds212j and see the difference.</span><br />
<span class="boldproname"><br /></span><span class="net_nemein_favourites">6 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=21caff22b04a11e1a9321138e5dcaff2aff2&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/21caff22b04a11e1a9321138e5dcaff2aff2/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>1 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=21caff22b04a11e1a9321138e5dcaff2aff2&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/21caff22b04a11e1a9321138e5dcaff2aff2/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Ben Martin &lt;monkeyiq@users.sourceforge.net&gt;</author>
            <category>feed:db85272b5cc4c48c874836930690af4e</category>
            <pubDate>Wed, 06 Jun 2012 19:32:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-21caff22b04a11e1a9321138e5dcaff2aff2</guid>
        </item>
        <item>
            <title>Pragmatically unlocking an n9, possible?</title>
            <link>http://monkeyiq.blogspot.com/2012/04/pragmatically-unlocking-n9-possible.html</link>
            <description><![CDATA[
I have in mind an app to use RFID over the NFC hardware on the n9 to allow the phone to be unlocked by an RFID tag. This way the password can be nice and long for locking the device, but I don't have to interact with the virtual keyboard in order to use the phone. If the phone locks, I just tap the RFID tag to it, it unlocks, and I'm away. Yes, two phase would be a logical next step, but that assumes that the "lock" on the phone is very hard to break.<br /><br />Reading the RFID on the n9 is the simple part, I have that working fine with physical keys. Unlocking the phone is proving not so simple. I was hoping that <a href="http://harmattan-dev.nokia.com/docs/library/html/qmsystem2/classMeeGo_1_1QmLocks.html?tab=0#a4a33dfe6fb061753b0118a93fb88c4d9">MeeGo::QmLocks::setState</a> would do the trick, but it is not to be so as the API docs explain.<br /><br />Anyone stumbled on a way to unlock the n9 from a program?<span class="net_nemein_favourites">2 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=473c1668894b11e1a9d8c94861c992bb92bb&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/473c1668894b11e1a9d8c94861c992bb92bb/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>2 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=473c1668894b11e1a9d8c94861c992bb92bb&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/473c1668894b11e1a9d8c94861c992bb92bb/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Ben Martin &lt;monkeyiq@users.sourceforge.net&gt;</author>
            <category>feed:db85272b5cc4c48c874836930690af4e</category>
            <pubDate>Wed, 18 Apr 2012 04:09:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-473c1668894b11e1a9d8c94861c992bb92bb</guid>
        </item>
        <item>
            <title>Support libferris, get at ferris through KIO, and read about OTR messaging</title>
            <link>http://monkeyiq.blogspot.com/2012/04/support-libferris-get-at-ferris-through.html</link>
            <description><![CDATA[
I thought I'd see how well some pledgie tasks would do in the wild. Some of this code is stuff I've been wishing to write for a while but unable to make the time.<br /><br />If you want to get at some of the funky filesystems offered by libferris from your KDE desktop, you might like to support my "KIO Slave for libferris" pledgie:<br /><br /><a href='http://www.pledgie.com/campaigns/17076'><img alt='Click here to lend your support to: KIO Slave for libferris and make a donation at www.pledgie.com !' src='http://www.pledgie.com/campaigns/17076.png?skin_name=chrome' border='0' /></a><br /><br />If you've always wanted to add support for Off-the-Record messaging to your project, or help entice somebody else in that direction, I have a tutorial article on offer here:<br /><br /><a href='http://www.pledgie.com/campaigns/17070'><img alt='Click here to lend your support to: Off The Record Messaging HOWTO article and make a donation at www.pledgie.com !' src='http://www.pledgie.com/campaigns/17070.png?skin_name=chrome' border='0' /></a><br /><br />If you want a REST interface for libferris, listing directories and getting at files over HTTP/HTTPS, you can help make that happen here:<br /><br /><a href='http://www.pledgie.com/campaigns/17069'><img alt='Click here to lend your support to: Extend the REST interface of libferris and make a donation at www.pledgie.com !' src='http://www.pledgie.com/campaigns/17069.png?skin_name=chrome' border='0' /></a><br /><br />And finally, last for today but not least, if you want to get at jpeg images on your Zoneminder server using nice normal command lines like the following:<br /><pre><br />$ fcat zoneminder://server/monitor | okular -<br /></pre><br />Then you might like to throw a little loose change at the zoneminder plugin pledgie:<br /><br /><a href='http://www.pledgie.com/campaigns/17068'><img alt='Click here to lend your support to: libferris mounting Zoneminder and make a donation at www.pledgie.com !' src='http://www.pledgie.com/campaigns/17068.png?skin_name=chrome' border='0' /></a><span class="net_nemein_favourites">0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=e37bb5947d2811e190cad530fc30de6fde6f&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/e37bb5947d2811e190cad530fc30de6fde6f/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>4 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=e37bb5947d2811e190cad530fc30de6fde6f&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/e37bb5947d2811e190cad530fc30de6fde6f/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Ben Martin &lt;monkeyiq@users.sourceforge.net&gt;</author>
            <category>feed:db85272b5cc4c48c874836930690af4e</category>
            <pubDate>Mon, 02 Apr 2012 17:24:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-e37bb5947d2811e190cad530fc30de6fde6f</guid>
        </item>
        <item>
            <title>N9: Two socks VPN solution</title>
            <link>http://monkeyiq.blogspot.com/2012/03/n9-two-socks-vpn-solution.html</link>
            <description><![CDATA[
I always tend to lean more towards SSH for VPN stuff than other tools like openvpn. With this mindset I was working out how one might get access to servers on the Intranet while on the move. Having created a bunch of nice little apps that do things on my network is all well and good, but I wanted to also use them while on the move.<br /><br />My current solution is to use two socks servers on the phone. It might seem strange to need two, but this allows routing depending on source address and destination address. The first SOCKs server is dante which routes all "normal" traffic directly to the chosen Internet connection on the phone. Traffic which wants to go to selected addresses on my Intranet is instead forwarded to a second socks proxy on the phone. This second socks proxy is implemented with ssh "DynamicForward" to send traffic over the SSH link to the Intranet.<br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrmdDIPQTSu0laZYPuex5-TQsc16LMCNbO9YESJ3PVerC2x63aRtVjODzxidajo8bLwd5zE5BtvPL7iQ8boHc0TvHL8gRz6MKsRQwFX6bURXzWgxA4gJ2P6trOdcYmMLB-oQLyLiLJ8SE/s1600/two-socks.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 136px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrmdDIPQTSu0laZYPuex5-TQsc16LMCNbO9YESJ3PVerC2x63aRtVjODzxidajo8bLwd5zE5BtvPL7iQ8boHc0TvHL8gRz6MKsRQwFX6bURXzWgxA4gJ2P6trOdcYmMLB-oQLyLiLJ8SE/s400/two-socks.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5725966508275047058" /></a><br /><br />The glory here is that Internet traffic goes directly, and Intranet traffic is sent over an encrypted pipe to the Intranet. If on the other hand I connect to any router on the Intranet, the phone gets a local IP address and dante is instructed to "route" traffic from that local address directly to the target instead of to the second local ssh socks server. Thus I don't have to concern myself with the details of which side of firewalls I am on, the phone automatically does that for me and chooses the most efficient route for packets.<br /><br />Having a phone that runs so much like a proper Linux distro makes this sort of thing fairly easy to get going. No need for funky NDKs, NDAs, or TLAs.<br /><br />If you want to play around with this stuff I have dante debs in my repo:<br />http://fuuko.libferris.com/maemo/n9/<br />Using non privlidged ports on the phone means you can run danted as a normal user. I have an icon on the n9 home screen that makes sure dante is running instead of using init.d at the moment. Also, an icon that runs a bash encapsulated with tsocks can be handy for tinkering:<br />Desktop file segment:<br /><pre><br />Exec=meego-terminal -n -e /bin/sh /home/user/bin/create-tsocks-env<br />...<br /><br />$ cat /home/user/bin/create-tsocks-env<br />export http_proxy=http://1.2.3.4:1313/<br />tsocks bash<br /></pre><br /><br />Using a similar style Exec in a desktop file one can start the SSH client in "-N" mode and use the passphrase to connect and setup an SSH connection with a socks server on the phone. It is quick and dirty without shiny QML interfaces, but it works^TM.<span class="net_nemein_favourites">5 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=52d45a7c7b0d11e19596e371f73fd6e4d6e4&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/52d45a7c7b0d11e19596e371f73fd6e4d6e4/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>1 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=52d45a7c7b0d11e19596e371f73fd6e4d6e4&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/52d45a7c7b0d11e19596e371f73fd6e4d6e4/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Ben Martin &lt;monkeyiq@users.sourceforge.net&gt;</author>
            <category>feed:db85272b5cc4c48c874836930690af4e</category>
            <pubDate>Sat, 31 Mar 2012 00:51:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-52d45a7c7b0d11e19596e371f73fd6e4d6e4</guid>
        </item>
        <item>
            <title>Zoneminder on the n9. Maybe n900 too?</title>
            <link>http://monkeyiq.blogspot.com/2012/03/zoneminder-on-n9-maybe-n900-too.html</link>
            <description><![CDATA[
My <a href="https://github.com/monkeyiq/">growing collection</a> of Qt/QML applications has now hit 6 apps with the inclusion of a Zoneminder client for the n9. As I still have ideas for more apps I wonder how long until I fill half a screen with my own apps on the device ;)<br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiftXFSyIu6Xways_wX8t6rrOFhxzxQOLjrre-Q8DwkAEjHFKWkzN9VereoHvfe5szgnmwsAWTK7rHNiXAcNcpM5xdUoCEohjyUmiso5EKOCTAtLLK3Xmy56wUSzTEbsyeaoRtCAINyC1w/s1600/qmlzoneminder-main.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 238px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiftXFSyIu6Xways_wX8t6rrOFhxzxQOLjrre-Q8DwkAEjHFKWkzN9VereoHvfe5szgnmwsAWTK7rHNiXAcNcpM5xdUoCEohjyUmiso5EKOCTAtLLK3Xmy56wUSzTEbsyeaoRtCAINyC1w/s400/qmlzoneminder-main.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5724488458131609762" /></a><br /><br />Anyways, the Zoneminder app uses server side scaling and jpeg generation to keep bandwidth down and CPU/RAM very low on the device. I have modified some of the images for example purposes. The app is basically as shown but will display your real camera data instead of Koalas... Unless you are lucky enough to have some furry little friends. The first camera starts a live view right off the bat when the app starts, so there is as little finger use needed to get some useful action from running the app.<br /><br />Only active cameras are listed. The play button changes the image on the right to be a 1 second rolling "live view" of that camera. The little watch moves to the recorded events for that camera which is shown below. The config is quite simple; the Zoneminder server URL, and the user/password to login to that server. <br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiou8ZE0gvBYkFJqiDUns0jv6hwHPm-OJO36YEhSRI_0pAgcr9iWjqgBvP2RGRzjB0ESR8rSFyd3iatOd8zSSAZKOMNfyUEbFbAmTEBaTC4feeD0iqH6G2wDSFW0Ps15Xi6STyAd45qRZs/s1600/qmlzoneminder-event.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 238px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiou8ZE0gvBYkFJqiDUns0jv6hwHPm-OJO36YEhSRI_0pAgcr9iWjqgBvP2RGRzjB0ESR8rSFyd3iatOd8zSSAZKOMNfyUEbFbAmTEBaTC4feeD0iqH6G2wDSFW0Ps15Xi6STyAd45qRZs/s400/qmlzoneminder-event.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5724497724380214594" /></a><br /><br />Alarm events are shown on the left side and the play button rolls through that event with the progress bar showing how far through the alarm you are. Naturally both the lists scroll to show more cameras or events if there are more than 5. By default only 25 of the most recent alarm events are shown in the list. A future expansion might allow paging back to see older ones.<span class="net_nemein_favourites">5 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=f6d32e7a77f011e19d3de7cdc1789ed29ed2&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/f6d32e7a77f011e19d3de7cdc1789ed29ed2/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>1 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=f6d32e7a77f011e19d3de7cdc1789ed29ed2&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/f6d32e7a77f011e19d3de7cdc1789ed29ed2/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Ben Martin &lt;monkeyiq@users.sourceforge.net&gt;</author>
            <category>feed:db85272b5cc4c48c874836930690af4e</category>
            <pubDate>Tue, 27 Mar 2012 01:16:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-f6d32e7a77f011e19d3de7cdc1789ed29ed2</guid>
        </item>
        <item>
            <title>Ferris on the n9: Search by URL, content, and mtime</title>
            <link>http://monkeyiq.blogspot.com/2012/03/ferris-on-n9-search-by-url-content-and.html</link>
            <description><![CDATA[
The n9 libferris app now allows you to search by the URL of the file as before, but also now by the file text content and it's modification time. Query type is selected by a button in the top right corner which unfortunately isn't nearly as easy to read in the video file as it is in real life.<br /><br />As libferris handles extraction, update, and storage of metadata from disparate locations I have also added a sprinkling of what that means into the video. Notice that the first search by URL shows a comment "REST interface to libferris" in bold. This is simply the "annotation" metadata of the file but is much more interesting to the searcher than it's URL. Likewise in the second query, which finds a Gutenburg text file by searhing on text content, the annotation offers the name of the book that the file contains. Again much more interesting content to the human who is at the helm.<br /><br />The third query is on the modification time of the files. There are three ways offered to perform a time search, "more recently than this" or "than last" which can have month or day as options for example, and modified >= X months ago which obviously wants a number as the query text. When querying by time like this, libferris happily accepts some human readable terms like "begin this month" as the time you specify. This makes it just as convenient to use search in scripts as in the dedicated front ends like the n9 app.<br /><br /><iframe src="http://player.vimeo.com/video/39101002?title=0&amp;byline=0&amp;portrait=0" width="801" height="451" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe><br /><br />The plan is as always, to push metadata from being an after thought to being a first class citizen: able to be created, read, written, indexed, and searched on. Any file with metadata should be able to expose that as simply as its mtime or size, which is all currently done via a key-value "Extended Attribute" interface at the lowest level.<br /><br />If you like libferris or the recent updates (status.net mounting, these indexing tweaks etc) then please consider making a donation. If you want to use this technology at a corporate level, please feel free to contact me.<span class="net_nemein_favourites">4 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=18e0226a761c11e1911e7de87e6f258a258a&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/18e0226a761c11e1911e7de87e6f258a258a/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>1 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=18e0226a761c11e1911e7de87e6f258a258a&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/18e0226a761c11e1911e7de87e6f258a258a/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Ben Martin &lt;monkeyiq@users.sourceforge.net&gt;</author>
            <category>feed:db85272b5cc4c48c874836930690af4e</category>
            <pubDate>Sat, 24 Mar 2012 18:10:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-18e0226a761c11e1911e7de87e6f258a258a</guid>
        </item>
        <item>
            <title>Libferris on the N9: JSON, REST, QML, Index and Search, VFS all together</title>
            <link>http://monkeyiq.blogspot.com/2012/03/libferris-on-n9-json-rest-qml-index-and.html</link>
            <description><![CDATA[
Continuing my n9 apps I now have an index search app that uses libferris. Currently I have only exposed URL regular expression search. This is searching an index maintained and stored in a PostgreSQL database. Solving regex query in a timely manner is a fairly complex problem with one useful solution outlined in one of my previous <a href="http://monkeyiq.blogspot.com.au/2011/05/searching-again-400ms-2ms.html">blog entries.</a><br /><br />Note that data is downloaded over normal http(s) from the server using the n9 app, so no NFS or other network mounts are needed. This might be handy for grabbing a PDF, image or text file off an Intranet file server while on the move.<br /><br /><iframe src="http://player.vimeo.com/video/38987482?title=0&amp;byline=0&amp;portrait=0" width="801" height="451" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe><br /><br />I have also been updating the clucene libferris module to allow more effective index use during regex/infix queries. This libferris engine works quite nicely on older ARM machines. Benchmarks on that to follow, once I reindex the arm and produce the comparative figures.<span class="net_nemein_favourites">4 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=a48c748c743511e19cbd21af0bfe9bc19bc1&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/a48c748c743511e19cbd21af0bfe9bc19bc1/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>1 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=a48c748c743511e19cbd21af0bfe9bc19bc1&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/a48c748c743511e19cbd21af0bfe9bc19bc1/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Ben Martin &lt;monkeyiq@users.sourceforge.net&gt;</author>
            <category>feed:db85272b5cc4c48c874836930690af4e</category>
            <pubDate>Thu, 22 Mar 2012 07:55:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-a48c748c743511e19cbd21af0bfe9bc19bc1</guid>
        </item>
        <item>
            <title>QML BOM: Weather on the go...</title>
            <link>http://monkeyiq.blogspot.com/2012/03/qml-bom-weather-on-go.html</link>
            <description><![CDATA[
As part of my foray into n9 apps, a new one that displays information from the Australian Bureau of Meteorology on the n9. Being pure QML + Javascript it also runs on the desktop. The forecasts include min and max temps, and for the Europeans reading this, the middle line "10..." is the UV prediction and roasting window for the day... all your sunscreen are belong to us.<br />   <br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMt9YFeUGD7QeZmN97k3XgSWkVTpFW7V8mNN6tI94VJIVuE2VqBGIgOO8KR-5w862povdOaf_1ZXubvHnd-vI-j_uaiUYg1HRyPgU3e-Wk3SfGZrRtqG6ABOCyC2-1Hwja3jWiKLA9Q-U/s1600/qmlbom.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 266px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMt9YFeUGD7QeZmN97k3XgSWkVTpFW7V8mNN6tI94VJIVuE2VqBGIgOO8KR-5w862povdOaf_1ZXubvHnd-vI-j_uaiUYg1HRyPgU3e-Wk3SfGZrRtqG6ABOCyC2-1Hwja3jWiKLA9Q-U/s400/qmlbom.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5719914586297585202" /></a><br /><br />Apart from saving a little on downloads for the topology and background images when on the move, you get to customize those as they are just png files living in the images subdirectory. So I have the local rocket launch site indicated. I'd like to make a LOTR style topology overlay, perhaps mt Glorious becomes Mordor?<br /><br />Code available at https://github.com/monkeyiq/qmlbom<span class="net_nemein_favourites">4 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=2e8aaaee6e3911e1b93aabe9283a34cb34cb&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/2e8aaaee6e3911e1b93aabe9283a34cb34cb/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>1 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=2e8aaaee6e3911e1b93aabe9283a34cb34cb&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/2e8aaaee6e3911e1b93aabe9283a34cb34cb/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Ben Martin &lt;monkeyiq@users.sourceforge.net&gt;</author>
            <category>feed:db85272b5cc4c48c874836930690af4e</category>
            <pubDate>Wed, 14 Mar 2012 17:29:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-2e8aaaee6e3911e1b93aabe9283a34cb34cb</guid>
        </item>
        <item>
            <title>N9, QML, Javascript and differential update.</title>
            <link>http://monkeyiq.blogspot.com/2012/03/n9-qml-javascript-and-differential.html</link>
            <description><![CDATA[
I had a server app that had both a desktop and web interface. Though I discovered that the web interface was less than monkey finger friendly on the n9 and required some authentication each time. I thought this was a job for QML and javascript on the device. The good news is that I now have a client using just those tools, so no cross compilation needed at all ;)<br /><br />The core of the UI is updated via a timer which runs an ajax call, parses the JSON response and gives that to updateModel(). The first implementation of the later method was to clear the listModel and repopulate from scratch each time. Rather wasteful, even though it was only being called once every 2-3 seconds, it was eating up 8-9% CPU of the n9 in top. A better solution is to iterate the existing items, performing update, remove, or add as you go. This needs a "key" field for each tuple and a stable total order on the model JSON data, either from the server or through an explicit client side sort.<br /><br />I'll probably put this up on github soon, but in the meantime, this is the updateModel() which has the smarts I mentioned above. It takes 3-4% of CPU instead, and should maintain view state better on the device. I use objid as the key, and the "state" is cloned to objstate because I noticed some issues there with QML interaction using state as the property. Interesting what one can do with QML+JS in very short time for the n9.<br /><br /><pre><br />    function updateModel( model, data ) <br />    {<br /> var existingIndex = 0;<br /> var existingIndexMax = model.count;<br /> var id;<br /><br /> for( id in data ) <br /> {<br />     var found = false;<br />     var name  = data[ id ];<br />     var col   = data[ id ];<br />     var k;<br />     var row = {};<br />     row[ "objid" ] = id;<br />     row[ "name" ] = "v";<br />     for( k in col ) <br />     {<br />  if( k == "state" ) {<br />      row[ "objstate" ] = col[k];<br />  }<br />  else {<br />      row[ k ] = col[ k ];<br />  }<br />     }<br /><br />      // find it if it exists...<br />     for( ; existingIndex < existingIndexMax; ++existingIndex )<br />     {<br />  if( model.get( existingIndex ).objid == id )<br />  {<br />      found = true;<br />       model.set( existingIndex, row );<br />      ++existingIndex;<br />      break;<br />  }<br />  else<br />  {<br />      // This element from the local model no longer exists on the server,<br />      // remove it. Do not advance the index as we have removed an element instead.<br />      model.remove( existingIndex );<br />      --existingIndex;<br />  }<br />     }<br /><br />     // it didn't exist, add it as new.<br />     if( !found )<br />     {<br />  model.append( row );<br />     }<br /> }<br />    }<br /></pre><span class="net_nemein_favourites">4 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=dc5f84906c1e11e19d582f18e3d46c026c02&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/dc5f84906c1e11e19d582f18e3d46c026c02/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>1 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=dc5f84906c1e11e19d582f18e3d46c026c02&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/dc5f84906c1e11e19d582f18e3d46c026c02/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Ben Martin &lt;monkeyiq@users.sourceforge.net&gt;</author>
            <category>feed:db85272b5cc4c48c874836930690af4e</category>
            <pubDate>Mon, 12 Mar 2012 00:59:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-dc5f84906c1e11e19d582f18e3d46c026c02</guid>
        </item>
        <item>
            <title>Libferris on both arms</title>
            <link>http://monkeyiq.blogspot.com/2012/03/libferris-on-both-arms.html</link>
            <description><![CDATA[
I now have libferris on a 512mb ARM5t embedded device and a 1gb arm7 one (the Nokia n9). As part of the fun and games I updated the clucene and boostmmap index modules for libferris and created a QtSQL module which uses SQLite by default. Hey, when you can't choose which cake to have why not have a slice of them all... or a slice to fit the moment or device at hand. eg, desktop or server works nicely with the soprano or postgresql indexing modules, embedded is nicer on mmap or clucene.<br /><br />I find it ironic that I never really thought much of "embedded" devices when hacking libferris. But devices with 512/1024mb of RAM are really not so much embedded I guess.<br /><br />A few things I've tried to do in the design of libferris index+search is to design for many machines and also federations of them. It is possible to search a router, phone, and desktop's individual indexes as a federation from the laptop. Another thing that helps is that indexing is routed through the "findexadd" commands. So you can use find and split to break up indexing activity, and have it done from cron when you want. <br />The new --total-files-to-index-per-run option works in combination, causing findexadd to exit when it has indexed a given number of files. Note that if a file has not changed since it was last indexed it is not indexed again (no need), so that file does not count toward the <br />total-files-to-index-per-run tally.<br /><br />The below is a little script to incrementally index just selected metadata from /usr and your home directory using clucene. The WHITELIST environment variable stops libferris from trying to sniff up metadata for files and has it only look for and add what metadata you want. If you have md5 in there then libferris will store the checksum for each file, at a commensurate cost in IO. Splitting into batches of 5000 prevents the process running too long and wanting too much RAM.<br /><br />$ mkdir -p ~/.ferris/ea-index<br />$ cd ~/.ferris/ea-index<br />$ fcreate --create-type eaindexclucene .<br />$ vi update.sh<br />#!/bin/bash<br /><br />TMPDIR=~/tmp<br />EAIDXPATH=~/.ferris/ea-index<br /><br />cd $TMPDIR<br />find /usr | split -l 5000 -  usr.split.<br />find ~    | split -l 5000 - home.split.<br /><br />export LIBFERRIS_EAINDEX_EXPLICIT_WHITELIST=name,size,mtime,mtime-display,atime,ctime,user-owner-name,group-owner-name,user-owner-number,group-owner-number,inode<br />echo "whitelist: $LIBFERRIS_EAINDEX_EXPLICIT_WHITELIST"<br />cd $EAIDXPATH<br />rm -f write.lock <br />for if in $TMPDIR/*split.*<br />do<br />   echo "Processing $if"<br />   cat $if | feaindexadd -P `pwd` -1<br />done<br /><br /><br /><br />Ironically the arm5 has given me much less trouble overall. One issue seems to be with gcc-4.4x on the n9. Charming little errors like my old friend the undefined __sync_val_compare_and_swap_4 which stops memory mapped boost data structures from working properly and also leaves the clucene-core-2.3.3.4 build laying on the side of the road bleeding. I've hacked the clucene code to get around the atomic errors, but then seem to have found that search results are not accurate. I guess my quick hack there was just bad^TM. Especially since the arm5 produces the right results using the virgin clucene codebase.<br /><br />I've been trying to convince gcc 4.5 and 4.6 to build for me so I can use the updated compiler to generate a proper and working clucene for the device. I seem to run into little build issues after time consuming rebuilds. (uses VFP register arguments, yay). Once I stop compiling compilers then maybe I can get my favourite indexing code on the n9.<span class="net_nemein_favourites">1 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=b93e922c691b11e191c3ab8752fd25432543&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/b93e922c691b11e191c3ab8752fd25432543/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>3 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=b93e922c691b11e191c3ab8752fd25432543&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/b93e922c691b11e191c3ab8752fd25432543/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Ben Martin &lt;monkeyiq@users.sourceforge.net&gt;</author>
            <category>feed:db85272b5cc4c48c874836930690af4e</category>
            <pubDate>Thu, 08 Mar 2012 04:07:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-b93e922c691b11e191c3ab8752fd25432543</guid>
        </item>
        <item>
            <title>The Nokia N9: Going for a spin</title>
            <link>http://monkeyiq.blogspot.com/2012/02/nokia-n9-going-for-spin.html</link>
            <description><![CDATA[
In short, I now have a Nokia n9, and setup a scratchbox for it, and compiled & installed abiword, clawmotia, unison, and libferris for and on the device. If that didn't enlarge your page down key, the longer version now follows ;-)<br /><br />FWIW my impression of the device is very positive. Hardware wise the biggest issue I have is the inability to add more storage to it. A high gb microsd slotted in would make things a whole bunch nicer, mainly for using the device as a music box on the road. The speed of interaction is very nice, and the swipe interface is very easy to get used to. Just flick an app away to minimize it or flick from another screen edge to close it.<br /><br />gstreamer works quite nicely for viewing network streams, though there is a deadzone bar on the logical "bottom" of the screen (left of screen in portrait mode). I noticed this bar in abiword too, so I assume it is an issue with going fullscreen for non Qt native apps.<br /><br />There isn't much to show for unison, as I tend to drive that from the dekstop/laptop end of the connection. Getting it on the device is always a matter for first compiling ocaml and installing that into the scratchbox.<br /><br />One very pleasant surprise is how snappy clawmotia runs on the n9. Startup time is significantly less than on the n900 and the screen operations like swiping the main controls left to get to the jog shuttle page is now at an acceptably smooth speed. I'll have to work up a video of this in action to show the speed of things...<br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzJymPSKnrxsUO5WDAFyN21j4XvoLUubnTtjozwFItnoxNpmK0bBDHJyO8J42Cm5qvogsffqK3D4NpP7YuSfIxt0Ts-r6az_BDHWkZPpr9PsEGZruR7SJvDqME4nRCgS88yJFpzfIKq8o/s1600/2012feb-n9-clawmotia.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 266px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzJymPSKnrxsUO5WDAFyN21j4XvoLUubnTtjozwFItnoxNpmK0bBDHJyO8J42Cm5qvogsffqK3D4NpP7YuSfIxt0Ts-r6az_BDHWkZPpr9PsEGZruR7SJvDqME4nRCgS88yJFpzfIKq8o/s400/2012feb-n9-clawmotia.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5713605342298618786" /></a><br /><br />I got libferris compiled for the n9 too. Using boost::spirit for some of the parsers has dropped one compile time dependency away. I did make both ferris and ferriscreate able to compile in glib2 only mode. You loose one or two apps by doing this, but it also makes the footprint smaller so that I can use it with QML apps without needing to pull in gtk2 from a third party repo just for those apps in ferris itself. Mainly some capplets, gfcreate, and the gfcp and other graphical coreutils reimplementations are lost in building this way. <br /><br />And what is not complete without a screenshot of things on the device? Sorry for the quality of the picture, I need to work out lighting for some device shots a bit better than this adhoc quick shot. Just to tap into the ferris power a tiny bit I decided to mount an XML file as a filesystem and fcat directly into it.. A few of the fun things I plan are a QML client for index/search using the customized maemo index backend in libferris and using the mounted pulseaudio and mounted gstreamer to implement yet another audio player for the device. The index+search in both these apps should be blisteringly fast, given that I could index an NFS mount with 10x the data I could hold on an n810 and search as you type in real time...<br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLz1opb9WNtH3H6h51OQgY124-TO9_qUH7eo7F4JTOZXVyXSaYyd50VCbN7-TDLAtCOGu6B_hDkstgOaSxkThjB9Eh_qolsk6mQHE85VbBU6c20PlK64_M9iNgVUIpN_w-smo2YblA0AI/s1600/2012feb-n9-ferris-xml.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 266px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLz1opb9WNtH3H6h51OQgY124-TO9_qUH7eo7F4JTOZXVyXSaYyd50VCbN7-TDLAtCOGu6B_hDkstgOaSxkThjB9Eh_qolsk6mQHE85VbBU6c20PlK64_M9iNgVUIpN_w-smo2YblA0AI/s400/2012feb-n9-ferris-xml.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5713606695404196098" /></a><br /><br />Abiword proved to be the harder thing to compile for the n9. It seems GTK2/3 has fallen off the device so I got gtk2 from a third party repository. The downside is that the app doesn't run entirely fullscreen and has pretty much no finger friendlyness from gtk2 itself. Oh yeah, the virtual keyboard doesn't come up on text entries in gtk2 either. I might be compiling and installing gtk2 incorrectly on the device, so this complaint about device interaction might be my own fault?<br /><br />I then got libwv and libwmf, following the dependency rabbit down the white hole. Of course my abiword compile has full ODF support in it too! The below screenshot is of one of my sample ODF+RDF documents with the content that links to RDF shown in purple. For more info on RDF in abiword see the abiword talk video from <a href="http://mirror.linux.org.au/linux.conf.au/2012/">lca 2012</a>.<br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiJTgkW9r1hA2dlBkHj2DUBYTY1THepw6cII8dQQDB6mG3KbZ5rOupNNenTxM4afs7SYafnWb_GSir6qkA4IcMybrzVQ2ORk_oNyMgqDXRIlam8LWKw-wAqCHiarrYk6qJ1lNAhQNz-5Y/s1600/2012feb-n9-abiword.JPG"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 266px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiJTgkW9r1hA2dlBkHj2DUBYTY1THepw6cII8dQQDB6mG3KbZ5rOupNNenTxM4afs7SYafnWb_GSir6qkA4IcMybrzVQ2ORk_oNyMgqDXRIlam8LWKw-wAqCHiarrYk6qJ1lNAhQNz-5Y/s400/2012feb-n9-abiword.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5713608371729614994" /></a><br /><br />More fun an games to follow, and I'll post a link to a repo with the debs once I work out where I'm going to host the 100mb odd of files. Not all those are for the device, some are mainly for scratchbox such as the dev packages and full ocaml compiler debs.<span class="net_nemein_favourites">4 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=d2b56b3a60e311e19f9481bfe78f77d777d7&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/d2b56b3a60e311e19f9481bfe78f77d777d7/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>1 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=d2b56b3a60e311e19f9481bfe78f77d777d7&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/d2b56b3a60e311e19f9481bfe78f77d777d7/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Ben Martin &lt;monkeyiq@users.sourceforge.net&gt;</author>
            <category>feed:db85272b5cc4c48c874836930690af4e</category>
            <pubDate>Sun, 26 Feb 2012 15:55:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-d2b56b3a60e311e19f9481bfe78f77d777d7</guid>
        </item>
        <item>
            <title>Mounting statusnet/identica as a filesystem</title>
            <link>http://monkeyiq.blogspot.com/2012/02/mounting-statusnetidentica-as.html</link>
            <description><![CDATA[
With the 1.5.12 release of libferris hot off the presses, I thought I'd blog about how to use the new statusnet mounting. I tried to do some testing against identica at the start, and managed to get myself silenced there ;) I was resurrected within hours once I put forward my case as not-a-trollbot^tm. Anyway, that led me to setup my own local statusnet server for testing against, and now libferris can mount identi.ca and also one or more local servers if you so desire.... yay!<br /><br />There is a little bit of setup required, web keys, secrets and oauth... the normal story. <br />The identica filesystem contains a directory for each server you have setup in ~/.ferris/identica. To update my public status I just write to the status file in my identica account:<br /><br />$ echo "this is coming from the console via libferris, mounting the public statusnet ;-p" \<br />| ferris-redirect identica://identica/status<br /><br />To see what has been going on I can list the timeline directory, using "-0" to get libferris to tell me what metadata is interesting for that directory instead of viewing the protection bits and other non interesting information.<br /><br />$ fls -0 identica://identica/timeline<br />89868729        Welcome to Identi.ca, @monkeyiq!        Welcome Bot     12 Feb  2 03:53<br />...<br /><br />There is also support for direct messaging through the filesystem, seeing retweets, friends, and mentions.<br /><br />Now for the details... Configuration happens through the virtual filesystem. Each statusnet server you want to mount has it's own directory inside ~/.ferris/identica. The configuration directory lists the base URL for performing REST requests on that server and the prefix of where the webkey and secret are to live. For the public identi.ca server I have the following:<br /><br />$ pwd<br />~/.ferris/identica/identica<br />$ cat rest_base <br />https://identi.ca/api/<br />$ cat token_prefix <br />identica<br /><br />And the webkeys go in a file in ~/.ferris prefixed with the token_prefix above:<br />$ cat ~/.ferris/identica-api-key.txt <br />5045332...<br /><br />I do not distribute web keys, so you need to go to http://identi.ca/settings/oauthapps and create one yourself.<br /><br />If you have a private statusnet server foobar then you create ~/.ferris/identica/foobar with the REST url for it, and foobar as the token_prefix. Then put the web API key into ~/.ferris/foobar-api-key.txt.<br /><br />To setup the oauth part, we use our old friend capplet-auth. Again for our foobar custom server replace the auth-with-site with foobar instead. This will give you a URL to visit to authorize your webapp (libferris) on your account. You'll be given a PIN to copy back onto the console and then you should be setup. <br /><br />$ ferris-capplet-auth --auth-service identica --auth-with-site identica<span class="net_nemein_favourites">6 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=bfbc7a225dbf11e18c98dd01dbe4b6bab6ba&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/bfbc7a225dbf11e18c98dd01dbe4b6bab6ba/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=bfbc7a225dbf11e18c98dd01dbe4b6bab6ba&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/bfbc7a225dbf11e18c98dd01dbe4b6bab6ba/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Ben Martin &lt;monkeyiq@users.sourceforge.net&gt;</author>
            <category>feed:db85272b5cc4c48c874836930690af4e</category>
            <pubDate>Wed, 22 Feb 2012 17:13:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-bfbc7a225dbf11e18c98dd01dbe4b6bab6ba</guid>
        </item>
        <item>
            <title>Searching again (400ms -&gt; 2ms)</title>
            <link>http://monkeyiq.blogspot.com/2011/05/searching-again-400ms-2ms.html</link>
            <description><![CDATA[
The problem statement: you want to search for a file using any arbitrary substring contained in the file url. This is deceptively hard, if you think in a relational db way, you want something "like %foo%" where the leading percent will force indexes to be considered redundant and a sequential scan to ensue. If you try instead to break up the file's URL into words and use a full text indexing solution you will find your old friend the leading percent again, like <a href="http://lucene.apache.org/java/2_3_2/queryparsersyntax.html#Wildcard%20Searches">here for Lucene</a>.<br /><br />One easy way to use full text indexing style and allow substrings is to cheat. First disable word stemming (ie, dont turn diving and dive into a stemmed "dive" word). Then for each word to be added to the full text index, shift it left from 1..10 times. So wonderful, onderful, nderful, derful, erful etc are all added as words for the same URL. This is most simply accomplished using a postgresql function to do the shifting. <br /><br />Then when you search for a substring foo you want to find to_tsquery('simple,'foo:*') as a fulltext query on your url column. As prefix searches are allowed in fulltext index engines like Lucene and postgresql's TSearch2 engine, this evaluates quite quickly. <br /><br />For 200,000 URLs when using the raw regex match "~" in postgresql you might see 400ms evaluation times, the same data using a gin index on to_tsvector('simple',fnshiftstring(url)) might return in 2-3ms. Of course the index can't always handle your regular expression, but if you can tease out substrings which must be present from your regular expression, a shifted gin index could drop evaluation times for you. eg, .*[Ff]oob([0-9]... could use a shifted search for "oob" as a prefilter to full regular expression evaluation.<br /><br />Getting down to a few ms evaluation allows GUIs to return some sample results as you type in your regular expression. This speed up will be available in 1.5.6+ of libferris.<br /><br />A while ago I released <a href="http://monkeyiq.blogspot.com/2009/01/searching-indexes-on-maemo-device.html">an engine for maemo</a> with statistical spatial indexing for regular expression evaluation. It's an interesting problem IMHO, and its also a very common one.<span class="net_nemein_favourites">3 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=e5d42318752611e0aa2259374bf35cbd5cbd&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/e5d42318752611e0aa2259374bf35cbd5cbd/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=e5d42318752611e0aa2259374bf35cbd5cbd&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/e5d42318752611e0aa2259374bf35cbd5cbd/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Ben Martin &lt;monkeyiq@users.sourceforge.net&gt;</author>
            <category>feed:db85272b5cc4c48c874836930690af4e</category>
            <pubDate>Mon, 02 May 2011 03:12:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-e5d42318752611e0aa2259374bf35cbd5cbd</guid>
        </item>
        <item>
            <title>Change Tracking: Why?</title>
            <link>http://monkeyiq.blogspot.com/2011/04/change-tracking-why.html</link>
            <description><![CDATA[
As some of my past posts have mentioned, the OASIS group is currently working out how it wishes to extend support for change tracking in ODF. The change tracking feature allows you to have an office application remember what changes you have made and associate them with one or more revisions. There are many examples where governments might want such traceability, but small businesses are likely to find this functionality valuable too.<br /><br />Late last year there was an <a href="http://www.odfplugfest.be/">ODF plugfest held in Brussels</a> where it was decided that an <a href="http://www.opendocsociety.org/news/advanced-document-collaboration-sc-launched-at-oasis">Advanced Document Collaboration</a> subcommittee should be formed to work out how to serialize tracked changes into ODF.<br /><br />There are currently two proposals. One which is <a href="http://lists.oasis-open.org/archives/office-comment/201007/msg00010.html">generic</a> and tracks how the XML of the ODF is modified over time, and an <a href="http://lists.oasis-open.org/archives/office-collab/201103/msg00007.html">extension</a> to the limited change tracking that already exists in ODF 1.2.<br /><br />As my previous posts have mentioned, I'm involved in making abiword able to produce and consume ODF files which contain tracked changes in the format of the generic proposal.<br />See <a href="https://github.com/monkeyiq">my github</a> for abiword and its change tracking test suite. Ganesh Paramasivam has been working to make Calligra and KOffice support the generic proposal too, and Jos van den Oever has done some hacking to enrich <a href="http://webodf.org/ctdemo/cttest.html">WebODF</a> for change tracking.<br /><br />As I have been going along implementing things in abiword, I've been clarifying some points on the oasis <a href="http://lists.oasis-open.org/archives/office-collab/201104/threads.html">office-collab</a> mailing list, and participating in some of the general conversation there too. <br /><br />Some of the differences between the two proposals can have a <a href="http://lists.oasis-open.org/archives/office-collab/201104/msg00092.html">large impact</a> to the complexity of implementing change tracking in applications. Folks who are involved in office applications which use ODF might like to read up on the proposals and have their say on the future of this feature before a decision is made for you.<br /><br />I think it is important for ODT to include a good, complete change tracking specification because it would offer all people the ability to collaborate on documents and businesses the change to know the exact extent of modifications made to documents by each party.<span class="net_nemein_favourites">5 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=933f7cd26edd11e09a74e908a04e94929492&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/933f7cd26edd11e09a74e908a04e94929492/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=933f7cd26edd11e09a74e908a04e94929492&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/933f7cd26edd11e09a74e908a04e94929492/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Ben Martin &lt;monkeyiq@users.sourceforge.net&gt;</author>
            <category>feed:db85272b5cc4c48c874836930690af4e</category>
            <pubDate>Sun, 24 Apr 2011 17:40:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-933f7cd26edd11e09a74e908a04e94929492</guid>
        </item>
        <item>
            <title>From Canon CR2 Raw files to the Web</title>
            <link>http://monkeyiq.blogspot.com/2011/01/from-canon-cr2-raw-files-to-web.html</link>
            <description><![CDATA[
A potentially interesting artefact of me playing around with a Canon DSLR is that libferris now has some initial support for CR2 "raw" files. Complements of course go to the dcraw library and tools for the heavy lifting. The upshot is that ferriscp ~/cam/foo.CR2 flickr://me/upload now works as expected. Once I update my maemo build, this should also let me use an n900 with 3G to upload from RAW while on the move. <br /><br />I need to include stuff for ICC profiles and the like but at least the Web services get what they expect and everything runs smoothly, and it will for you too next release (TM). I really should look into mounting the kipi plugins as a filesystem sometime, they offer some awesome Web import/export functionality, ripe for a filesystem I tell's ya.<br /><br />I still need to add "rgba-32bpp" metadata support for CR2 files. As you can imagine from the name, if you read this metadata for a jpeg, png or other supported image file, libferris decodes the image to 32 bit RGBA byte values for you. It might also be interesting to create another "file as filesystem" design where a bunch of virtual files are offered to see the small thumbnail, the roughly 1080p sized thumbnail or the ICC corrected rendering of the CR2 and others. Such virtual files are really handy for drag and drop to other filesystems ;) <br /> <br />I might hunt around for some Nikon raw files to add support for those too at some point. Though there is nothing like having a camera generating files to make you want to make your software support those files.<span class="net_nemein_favourites">5 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=805b0e3a252a11e0a45aed352ceebdecbdec&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/805b0e3a252a11e0a45aed352ceebdecbdec/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=805b0e3a252a11e0a45aed352ceebdecbdec&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/805b0e3a252a11e0a45aed352ceebdecbdec/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Ben Martin &lt;monkeyiq@users.sourceforge.net&gt;</author>
            <category>feed:db85272b5cc4c48c874836930690af4e</category>
            <pubDate>Thu, 20 Jan 2011 21:28:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-805b0e3a252a11e0a45aed352ceebdecbdec</guid>
        </item>
        <item>
            <title>Sharing is Caring...</title>
            <link>http://monkeyiq.blogspot.com/2010/11/sharing-is-caring.html</link>
            <description><![CDATA[
My <a href="http://fuuko.libferris.com/maemo/n900/repository/">repository</a> now contains a steaming ferris-sharing-plugin_0.2_armel.deb which will hook up libferris to the Nokia sharing system on the n900. This lets you click the funky Brussels atom building "sharing" icon from many places and copy images to flickr, 23hq, facebook.<br /><br />There isn't much feedback at the moment, that is planned for "the future". You might also like to install the ImageMagick from my repo. Simply expand it to /opt and make a link /usr/lib/ImageMagick-6.6.0 -> /opt/ImageMagick-6.6.0/lib/ImageMagick-6.6.0. This gives you proper handling of exif orientation during scaling prior to upload with libferris.<br /><br />I also have some tweaks to libferris itself which will be in the upcoming 1.5.1 release to help with annotations etc during upload. The next step is to get vimeo and youtube upload support happening too, since libferris can already upload to those.<span class="net_nemein_favourites">3 <a href="http://maemo.org/news/?net_nemein_favourites_execute=fav&net_nemein_favourites_execute_for=1a9216faf11a11df93e5b3a6e29976127612&net_nemein_favourites_url=https://maemo.org/news/favorites//json/fav/midgard_article/1a9216faf11a11df93e5b3a6e29976127612/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-favorite.png" style="border: none;" alt="Add to favourites" title="Add to favourites" /></a>0 <a href="http://maemo.org/news/?net_nemein_favourites_execute=bury&net_nemein_favourites_execute_for=1a9216faf11a11df93e5b3a6e29976127612&net_nemein_favourites_url=https://maemo.org/news/favorites//json/bury/midgard_article/1a9216faf11a11df93e5b3a6e29976127612/" class="net_nemein_favourites_create"><img src="http://static.maemo.org:81/net.nemein.favourites/not-buried.png" style="border: none;" alt="Bury" title="Bury" /></a></span>]]></description>
            <author>Ben Martin &lt;monkeyiq@users.sourceforge.net&gt;</author>
            <category>feed:db85272b5cc4c48c874836930690af4e</category>
            <pubDate>Mon, 15 Nov 2010 15:46:00 +0000</pubDate>
            <guid>http://maemo.org/midcom-permalink-1a9216faf11a11df93e5b3a6e29976127612</guid>
        </item>
    </channel>
</rss>
