Centering A Header Image In jQuery Mobile

I needed to replace the header text in a jQuery Mobile application with an image.

I first tried wrapping the image in the <h1> tag, but that adds quite a large margin and cuts off some of my image.

The solution I used was to instead add a wrapper div that centers everything in it. My header ended up looking like this…

Header

center-wrapper is a custom style defined like this…

.center-wrapper {
  text-align: center;
}
.center-wrapper * {
  margin: 0 auto;
}

There may be a better way to do this, but this works for now.

Draw Something Solver – The Platform

I have been putting some more thought into how to build my Draw Something Solver.

I have decided as I use Draw Something on my iPhone 4S, the solver should really run on there. This means coding using Objective C, or using HTML 5 and JavaScript.

As I haven’t written an HTML and JavaScript application for a while, and as it’s more fun, I think this should be the technology to use.

The only difficulty I can see is in getting screenshots from Draw Something into the application. Phonegap looks like it exposes some functionality to achieve this in JavaScript, so it looks like a good idea to use this as well. It also gives me the bonus of being able to create a native iOS application I could choose to upload to the App Store if I wanted, and also look a producing a version for Android in the future.

To give the application a native look and feel, using something like jQTouch or jQuery Mobile would make sense. jQuery Mobile has quite a lot of buzz at the moment and I’ve not had the opportunity to use it before, so I think I’ll try it out in this project.

Atom Posting To Movable Type

For the Q Awards 2007, we wanted to have minute by minute blogging.

q awards minute by minute

We used Movable Type for the website, but didn’t want to have to rely on having a laptop available to blog from, so blogging from a mobile phone was the approach we took.

Originally we looked at Twitter for this, but we worried about connection speed. We also looked at Nokia Lifeblog, while good, it doesn’t really allow for just headline posting. Finally, we took the custom code approach.

Movable Type has an Atom interface, it’s what Nokia Lifeblog uses. This lets us post articles, so all we needed was a suitable client. Thankfully, using Perl, there is XML::Atom::Client.

Ben Hammersley provides an great tutorial on using the Atom API in Movable Type.

My code needed to take a line of text and post automatically to Movable Type in a certain category (called “livefeed”). I built a really simple HTML page that could be used by any internet enabled phone. It had one text box and one submit button. Copy entered here and submitted would appear in the Movable Type blog automatically.

I needed some glue Perl code behind this page to make this happen. It turned out to be really simple, and here’s the core functionality. I won’t bore you with CGI handling or display code, just the Atom meat.

my $api = XML::Atom::Client->new;
$api->username($username);
$api->password($password);
my $dc = XML::Atom::Namespace->new(dc => 'http://purl.org/dc/elements/1.1/');
my $entry = XML::Atom::Entry->new;
$entry->title($title);
$entry->content('');
$entry->set($dc, 'subject', 'livefeed');
my $edituri = $api->createEntry($posturl, $entry);
if ($edituri) {
## posted ok
} else {
## not posted, $api->errstr has the error message;
}

This code assumes you have a few variables in place, those are

  • $username – the poster’s username
  • $password – the poster’s web services password
  • $posturl – the web service’s post url
  • $subject – the copy to post to the blog

Movable Type has two different passwords per user, it is important we use the webservices password and not the users normal Movable Type password.

Now we were posting and creating entries each post, we wanted to show them all on one page. my collegue Ross wrote this block of code to display the posts.

<MTEntries category="livefeed">
<li>
<MTIfNonEmpty tag="EntryTitle">
<p class="time"><$MTEntryDate format="%I:%M %p"$></p>
<p><$MTEntryTitle$></p>
</MTIfNonEmpty>
</li>
</MTEntries>

This turned out to be a nice, fast solution to getting content up quickly on the day.

Using Nokia Lifeblog On Vodafone UK

Those of you in the UK and using Nokia Lifeblog on Vodafone contract may have noticed it no longer works.

We have problems at the moment with Vodafone’s new mobile optimising technology. This takes a page and tries to fit it onto a mobile phone screen. It does this by pretending to be a more competant browser in it’s HTTP headers.

However, in faking the HTTP headers it also strips out the WSSE authentication that Lifeblog uses for it’s security, meaning that each post will fail as unauthorised.

There is currently no easy work around for this except to change network or to register your site with Bango as they are apparently whitelisting sites to bypass this new proxy.

Atom WSSE Authentication Using C# .NET

I received an email asking for a hand with a C# .NET implementation of the WSSE atom authentication for Nokia’s Lifeblog.

I took a look at this as I’m brushing up on my C# at the moment for work, and I relish a challenge.

As there are two different methods of authentication depending on the version of Lifeblog being used, the code has to handle this.

The first method is to append the nonce, timestamp and password together, create a SHA1 hash with this and Base64 encode the result. The second way is almost the same, but the nonce has to be Base64 decoded first before being appended with the timestamp and password.

