Friday, 16 November 2007

St Pancras International

I've been going through St Pancras station every week for 2 months or so. But when I came back to London yesterday, it no longer was St Pancras, it was St Pancras International, now that the Eurostar trains leave from there rather than Waterloo. I have to say the new station is large and impressive, of course full of shops in case you want to do a bit of shopping before getting on the train. It is amusing how they insist on the International bit though. Should Paris Gare du Nord be renamed Gare Internationale de Parid Nord?

Saturday, 3 November 2007

DHCP and Dynamic DNS on Ubuntu Server

The cunning plan

I have broadband Internet at home and to connect to the outside world I use a Wi-Fi ADSL router. This router also acts as a DHCP and DNS server. The DHCP function is what allows any machine I connect to my home network to dynamically obtain an IP address. The DNS function is what resolves names into IP addresses, for example, the DNS will tell you that www.blogger.com is really called blogger.l.google.com and its address is 72.14.221.191. This is all well and good: when I switch on one of my computers and let it connect to the network, it will get its IP address from the router, which will also tell it to use the same router for names service queries. The router itself knows to delegate requests to my ISP's DNS so the new computer on the network has full access to the Internet. If I connect a second computer on the network, the same happens and both can have access to the Internet at the same time. Great! However, they don't know anything about each other. If I connect the two machines called nuuk and helsinki to my network, the DNS server is unable to tell either what the address of the other one is. This is because the DNS in the router is fairly basic and doesn't know to update its database when a new machine gets allocated an address by the DHCP service. Basically, we'd want a DHCP server that can communicate with the DNS server and tell it oy, I've got a new machine on the network, here's its name and the address I just allocated to it when a new machine comes online.

So what's a geek to do? Set up his own DHCP and DNS server obviously! And make them talk together. Luckily, I have an old workstation that I haven't used for many years and that I was planning to throw away: it's a bit dated but it should be exactly what I need for this. Then my recent experience with Ubuntu suggests that the recently released Ubuntu 7.10 Gutsy Gibbon Server Edition might be exactly what I need for the job. So let's get started.

The hardware

I said I had this dated workstation lying around. It's an 8 year old piece of kit that was originally built to run Red Hat Linux. It wasn't very good at it at the time because Linux was not quite ready for the desktop at the time but it was a wicked piece of kit at the time:

CPU
Dual 666 MHz Pentium III (Coppermine)
Memory
256 Mb
Storage
10 Gb SCSI hard disk: I got a SCSI controller rather than the cheaper IDE because I wanted to connect my SCSI negative scanner to it

There's plenty of horsepower for what we want to do, more than enough storage and the memory should be fine if the operating system we install on it is lightweight enough. This is where the Server Edition of Ubuntu comes into play: it's meant for server hardware and doesn't have the nice but memory hungry desktop front-end, it's all command line driven. No glitz, just useful stuff. This means that even the latest version of Ubuntu Server should be able to run comfortably within 256 Mb and there should be no need to fall back on an older version of the operating system.

Preparation

Before we start, there is a bit of planning to do. As the new server will be the authority in terms of assigning IP addresses on the network, it needs to have its own address fixed. We also need to decide on a range of addresses to allocate through DHCP. As the router is currently using the address 192.168.1.254, it makes sense to leave it as it is. Here is the network configuration I am aiming for:

ADSL router
192.168.1.254
New DHCP and DNS server
192.168.1.253 and I'll call it szczecin
DHCP address range
From 192.168.1.100 to 192.168.1.200
Domain name
home: no need to have an official domain name and in fact it's probably better if it's not something that could be a valid Internet domain

One thing I did before installing anything and that you may want to do as well is boot the new server with the desktop Ubuntu Live CD just to check that all the hardware is supported. The server edition is not a live CD so it doesn't give you the opportunity to check that before going ahead.

Installing Ubuntu

Let's plug everything together first: a monitor, a keyboard, no need for a mouse as it's all command line, power and VGA cables. And we might as well connect it to the network immediately so we'll need a network cable as well.

