ramblings


Cor, Andrew Bednarz has written an iPhone client for mserv. Thanks Andrew!

mserv controller for iPhone

If only I had an iPhone :-(

I’ve recently done some work to talk to Sharepoint with Perl and thought I would share my experiences. I couldn’t find any example code out there in the wild for doing this, so I had to figure a lot of this out by trial and error. It’s actually quite simple once you’ve got it set up. I hope this helps someone.

This code shows you how to connect via the Web Services interface with NTLM authentication (i.e. standard Windows authentication) to manipulate Lists, but you could do almost anything.

You will need:

  • SOAP::Lite for talking to Sharepoint Web Services interface
  • LWP::Authen::Ntlm to enable LWP to talk NTLM
  • Authen::NTLM which LWP::Authen::Ntlm uses for the NTLM authentication

Some information sources that you’ll find useful:

  • MSDN Sharepoint Web Services documentation
  • Go to /_vti_bin/lists.asmx on your Sharepoint server for a lot of useful information
  • Go to /_vti_bin/lists.asmx?WSDL for the WSDL definitions (if all else fails)

So here’s how to get started:

use LWP::UserAgent;
use LWP::Debug;
use SOAP::Lite on_action => sub { "$_[0]$_[1]"; };
import SOAP::Data 'name', 'value';
our $sp_endpoint = 'http://sp.example.com/sites/mysite/_vti_bin/lists.asmx';
our $sp_domain = 'sp.example.com:80';
our $sp_username = 'DOMAIN\username';
our $sp_password = 'xyz';

The SOAP::Lite module needs to be told how to construct the SOAPAction header properly for Sharepoint. The on_action does just this, and means you’ll end up with a SOAPAction appending the URL and the method name together without anything in between (stops the default # that Sharepoint doesn’t want).

if ($debug) {
    LWP::Debug::level('+');
    SOAP::Lite->import(+trace => 'all');
}

Use the above code to turn on debugging if you get errors.

my @ua_args = (keep_alive => 1);
my @credentials = ($sp_domain, "", $sp_endpoint, $sp_password);
my $schema_ua = LWP::UserAgent->new(@ua_args);
$schema_ua->credentials(@credentials);
$soap = SOAP::Lite->proxy($sp_endpoint, @ua_args, credentials => \@credentials);
$soap->schema->useragent($schema_ua);
$soap->uri("http://schemas.microsoft.com/sharepoint/soap/");

This complete mess is the necessary steps to get SOAP::Lite to use a properly configured LWP UserAgent to do NTLM authentication. SOAP::Lite uses two UserAgents, one for the main SOAP calls and one for the Schema fetching. Although you don’t need to fetch a schema, I’ve included the proper set up above in case you want to call $soap->service(”$sp_endpoint?WSDL”); for some reason.

$lists = $soap->GetListCollection();
quit(1, $lists->faultstring()) if defined $lists->fault();

That’s all you need to do to get a list of all the lists on your Sharepoint site. And we can print them out:

my @result = $lists->dataof('//GetListCollectionResult/Lists/List');
foreach my $data (@result) {
    my $attr = $data->attr;
    foreach my $a qw/Title Description DefaultViewUrl Name ID WebId ItemCount/ {
        printf "%-16s %s\n", $a, $attr->{$a};
    }
    print "\n";
}

Or if you need to find a particular list to do operations on it, search for it in the results by looking up the Title with something like this:

sub lists_getid
{
    my $title = shift;
    my @result = $lists->dataof('//GetListCollectionResult/Lists/List');
    foreach my $data (@result) {
        my $attr = $data->attr;
        return $attr->{ID} if ($attr->{Title} eq $title);
    }
    return undef;
}

And here’s another useful subroutine to get all the items in a list:

sub lists_getitems
{
    my $listid = shift;
    my $in_listName = name('listName' => $listid);
    my $in_viewName = name('viewName' => '');
    my $in_rowLimit = name('rowLimit' => 99999);
    my $call = $soap->GetListItems($in_listName, $in_viewName, $in_rowLimit);
    quit(1, $call->faultstring()) if defined $call->fault();
    return $call->dataof('//GetListItemsResult/listitems/data/row');
}

That will use the default view. The 99999 is a hack to get all the items and stop the server “paging” the results. Putting this together you’d do something like this:

my $list_id = lists_getid('MyList');
print "List ID is: $list_id\n";
my @items = lists_getitems($list_id);
foreach my $data (@items) {
    my $attr = $data->attr;
    # print Dumper($attr);
}

Here’s some code to add a new list item:

my $field_id = name('Field', 'New')->attr({ Name => 'ID'});
my $field_linktitle = name('Field', $title)->attr({ Name => 'Title'});
my $field_something = name('Field', $something_else)->attr({ Name => 'Something_x0020_Else'});
my $method = name('Method', [$field_id, $field_linktitle, $field_something])->attr({ ID => "anything", Cmd => 'New'});
my $batch = name('Batch', \$method);
my $in_listName = name('listName' => $list_id);
my $in_updates = name('updates' => \$batch);
my $call = $soap->UpdateListItems($in_listName, $in_updates);
quit(1, $call->faultstring()) if defined $call->fault();

The content for Name=”ID” must be “New”. Where it says “anything” it really can be anything, it’s just an identifier for responses. You can also see that spaces are encoded as _x0020_.

my $field_id = name('Field', $sp_id)->attr({ Name => 'ID'});
my $field_something = name('Field', $something_else)->attr({ Name => 'Something_x0020_Else'});
my $method = name('Method', [$field_id, $field_appname])->attr({ ID => $jira_name, Cmd => 'Update'});

The above is for modifying an item. In this case the $sp_id must be set appropriately from the “id” attribute of a list item you previously fetched.

I hope that helps someone. Perhaps one day someone can put the effort in to writing a module to do all this.

James

del.icio.us links:

Wireless Phone Jack — muuk - The New Technology Store (tags: gadgets network phone)

I’ve cleared my photo backlog! Instead of buying a new memory card every time I need to take any photos this means I can re-use the ones I already have :-)

There’s over a dozen albums of photos I’ve added over at my photo album including Boston, Las Vegas, Open House walk, Glasgow, Malta, Tobago, and various parties and dinners.

Enjoy!

Grand Canyon Panoramic
A panoramic photo that I took while in the Grand Canyon in September. It was stitched together with AutoStitch.

It’s official! I drink too much coffee! Starbucks sent me a free pack of coffee in the post today to thank me for using my Starbucks cash card so much :-)