See my previous article on WSSE Authentication For Atom Using Perl for more details on how this works.

The first method can be calculate a digest value using code like this.

string mystring = nonce + created + password;
SHA1Managed SHhash = new SHA1Managed();
string mydigest = Convert.ToBase64String(SHhash.ComputeHash(System.Text.Encoding.ASCII.GetBytes(mystring)));

My first attempt at the second method looked very similar.

string mystring = (System.Text.Encoding.ASCII.GetString(Convert.FromBase64String(nonce))) + created + password;
SHA1Managed SHhash = new SHA1Managed();
string mydigest = Convert.ToBase64String(SHhash.ComputeHash(System.Text.Encoding.ASCII.GetBytes(mystring)));

Looks OK on the surface, but it fails to validate when posting from my Nokia N93 phone.

What’s gone wrong?

Well looking in the debugger, the process of converting the nonce back from the array of bytes Convert.FromBase64String() produces and appending them to form mystring corrupts the data compared with the Perl version in my previous article.

We know the approach is basically right, so we need to cut out this corrupting step.

The best way to do this is to keep the data in byte arrays as we need the data in this format anyway to computer the SHA1.


System.Text.Encoding enc = System.Text.Encoding.UTF8;
byte[] noncebytes = enc.GetBytes(nonce);
byte[] passwordbytes = enc.GetBytes(password);
byte[] createdbytes = enc.GetBytes(created);
byte[] code = new byte[nonce.Length + password.Length + created.Length];
Array.Copy(nonce, code, nonce.Length);
Array.Copy(created, 0, code, nonce.Length, created.Length);
Array.Copy(password, 0, code, nonce.Length + created.Length, password.Length);
System.Security.Cryptography.SHA1Managed SHhash = new System.Security.Cryptography.SHA1Managed();
string digest = Convert.ToBase64String(SHhash.ComputeHash(code));

I’m sure there is a nicer way to achieve the appending of the 3 arrays together in C#, but this works for now.

We can tie this up to form a nice static class to handle our WSSE authentication.

/// <summary>
/// Computes WSSE codes from input for validation.
/// </summary>
public static class WSSE {
/// <summary>
/// Calculate the digest.
/// </summary>
/// <param name="password">A string with your unencrypted password.</param>
/// <param name="nonce">The nonce the digest is to be created with as a string.</param>
/// <param name="created">The timestamp as a string.</param>
/// <returns>A string containing the digest.</returns>
public static string GetDigest(string password, string nonce, string created)
{
return GetDigest(password, nonce, created, System.Text.Encoding.ASCII);
}
/// <summary>
/// Calculate the digest.
/// </summary>
/// <param name="password">A string with your unencrypted password.</param>
/// <param name="nonce">The nonce the digest is to be created with as a string.</param>
/// <param name="created">The timestamp as a string.</param>
/// <param name="enc">The System.Text.Encoding to use.</param>
/// <returns>A string containing the digest.</returns>
public static string GetDigest(string password, string nonce, string created, System.Text.Encoding enc)
{
byte[] noncebytes = enc.GetBytes(nonce);
byte[] passwordbytes = enc.GetBytes(password);
byte[] createdbytes = enc.GetBytes(created);
return generatecode(noncebytes, passwordbytes, createdbytes);
}
/// <summary>
/// Calculate the alternative digest.
/// </summary>
/// <param name="password">A string with your unencrypted password.</param>
/// <param name="nonce">The nonce the digest is to be created with as a string.</param>
/// <param name="created">The timestamp as a string.</param>
/// <returns>A string containing the digest.</returns>
public static string GetDigestAlt(string password, string nonce, string created)
{
return GetDigestAlt(password, nonce, created, System.Text.Encoding.ASCII);
}
/// <summary>
/// Calculate the alternative digest.
/// </summary>
/// <param name="password">A string with your unencrypted password.</param>
/// <param name="nonce">The nonce the digest is to be created with as a string.</param>
/// <param name="created">The timestamp as a string.</param>
/// <param name="enc">The System.Text.Encoding to use.</param>
/// <returns>A string containing the digest.</returns>
public static string GetDigestAlt(string password, string nonce, string created, System.Text.Encoding enc)
{
byte[] noncebytes = Convert.FromBase64String(nonce);
byte[] passwordbytes = enc.GetBytes(password);
byte[] createdbytes = enc.GetBytes(created);
return generatecode(noncebytes, passwordbytes, createdbytes);
}
private static string generatecode(byte[] nonce, byte[] password, byte[] created)
{
byte[] code = new byte[nonce.Length + password.Length + created.Length];
Array.Copy(nonce, code, nonce.Length);
Array.Copy(created, 0, code, nonce.Length, created.Length);
Array.Copy(password, 0, code, nonce.Length + created.Length, password.Length);
System.Security.Cryptography.SHA1Managed SHhash = new System.Security.Cryptography.SHA1Managed();
return Convert.ToBase64String(SHhash.ComputeHash(code));
}
/// <summary>
/// Validates password, nonce and created create the same digest code as digest.
/// </summary>
/// <param name="password">A string with your unencrypted password.</param>
/// <param name="nonce">The nonce the digest is to be created with as a string.</param>
/// <param name="created">The timestamp as a string.</param>
/// <param name="digest">The digest to validate the password, nonce and created strings against as a string.</param>
/// <returns>true or false depending on wether the digest validates</returns>
public static bool IsValid(string password, string nonce, string created, string digest)
{
return digest == GetDigest(password, nonce, created) || digest == GetDigestAlt(password, nonce, created);
}
/// <summary>
/// Validates password, nonce and created create the same digest code as digest.
/// </summary>
/// <param name="password">A string with your unencrypted password.</param>
/// <param name="nonce">The nonce the digest is to be created with as a string.</param>
/// <param name="created">The timestamp as a string.</param>
/// <param name="digest">The digest to validate the password, nonce and created strings against as a string.</param>
/// <param name="enc">A System.Text.Encoding encoding.</param>
/// <returns>true or false depending on wether the digest validates.</returns>
public static bool IsValid(string password, string nonce, string created, string digest, System.Text.Encoding enc)
{
return digest == GetDigest(password, nonce, created, enc) || digest == GetDigestAlt(password, nonce, created, enc);
}
}