Start the machine, put the CD in the drive and follow the instructions. As usual with Ubuntu, it's quite easy. There are only a few things to be careful about:

  • When it asks how to partition the disk, choose the automatic option using the whole disk.
  • When it gets to network setup, cancel the DHCP client setup and configure the network manually. Give it the IP address chosen above and a name. When it asks for a DNS server, put its own address.
  • Don't forget to select DNS in the list of additional services you want to install. I would suggest you also install the SSH server to that you can connect to the machine remotely.

At the end of the installation, the machine pops the CD out and asks you to confirm a restart. No nice funky Ubuntu logo when it restarts, it's all text and you are faced with a command line login prompt. If you want to keep working from the console you can, or you can just connect from any other machine connected to the same network using SSH, provided you installed the SSH server obviously. So let's login to our new server.

Configuring a simple static DNS

The first step is to configure a simple static DNS service that is able to resolve names for the router and the new server. Ubuntu 7.10 comes with BIND 9.4.1 as a DNS server and I have used O'Reilly's DNS and BIND book as my reference. The copy I have is the 3rd edition rather than the 5th but it is more than adequate for my purpose.

The very first task is to make sure we have the necessary basics in /etc/hosts:

127.0.0.1       localhost
192.168.1.253   szczecin.home szczecin
192.168.1.254   gateway.home  gateway

Then we need to reproduce that in the BIND configuration. The first task is to find where the BIND configuration files are. On Ubuntu, you will find them in /etc/bind with a modular default set of files:

$ ls /etc/bind
db.0
db.127
db.255
db.empty
db.local
db.root
named.conf
named.conf.local
named.conf.options
rndc.key
zones.rfc1918

The main file, named.conf is constructed in such a way that for most simple installations, you should only have to change named.conf.local, which is exactly what we are going to do. But first, we need to create our database files. Let's start with the forward lookup, which we will name db.home

home.           IN SOA  szczecin.home. admin.email.address. (
                                1          ; serial
                                10800      ; refresh (3 hours)
                                3600       ; retry (1 hour)
                                604800     ; expire (1 week)
                                86400      ; minimum (1 day)
                                )
home.           IN NS   szczecin.home.

localhost.home. IN A    127.0.0.1

szczecin.home.  IN A    192.168.1.253
gateway.home.   IN A    192.168.1.254

The first entry specifies the Start Of Authority, identifying that our server is the best source of information for this zone. The admin.email.address. bit can be any admin email address you want to advertise, with the @ sign replaced by a dot. It doesn't have to be a valid address if you don't want it to be. The second entry identifies this machine as the name server for this zone. If you had multiple servers, you'd need one line per server. The following lines reflect what we have in /etc/hosts.

After that, we can work on the reverse lookup file, which will be named db.192.168.1:

1.168.192.in-addr.arpa.     IN SOA  szczecin.home. admin.email.address. (
                                1          ; serial
                                10800      ; refresh (3 hours)
                                3600       ; retry (1 hour)
                                604800     ; expire (1 week)
                                86400      ; minimum (1 day)
                                )
1.168.192.in-addr.arpa.     IN NS   szczecin.home.

253.1.168.192.in-addr.arpa. IN PTR  szczecin.home.
254.1.168.192.in-addr.arpa. IN PTR  gateway.home.

This file just defines the opposite mapping. The first two entries follow the same format that in the other file. Note how the IP addresses are back to front. The last two entries use the PTR record type rather than the A record type. We now need to declare those two database files in the BIND configuration. To do this, we just add the following to the end of the named.conf.local file:

zone "home" in {
        type master;
        file "/etc/bind/db.home";
};

zone "1.168.192.in-addr.arpa" in {
        type master;
        file "/etc/bind/db.192.168.1";
};

Note the semi-colons all over the place in the file, BIND doesn't like it if you forget them. We just need to restart the DNS for it to pick up the configuration:

$ sudo /etc/init.d/bind9 restart

If it doesn't start properly, the best way to identify what's wrong is to go have a look at the system log files. On Ubuntu, the DNS messages will be in /var/log/daemon.log. One last thing to do before we test our setup is to update the local resolver configuration by modifying /etc/resolv.conf. Remove all lines that start nameserver so that the local resolver automatically sends requests to the local BIND instance irrespective of the IP address of the machine. We should end up with a file that contains a single line:

domain home

And we can now use nslookup to verify that it's all working:

$ nslookup szczecin
Server:         127.0.0.1
Address:        127.0.0.1#53

Name:   szczecin.home
Address: 192.168.1.253

$ nslookup szczecin.home
Server:         127.0.0.1
Address:        127.0.0.1#53

Name:   szczecin.home
Address: 192.168.1.253

$ nslookup gateway
Server:         127.0.0.1
Address:        127.0.0.1#53

Name:   gateway.home
Address: 192.168.1.254

$ nslookup localhost
Server:         127.0.0.1
Address:        127.0.0.1#53

Name:   localhost.home
Address: 127.0.0.1

Installing the DHCP server

My reference for installing the DHCP server was an excellent article aimed at the Debian distribution by Adam Trickett. As Ubuntu is based on Debian, I didn't have much to change. In its default state, an Ubuntu installation doesn't include a DHCP server so we need to add it:

$ sudo apt-get install dhcp3-server

This will install the ISC DHCP server. It will ask you to insert the Ubuntu CD in the drive so just do so. It will then attempt to start the new DHCP server and fail saying that the configuration is incorrect, which is to be expected. Configuration files for this server can be found in /etc/dhcp3 and the one we are interested in is dhcpd.conf. Move the default version out of the way by renaming it and we will start anew with an empty file. Here is what I have on my system, based on Adam's article. I highlighted the lines that tell the DHCP server to update the DNS and what key file to use.

# Basic stuff to name the server and switch on updating
server-identifier       192.168.1.253;
ddns-updates            on;
ddns-update-style       interim;
ddns-domainname         "home.";
ddns-rev-domainname     "in-addr.arpa.";
# Ignore Windows FQDN updates
ignore                  client-updates;

# Include the key so that DHCP can authenticate itself to BIND9
include                 "/etc/bind/rndc.key";

# This is the communication zone
zone home. {
        primary 127.0.0.1;
        key rndc-key;
}

# Normal DHCP stuff
option domain-name              "home.";
option domain-name-servers      192.168.1.253;
option ip-forwarding            off;

default-lease-time              600;
max-lease-time                  7200;

# Tell the server it is authoritative on that subnet (essential)
authoritative;

subnet 192.168.1.0 netmask 255.255.255.0 {
        range                           192.168.1.100 192.168.1.200;
        option broadcast-address        192.168.1.255;
        option routers                  192.168.1.254;
        allow                           unknown-clients;

        zone 1.168.192.in-addr.arpa. {
                primary 192.168.1.253;
                key "rndc-key";
        }

        zone localdomain. {
                primary 192.168.1.253;
                key "rndc-key";
        }
}

Now that we've done that, we need to modify the DNS configuration so that it can accept the changes. But first, a quick note on the /etc/bind/rndc.key file. This file is automatically created when you install DNS on Ubuntu and should be fine for your installation. It is a key file that authenticates the DHCP server to the DNS server so that only the DHCP server is allowed to send updates. You don't want random people to be able to update your DNS database. Having said that, we need to modify the DNS configuration to accept the updates so back to /etc/bind. And while we are at it, let's have a look at this key file.

key "rndc-key" {
        algorithm hmac-md5;
        secret "some base 64 encoded secret key";
};

Note the name of the key on the first line, it may vary from one distribution to another so make a note of it. Then we need to add the control information to the DNS configuration. Rather than update named.conf, I decided to add the relevant code to the end of named.conf.options: it feels like the right place to put it but I suspect it doesn't really matter. So add this to the end of the file:

// allow localhost to perform updates
controls {
        inet 127.0.0.1 allow { localhost; } keys { "rndc-key"; };
};

Then we need to modify the zone definitions in the named.conf.local file. Here is what it looks like with changes highlighted:

zone "home" in {
        type master;
        file "/etc/bind/db.home";
        allow-update { key "rndc-key"; };
        notify yes;
};

zone "1.168.192.in-addr.arpa" in {
        type master;
        file "/etc/bind/db.192.168.1";
        allow-update { key "rndc-key"; };
        notify yes;
};

include "/etc/bind/rndc.key";