I always get funny looks when I load £100 on to the card. It only lasts a few weeks.

I went to the theatre yesterday to see The Lion King. I can highly recommend it, it’s a fantastic production and brings back lots of memories of the great songs in the film. The Lion King film, along with Aladdin, are for me the golden era of Disney films. Yeah, all those 3D computer generated films are great, but it’s just not the same! Perhaps you would disagree with me, but I think the songs in recent Disney productions are less memorable than the ones of that era…? (Or maybe I’m just too old now) Hakuna Matata, it’s a wonderful phrase…

In completely unrelated news I upgraded this blog to WordPress 2.2, and luckily my userextra plug-in works without problems (for me!).

Buying tickets gets more and more complicated every year, and this year it has to be the most complicated ever. You have to pre-register with your photo by the end of tomorrow or you can’t buy tickets later in the year. It’s almost easier to get a passport!

Hard workers
The end of an era. After a week long series of parties, my five+ years at Deutsche Bank is now over :-( I’ve worked with some absolutely fantastic people. I’ll miss you all. Web Infrastructure has been a fantastic group to work in and I know it has a bright future. I only wish I could have two jobs at the same time!

See more photos I took with my mobile phone…

What do you do when you’re a company that has a whole load of surplus stock, say of old crappy MP3 players, that doesn’t know what to do with them?

Give them away of course!

And that’s precisely what Dabs did to me and why I have to then go to all the effort of getting rid of it.

My flat’s managing agents today told me that Tower Hamlets will be kind enough to give us recycling bins for the whole block, although I have to wait now for a “survey”. I wonder if they’ll have an old MP3 player bin?

Next Page »