We can test the code using the following code snippet.

string digest = "nvvHvNuLb+7wGFrop+cC2tjgQqs=";
string nonce = "bgZ4BHcjmWcg7gVhCxyQOg==";
string timestamp = "2006-04-25T19:40:45Z";
string password = "a";
if (WSSE.IsValid(password, nonce, timestamp, digest, System.Text.Encoding.UTF8))
{
Console.WriteLine("valid");
}
else
{
Console.WriteLine("invalid");
}

This gives us the result “valid” as we’d hope.

To save you time, feel free to download the C# code
WSSE.cs.

Programming Bluetooth Using Python

I discovered the pybluez project that brings bluetooth connectivity to Python today. It’s been around for a while and is compatible with both Windows (running XP) and Linux (running the bluez stack).

I installed it using the ready made windows installer and it ran first time. It’s very simple and easy to use.

I tweaked the example inquiry.py file by Albert Huang and set it up to show all the services on nearby devices.

Here’s the code…

import bluetooth
print "looking for nearby devices..."
nearby_devices = bluetooth.discover_devices(lookup_names = True, flush_cache = True, duration = 20)
print "found %d devices" % len(nearby_devices)
for addr, name in nearby_devices:
print " %s - %s" % (addr, name)
for services in bluetooth.find_service(address = addr):
print " Name: %s" % (services["name"])
print " Description: %s" % (services["description"])
print " Protocol: %s" % (services["protocol"])
print " Provider: %s" % (services["provider"])
print " Port: %s" % (services["port"])
print " Service id: %s" % (services["service-id"])
print ""
print ""

Here’s a quick run through of the code.

Firstly we need to import the bluetooth class to give us access to all that lovely bluetooth functionality.

We now look for nearby devices using bluetooth.discover_devices. I’m adding a few parameters as well. lookup_names is set to True so we can get the devices names instead of the just their addresses, and flush_cache is also set to True to make sure we always look for fresh information. Finally we set duration to 20, meaning we look for devices for up to 20 seconds. This is a bit excessive, but useful when testing.

We should have a list of devices now, assuming some were found, so we now loop over them.

We print out the name and address then look for services offered by the device by calling the bluetooth.find_service method and passing in the device’s address.

This returns a list of dictionaries describing the services available. We iterate over this and print out details.

That’s the code, now here’s a few results. I ran this on the train home and discovered 7 active bluetooth devices offereing a variety of services. I won’t bore you with them all, so here’s the entry for my Nokia N93.

Perl - 00:16:BC:30:D8:76
Name:        AVRCP Target
Description: Audio Video Remote Control
Protocol:    L2CAP
Provider:    Symbian Software Ltd.
Port:        23
Service id:  None
Name:        Hands-Free Audio Gateway
Description:
Protocol:    RFCOMM
Provider:    None
Port:        28
Service id:  None
Name:        Headset Audio Gateway
Description:
Protocol:    RFCOMM
Provider:    None
Port:        29
Service id:  None
Name:        SyncMLClient
Description:
Protocol:    RFCOMM
Provider:    None
Port:        10
Service id:  None
Name:        OBEX File Transfer
Description:
Protocol:    RFCOMM
Provider:    None
Port:        11
Service id:  None
Name:        Nokia OBEX PC Suite Services
Description:
Protocol:    RFCOMM
Provider:    None
Port:        12
Service id:  None
Name:        SyncML DM Client
Description:
Protocol:    RFCOMM
Provider:    None
Port:        13
Service id:  None
Name:        Nokia SyncML Server
Description:
Protocol:    RFCOMM
Provider:    None
Port:        14
Service id:  None
Name:        OBEX Object Push
Description:
Protocol:    RFCOMM
Provider:    None
Port:        9
Service id:  None
Name:        Dial-Up Networking
Description:
Protocol:    RFCOMM
Provider:    None
Port:        2
Service id:  None
Name:        Imaging
Description:
Protocol:    RFCOMM
Provider:    None
Port:        15
Service id:  None