We're nearly there. The changes we just made mean two things: the DNS server needs to be able to update the content of the /etc/bind directory and the DHCP server needs to be able to read the key file /etc/bind/rndc.key. By default on Ubuntu, this won't work as the permissions around those files are fairly stringent. So let's change them. As the BIND configuration directory belongs to root:bind, we just need to give write access to the group for BIND to be able to write to it. To give the DHCP server access to the key file, the right thing to do would be to add the dhcpd user to the bind group but we can also make the file readable to everybody. Yes this is less secure but will be fine for a home installation.

$ sudo chmod g+w /etc/bind

$ sudo chmod +r /etc/bind/rndc.key

Now we just need to start DHCP and restart DNS.

$ sudo /etc/init.d/dhcp3-server start

$ sudo /etc/init.d/bind9 restart

Error messages will be in the same place as before if the services don't start properly. If all starts as exected, it's now time to go to the administration interface of the router and disable DHCP. We should not need it anymore.

Booting the clients

The proof of the pudding is in the eating and the proof of installing a server is in starting a number of clients to use the service. The first machine I tried with was my Ubuntu laptop called nuuk. To see what happens, tail the log file. You should see something like the following appear:

Nov  3 15:14:02 szczecin dhcpd: DHCPDISCOVER from 00:12:f0:1e:f4:79 via eth0
Nov  3 15:14:03 szczecin dhcpd: DHCPOFFER on 192.168.1.102 to 00:12:f0:1e:f4:79
(nuuk) via eth0
Nov  3 15:14:03 szczecin named[4771]: client 127.0.0.1#32773: updating zone
'home/IN': adding an RR at 'nuuk.home' A
Nov  3 15:14:03 szczecin named[4771]: client 127.0.0.1#32773: updating zone
'home/IN': adding an RR at 'nuuk.home' TXT
Nov  3 15:14:03 szczecin dhcpd: Added new forward map from nuuk.home. to
192.168.1.102
Nov  3 15:14:03 szczecin named[4771]: client 192.168.1.253#32773: updating zone
'1.168.192.in-addr.arpa/IN': deleting rrset at '102.1.168.192.in-addr.arpa' PTR
Nov  3 15:14:03 szczecin named[4771]: client 192.168.1.253#32773: updating zone
'1.168.192.in-addr.arpa/IN': adding an RR at '102.1.168.192.in-addr.arpa' PTR
Nov  3 15:14:03 szczecin dhcpd: added reverse map from 102.1.168.192.in-addr.arpa.
to nuuk.home.
Nov  3 15:14:03 szczecin dhcpd: Wrote 4 leases to leases file.
Nov  3 15:14:03 szczecin dhcpd: DHCPREQUEST for 192.168.1.102 (192.168.1.253) from
00:12:f0:1e:f4:79 (nuuk) via eth0
Nov  3 15:14:03 szczecin dhcpd: DHCPACK on 192.168.1.102 to 00:12:f0:1e:f4:79 (nuuk)
via eth0

If you don't see the message about updating the forward and reverse maps, it may be that your client machine is not configured to send its name to the DHCP server. For this to work on Ubuntu, you should have the following line in /etc/dhcp3/dhclient.conf:

send host-name "<hostname>";

Next on the list is my Apple PowerMac G5 called helsinki. A simple restart and it works like a charm: I can ping hesinki from nuuk or szczecin and the other way round, all machines can access the Internet, great! While we're talking about computer names, if you don't know how to change the machine's name under OS-X, here's how.

The next test is with my work's Windows XP laptop. All goes well: the Windows box gets an IP address and I can ping it from the other machines. However, I can't ping from the Windows box to the other ones unless I use the fully qualified domain name: that is I can ping nuuk.home but not nuuk. It looks like Windows ignores the domain information sent by DHCP. This is not a major problem as everything else works fine. I vaguely remember something about network settings on Windows that you have to change but. I'll have a look see if I can remember where it was when I can.

The final test is to start my Solaris Express laptop called mariehamn. It gets its IP address fine but doesn't seem to send its name to the server. So it can't be pinged. Everything else works though: it can ping all of the other machines, get to the Internet, etc. I suspect I need to find the equivalent of the /etc/dhcp3/dhclient.conf file on Solaris and change it so that it sends its name. It's probably hidden somewhere in the Network Auto-Magic configuration.