As you can see it offers a lot of interesting services, but two have caught my eye and call for a bit more investigation later.

Firstly there is the Imaging service on port 15. I wonder what that does? Does it take input from a remote camera?

Secondly there is AVRCP Target the Audio Visual Remote Control Target from Symbian. I wonder if this means I can use a seperate bluetooth device to control my Nokia N93 when it’s playing back video?

A quick google reveals a (confidential?) specification document for AVRCP

Nokia Lifeblog Posting Protocol Update

Nokia seem to have updated their Atom upload protocol in recent versions of their phones.

I’ve just got hold of a Nokia N93 and tried posting to this blog using Lifeblog and the new Web Upload functionality in the Gallery with use the Atom protocol.

These postings were failing with a bad password error. I know my username and password are correct and they worked using my old phone.

As I had written my own blogging software, and it’s Atom upload functionality I was able to debug the messages being sent from the phone to the server.

It turns out that newer versions of Nokia Lifeblog encrypt their passwords differently to older versions.

They use a method called WSSE. See my previous article on how to use WSSE with Perl for more details on how this works, plus example code.

Very quickly, the password isn’t sent, but a digest of the password and the values to generate the digest yourself are. These are then encoded using base64 for transmission over the internet.

Older versions (pre Lifeblog 2.0) expect a value called the nonce to be used as sent while the password digest is generated. Newer versions (Lifeblog 2.0+) expect the nonce to be decoded from base64 before the digest is generated.

Once I had worked out what was going on, it was simple to modify my code to check against both possible versions of the password digest. This means I can now post using old and new versions of Lifeblog, or the web upload functionality.

Here’s a very quick bit of example Perl code. Assume $my_digest is the digest with the original nonce left in place and $my_alternative_digest is the digest with the nonce decoded first. $digest is the digest sent my incoming Atom request.

## example perl code to check digests)
if (($digest eq $my_digest) || ($digest eq $my_alternative_digest)) {
## one of the digests has validated, so continue here
} else {
## neither digests has validated, so return invalid password responses here.
}

I don’t think this change has been communicated very well amongst the development community. It has probably come about due to changes in the Atom spec, but (admittedly only quickly) checking the documentation I’ve not found it.

I will be updating my WSSE validation example accordingly, and a new version of AtomServer.pm that allows posting from Lifeblog 2.0 to Movable Type shortly.

Posting To Movable Type 3.3 Using Nokia Lifeblog

We’ve been installing Movable Type as a blogging solution at work for various sites recently.

We’d been using Typepad, the hosted version of Movable Type for a while, but wanted some extra flexibility and functionality.

One problem we came across was the lack of support for Nokia Lifeblog on Movable Type, compared to Typepad.

Thankfully Martin Higham has worked on this in the past, and even used my old notes on the Nokia Lifeblog Posting Protocol.

However, the current version of Movable Type is 3.3, and Martin’s work only extends to 3.2.

I took Martin’s code, which modifies AtomServer.pm and modified it so it works on Movable Type 3.3. You can download my Nokia Lifeblog compatible AtomServer.pm for Movable Type 3.3 here.

Make sure you follow Martin’s instructions for Movable Type 3.2 as the method is exactly the same and the same caveats apply (namely, this could well break other Atom tools that use your blog as it has to disable some WSSE authentication).

I hope you find it useful!

UPDATE: 22nd November 2006

With version 2.0 of Lifeblog and web upload functionality from Nokia phones, the authentication method has changed slightly. A new version of AtomServer.pm that works with Lifeblog 2.0 is now available.

UPDATE: 26th June 2007

Neils Berkers has been in touch to say he’s adapted the script so it now works with Movable Type 3.35, Lifeblogging Fixed.

Interesting Nokia Lifeblog Bug

Now here’s an interesting bug in Nokia Lifeblog application on my Nokia 3230 phone.

If you take a photo using the camera and then post it to the web using Lifeblog, it won’t then let you send the image via MMS. Instead, it complains “unable to send copyright protected item”, even though I own the copyright of my own picture.

This is running version 1.51.2 of the Lifeblog software.