Conclusion

That was a bit convoluted but the excellent resources that are the O'Reilly DNS and BIND book and Adam's article made it significantly easier. Real system administrators would say that was a doodle and made way too easy by Ubuntu. I've learnt useful stuff on the way and I now have a good use for this old workstation. Speaking of which, it hasn't really been breaking a sweat so far: it's been close to 100% idle all the time, it has 114Mb RAM free out of 256 and the hard disk has seen virtually no activity. In other words, my 8 year old box is over spec'ed for this and I could get it to do a lot more server tasks. Should I mention that the server version of some other recent operating systems that shall remain nameless would not even start on such a machine? No, I'll leave that debate for another day.

For those who are wondering what scheme I use to name my computers, it all comes from a previous job and all machines are named after cities of the world, with a Scandinavian and Baltic theme so far: Helsinki, Szczecin, Nuuk and Mariehamn.

Sunday, 28 October 2007

From Feisty to Gutsy

Ubuntu released the version 7.10 of their operating system 10 days ago, code named Gutsy Gibbon. As my laptop was on the previous release (Feisty Fawn, 7.04), when I booted it yesterday the install manager suggested I upgrade. I decided to do so, wondering how long it would take and how complicated it would be, my experience of other operating systems that shall remain nameless telling me that I could be in for the long haul. I shouldn't have worried: in typical Ubuntu fashion, it was dead easy: once I had clicked on the upgrade button, it did everything on its own, I just had to provide my password so that it could have root privileges. In fact, the only difference with a normal package update was that it took longer and the laptop had to be restarted once at the end of the process in order to boot under the new version.

Needless to say, I was impressed. If only all operating system upgrades could be that easy!

Saturday, 27 October 2007

Geeky experiments with bash functions

return doesn't mean what you think it does

Modern UNIX shells like bash have the ability to define functions. Functions are a great way to factorise parts of code that you need to use in several areas of your script or isolate discrete pieces of logic. In most programming languages, one fundamental aspect of functions is that they can return a value which is the result of whatever computation they were doing. And indeed a shell like bash has a built in return command. But, hang on, if you read up on return, you realise that it can only return integer values. The reason for this is that return works the same way as exit: it sets the $? variable with the value given as argument, or 0 if no argument is given, and aborts the function. exit aborts the whole script instead. So, if you use return, use it to provide the calling code with an error code. This doesn't solve the original problem though: how can we return a value from a function, such as a character string?

As often with UNIX, the answer is deceptively simple and consistent with everything you know about scripts: just echo the value you want to return and call your function as if it was a full blown script, with inverted quotes or the $(...) construct, as in the example below.

#!/bin/bash

function f {
  echo "[ $1 ]"
  return 1
}

s=`f "abc"`
echo "\$?=$?"
echo "\$s=$s"

Save this in a file called fn.sh, make it executable and run it:

$ ./fn.sh
$?=1
$s=[ abc ]

As you can see, the $? special variable was set with the value 1 and the $s variable was updated with the result of the function.

Recursive fun

Once you know how to return a value from your function, the next thing you need is to know how to pass it some parameters. Once again, it works exactly the same as in a full blown script: you just use the $n positional variables. Recursion works as you expect as well. So let's demonstrate with a classic textbook example: a recursive factorial.

#!/bin/bash

function fact {
  if [ $# -lt 1 ]; then
    return 1
  elif [ $1 -lt 1 ]; then
    return 2
  elif [ $1 -eq 1 ]; then
    r=1
  else
    r=$(( $1 * `fact $(( $1 - 1 ))` ))
  fi
  echo "$r"
}

fact $1

Save it, run it and you should get something like the following. Don't give it too high a value though, we'll see why in a second: 10 should be enough to demonstrate that it works.

$ ./fact.sh 10
3628800

While we're here, let's have a quick look at this function as it has a couple of interesting constructs. It does the following:

  • check the number of parameters it has been passed, using the $# variable, and returns an error if less than 1,
  • check that the first parameter is positive, as a negative value is invalid and return an error code in this case,
  • check the termination condition of the recursion and set the result if we have reached that condition,
  • finally calculate the factorial by calling itself recursively.

Note the use of the $((...)) construct to do the relevant arithmetic calculations: one is needed inside the recursive call to the function, to tell ensure the value passed is the result if $1 - 1 rather than the three parameters $1, - and 1; another one is needed outside the call to calculate the product.

This script also proves that when using functions in this way, the variables defined inside the function are local and not overwritten by a subsequent call. This is because the use of the back quotes actually forks a new process in which the function is called. You can verify this by adding a sleep statement inside the function, running the script in the background and running ps:

$ ps
  PID  TT  STAT      TIME COMMAND
  394  p1  S      0:00.07 -bash
 2414  p1  S      0:00.01 /bin/bash ./fact.sh 10
 2415  p1  S      0:00.00 /bin/bash ./fact.sh 10
 2416  p1  S      0:00.00 /bin/bash ./fact.sh 10
 2417  p1  S      0:00.00 /bin/bash ./fact.sh 10
 2418  p1  S      0:00.00 /bin/bash ./fact.sh 10
 2419  p1  S      0:00.00 /bin/bash ./fact.sh 10
 2420  p1  S      0:00.00 /bin/bash ./fact.sh 10
 2421  p1  S      0:00.00 /bin/bash ./fact.sh 10
 2422  p1  S      0:00.00 /bin/bash ./fact.sh 10
 2423  p1  S      0:00.00 /bin/bash ./fact.sh 10
 2424  p1  S      0:00.00 sleep 5

Each child process has its own context and variables and doesn't interfere with the other ones. However, this means that you have to be extremely careful when using functions this way as you could quite easily spawn a large number of processes. Recursion in particular could be deadly.

Pipe dreams

Finally, if a function generally works like a script, can we pipe it? yes but if you want it to be on the consuming side of the pipe, you will need to adapt the function to take its input from stdin rather than a parameter. And you can even make it work so that it can do both. Here is a modified version of the very first script:

#!/bin/bash

function f {
  if [ $# -ge 1 ]; then
    echo "[ $1 ]"
  else
    while read line; do
      if [ -n "$line" ]; then
        echo `f "$line"`
      fi
    done
  fi
}

find ~ -type f -print | f

You could apply this construct to most functions: check if there are any parameters, in which case you can use them normally, otherwise read each input line and call the function recursively using the line as parameter. Don't forget to enclose it between quotes though, so that it is passed as a single parameter and blank lines don't trigger an infinite recursion. Run this script and you should get a list of all files in your home directory, with each file enclosed in square brackets.

That's it for functions. Please tell me if any of the examples above don't work for you. I have tested them on Ubuntu Linux, Sun Solaris Express and Mac OS-X so they should be fairly portable but you never know. They may not work with shells other than bash but feel free to experiment.

Tuesday, 16 October 2007

British Gas Customer Service

Unusually, I was home early tonight. I got a knock on my door so I went and opened.

Hello, I am from British Gas, can I ask you a few questions?

Yes, sure.

Can I ask you why you cancelled your electricity contract with British Gas?

I never had electricity through British Gas, I only buy gas from you.

Ah... So you never had electricity supplied by us? And you would not be interested in buying electricity from us, in addition to gas?

No.

Why not? We have good prices, you could save a lot of money.

I am happy with my current supplier.

Ah... OK, thank you, good night!

So now British Gas know that I only buy gas and not electricity from them. That's progress. It's only taken them 6 years to realise.

Monday, 15 October 2007

Labour Party's Reading Skills

I just got a call from a member of the Labour Party. I suppose they got my details from the Electoral Register. If so, said register clearly specifies that I am a French citizen. Therefore, asking me what party I was planning to vote for at the next General Election was quite senseless as I cannot vote for General Elections. Someone should teach the members of the Labour Party (and the others) basic skills like reading, that would save them quite a few phone calls.

Monday, 24 September 2007

The Big 18-Month Mobile Contract Scam

If you buy a new mobile phone contract in the UK these days, chances are that the sales person you are going to talk to will try to sell you an 18 month contract rather than a 12 month one. Be extremely careful before you decide to take such a contract. Perks will include a free mobile phone and a slightly cheaper contract than the shorter one. The downside is that you can only upgrade your handset after 18 months rather than 12. Not a major problem you may think if you are not the type who needs the latest handset as soon as it comes out.

Think again. And ask the sales person what is the length of the manufacturer's warranty on the handset. Chances are, the warranty for the handset is 12 months. If your handset starts malfunctioning through no fault of your own while it is under warranty, or once you are eligible for an upgrade, the provider will replace it at no cost to you. However, if your handset plays up after the warranty has expired but before you are eligible for an upgrade, that is during the last 6 months of a typical 18 month contract, then the provider will not replace the handset and you will have to buy one yourself at full market price.

Of course all this is explained in the small print of your contract but no sales person will mention it to you without prompting. So don't forget to ask and if the warranty on the handset expires before you are eligible for an upgrade, don't take the contract.

I just got bitten by that interesting loophole with Vodafone and am now left with a malfunctioning handset for the last 3 months of my contract. Luckily the fault is not debilitating, it just means that the handset occasionally restarts while in the middle of a call, cutting the call short. Not a complete failure then, but still extremely annoying. Evidently, the second my current contract expires, I will go shopping around for a new contract and I will only stay with my current provider if they can offer me a significantly better deal than the competition.

As Vodafone's support told me, everybody else does the same because the handset's warranty is set by the manufacturer, not the network and they have no say in this. Well, maybe they should talk to the manufacturers and solve this loophole. The reason why it should be solved is because the handset is bundled with the contract. You don't buy the handset, you buy a contract to provide you with mobile phone services and you are given a handset as part of that contract to enable you to connect to the service. The cost of the handset is then included in the price you pay for the service and it should be completely covered by the service agreement for the duration of that agreement. In the case where you buy the handset separately, you buy a service and an electronic device to use with this service, there are two separate transactions and it is therefore sensible to treat them separately. Not when the handset is bundled with the service.

I may be barking at the wrong tree but I will definitely contact the Office of Fair Trading and ask them whether this practice is actually fair. I shall update this blog when I have an answer.

Sunday, 23 September 2007

Bad Interface Design

Apple Computers are reknown for some of the best user interfaces. Like everybody else, they can occasionally get it wrong. I just had an amusing example of this. If you go to the HSBC web site and download any of their PDF documents such as their terms and conditions, you will notice that there is a slight bug that adds ;jsessionid= followed by a lot of gobbledygook at the end of the file name, after the extension, thus producing a file with an unusually long extension that OS-X doesn't recognise. So the first thing you'd want to do is change that file name and remove all the jsessionid malarkey at the end of the file name. When you do that, OS-X thinks you want to change the extension and are in risk of ending up with a file name it can't handle automatically. So it warns you and asks if you really want to do this, assuming you don't, as shown below:

Error dialogue with inaccessible button

Error dialogue with inaccessible button

In this example, you can just about see the other button pushed all the way left and therefore click on it as you really, really want to change that extension. But if you had just one more letter or if you changed the j in the ID for an M, the right button would be that little bit much wider and the left button would completely disappear. As you can't change the dialogue window's size, you're stuffed and you have no choice but to click on the highlighted button and leave your file name as is. The only way I found around this is to open the terminal and use the command line to change the name. That's one thing that OS-X has going for it: as it's UNIX underneath, you can always bypass the user interface when it gets in the way. On the other hand, that's not something that is very accessible to the average user.

There are a couple of solutions that Apple could apply to their dialogue boxes when such a problem occurs:

  • make the dialogue window's resizable and/or scrollable;
  • extend the window accordingly, although you'd get the same problem if you got to stupid extension lengths as long as the width of the screen;
  • make the buttons stack up and extend the window vertically.

The moral of the story is: when designing user interfaces, test them with very stupid values that make it break. Someone is bound to use such values one day or another, if only by accident.

Saturday, 22 September 2007

Big Brother Sam

Wired News have an interesting article about screening at American airports and the type of information they collect. This strengthens my resolution not to fly to the United States until further notice. Not that I have anything to fear from such screening but I really think this is going too far. It looks like Uncle Sam is more and more turning into Big Brother Sam!

Tuesday, 18 September 2007

Word of the Day

Dictionary.com's word of the day is potboiler. No, I didn't know it either. There you go, you learn something new every day.