Latest Tweet:
  • Loading...

One of the cool, but perhaps overlooked features, of Outlook 2007 is the integration of mobile messaging. Today many mobile providers offers some kind of plug-in to Outlook enabling their customers to send SMS messages from Outlook. The implementation and user experience differs for each mobile provider. In Outlook 2007 there is a standard way to supports incoming and outgoing SMS and MMS messages directly from Outlook. You simply implement an XML Web Service consisting of three simple methods. There really isn't too much information available on Outlook Mobile Services in the blog sphere, so hopefully this post and webcast will be a welcome addition. In this post you'll learn how to create a Outlook 2007 Mobile Service. I've also created a screen cast that walks you through the development and deployment process.

This post is the third in a series covering free SMS messages using the Ung1881 service. The first post covered how to wrap the service into a .NET library, while the second covered how to use the .NET library from a Vista Sidebar Gadget. In this post I'm going to discuss how to implement an Outlook 2007 Mobile Service that use the same library to send free SMS messages from Outlook 2007!

Using the Ung1881 Free SMS library and Outlook 2007 Mobile Services you can send free SMS messages directly from Outlook 2007

Your Web Service only need to implement three methods, GetServiceInfo, GetUserInfo and SendXms. I've included a simple class diagram showing the methods you need to implement.

The strings passed back and fourth between server and client contains XML data. The XML structure, and Outlook 2007 Mobile Services in general, is well documented in a comprehensive developer guide up on MSDN. Last week I did some e-mailing with the team behind Outlook 2007 Mobile Services, because I couldn't get it to work by following the code samples up on MSDN. I turned out the samples where written for 1.1, and that the SOAP encoder works a little bit different in .NET 2.0. The problem was that Outlook called the service, but the parameters where always null. In the samples they use SoapRpcMethodAttribute on all methods, instead of traditional SOAP message style. But you can just overlook all the attributes and just use the WebMethod attribute as usual. The entire code of the service is fairly short (less than 200 lines) and is included below.

#region Licence agreement
// Copyright (c) 2007, Jonas Follesø
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the Jonas Follesø nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY Jonas Follesø "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL Jonas Follesø BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion

using System;
using System.IO;
using System.Web;
using System.Xml;
using System.Data;
using System.Text;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Security.Authentication;
using System.Collections.Generic;
using System.Web.Services.Description;
using System.ComponentModel;

using Ung1881;

namespace Ung1881OMS
{
    /// <summary>
    /// A WebService implementing the Outlook 2007 Mobile Service interface.
    /// Allows you to send SMS messages from Outlook 2007!
    /// </summary>
    [WebService(Namespace = "http://schemas.microsoft.com/office/Outlook/2006/OMS")]
    [WebServiceBinding(ConformsTo=WsiProfiles.BasicProfile1_1)]
    public class OMSService : System.Web.Services.WebService, IOutlookMobileService
    {
        /// <summary>
        /// Returns information about the service. The returned XML contains
        /// information about the service, if it supports SMS, MMS or both etc.
        /// See the ServiceInfo.xml for more information about the XML format.
        /// </summary>
        /// <returns></returns>
        [WebMethodAttribute()]
        public string GetServiceInfo()
        {
            return ReadXml("ServiceInfo.xml");
        }

        /// <summary>
        /// Method authenticating a user and geting user information.
        /// Returns an XML string with some basic user information (phone number and e-mail).
        /// </summary>
        /// <param name="xmsUser">An XML string containing the user credentials.</param>
        /// <returns>An XML string with user information.</returns>
        [WebMethodAttribute()]
        public string GetUserInfo(string xmsUser)
        {
            try
            {
                XmlDocument xml = new XmlDocument();
                xml.LoadXml(xmsUser);

                XmlNamespaceManager nmManager = new XmlNamespaceManager(xml.NameTable);
                nmManager.AddNamespace("o", "http://schemas.microsoft.com/office/Outlook/2006/OMS");                
                
                string username = xml.SelectSingleNode("/o:xmsUser/o:userId", nmManager).InnerText;
                string password = xml.SelectSingleNode("/o:xmsUser/o:password", nmManager).InnerText;

                Ung1881Proxy proxy = new Ung1881Proxy();
                proxy.Login(username, password);
                
                return ReadXml("UserInfo.xml");
            }
            catch (Exception)
            {
                StringWriter stringWriter = new StringWriter();
                XmlTextWriter xmlWriter = new XmlTextWriter(stringWriter);

                xmlWriter.WriteStartElement("userInfo", "http://schemas.microsoft.com/office/Outlook/2006/OMS");                
                
                xmlWriter.WriteStartElement("error");
                xmlWriter.WriteAttributeString("code", "invalidUser");
                xmlWriter.WriteAttributeString("severity", "failure");
                xmlWriter.WriteEndElement(); 
               
                xmlWriter.WriteEndElement();

                string error = stringWriter.GetStringBuilder().ToString();

                xmlWriter.Close();
                stringWriter.Dispose();

                return error;
            }
        }

        /// <summary>
        /// Method sending an SMS/MMS message to one or more recepients.
        /// </summary>
        /// <param name="xmsData">An XML string with the list of recepients and the content of the message.</param>
        /// <returns>An XML string with a status message.</returns>
        [WebMethodAttribute()]
        public string SendXms(string xmsData)
        {            
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(xmsData);

            XmlNamespaceManager nmManager = new XmlNamespaceManager(xml.NameTable);
            nmManager.AddNamespace("o", "http://schemas.microsoft.com/office/Outlook/2006/OMS");

            string username = xml.SelectSingleNode("/o:xmsData/o:user/o:userId", nmManager).InnerText;
            string password = xml.SelectSingleNode("/o:xmsData/o:user/o:password", nmManager).InnerText;

            try
            {
                List<string> recipients = new List<string>();
                List<string> messages = new List<string>();

                foreach (XmlNode node in xml.SelectNodes("//o:recipient", nmManager))
                {
                    recipients.Add(node.InnerText);
                }

                foreach (XmlNode node in xml.SelectNodes("//o:content[@contentType='text/plain']", nmManager))
                {
                    messages.Add(node.InnerText);
                }

                Ung1881Client client = new Ung1881Client(username, password);

                foreach (string number in recipients)
                {
                    foreach (string message in messages)
                    {
                        client.SendMessage(number, message);
                    }
                }

                return BuildError("ok", false);;
            }
            catch (AuthenticationException)
            {
                return BuildError("invalidUser", true);
            }
            catch (Exception)
            {
                return BuildError("others", true);
            }
        }

        /// <summary>
        /// Simple helper method reading an file from disk and
        /// returning the content as a string.
        /// </summary>
        /// <param name="fileName">The relative path to the file you want to read.</param>
        /// <returns>The file content.</returns>
        private string ReadXml(string fileName)
        {
            StreamReader sr = new StreamReader(Server.MapPath(fileName), Encoding.Unicode);
            string xml = sr.ReadToEnd();
            sr.Dispose();
            return xml;
        }

        /// <summary>
        /// Simple helper method building the return XML for the SendXms method.
        /// </summary>
        /// <param name="errorCode">The error code.</param>
        /// <param name="failed">If this was a failure or not.</param>
        /// <returns>The XML fragment to return to the client.</returns>
        private string BuildError(string errorCode, bool failed)
        {
            StringWriter stringWriter = new StringWriter();
            XmlTextWriter wr = new XmlTextWriter(stringWriter);

            wr.WriteStartDocument();
            wr.WriteStartElement("xmsResponse", "http://schemas.microsoft.com/office/Outlook/2006/OMS");
            wr.WriteStartElement("error");
            wr.WriteAttributeString("code", errorCode);
            wr.WriteAttributeString("severity", failed ? "failure" : "neutral");
            wr.WriteEndElement();
            wr.WriteEndElement();
            wr.WriteEndDocument();

            wr.Close();
            string returnValue = stringWriter.GetStringBuilder().ToString();
            stringWriter.Dispose();
            return returnValue;
        }
    }
}

Once you have your service up and running you can add a new account in Outlook 2007. In the add account wizard, select "other" and "Outlook Mobile Service" as the account type. This will bring up the "Outlook Mobile Service Account" dialog. Here you enter the URL to the service and your user credentials.

 

Once you've created an Outlook Mobile Service account you get a new item in the "New" menu called "New Text Message". This brings up the new message dialog. When you send your message, Outlook will call your service and the SendXms method.

The installation process isn't as easy as I wish it was, since this is a server application you need to configure IIS. Outlook will only connect to HTTPS sites, so you need to create your own certificate as well. The screen cast walks you through this process. Scott Guthrie has a nice post on IIS7 and self signed certificates over at his blog

The next post in this Free SMS series will be an .NET 3.0 application for Windows XP users who don't have the Vista Sidebar available. Stay tuned! Please drop me a comment if you downloaded and installed the service and found it useful, or have any questions regarding Outlook 2007 Mobile Services.
 

I haven't blogged too much about my studies, but some of you might know that I'm graduating from the Norwegian University of Technology and Science with a bachelors degree in Informatics this summer. I think the coolest course I've taken through out the three years at the university is the "microcontroller system design" course. The course is all about embedded hardware and building software for devices. The course is really practical, so you get's lots of hands on assignments.

We're using the STK1000 development kit from the Trondheim based chip manufacture Atmel to learn microcontroller programming. This Friday Håvard Sørbø and Daugur Johanssonn and I delivered our third assignment in the course. It's a PONG clone running on the STK1000. The task was to install a custom Linux distribution on the device, write a kernel driver to handle buttons and lights, and to implement the PONG game. Håvard did the kernel driver for the LEDs and buttons and lights, Dagur did most of the game engine, while I did the graphics and some pair programming with Dagur on the actual game. The entire project is written in C. To make the game more fun we decided to base the theme of the game on Super Mario Brus on the NES.

  

I found this course really interesting since it's so far away from my everyday job as a .NET developer, working in such an high level of abstraction. On this course you get a chance to do really low level stuff, like writing C and assembly to the device, not depending on an operating system. You get to draw on the screen, one pixel at the time, and not depend on some pre-built graphics library. In all the course has been a great learning experience. I've included a YouTube video showing off the gameplay.

This post is the second in a series of posts covering how to send free SMS messages using the Ung1881 web site. The first post discussed how to use screen scraping to wrap the Ung1881 web site into a .NET library we could use to send messages from the command line. In this post I'm going to discuss how to create a Vista Sidebar Gadget that allows us to use the .NET library to send free messages.

 Now that we have a nice and clean SMS library at our disposal it's time to do something more fun (and useful) than sending messages from a Console application. The next step is to create a Vista Sidebar Gadget that uses the .NET library to send SMS messages. I'm not going to walk you through the basics of a Sidebar Gadget in this post. There is an excellent article for absolute beginners up on MSDN. The focus of this post is going to be .NET interop, and how to read phone numbers from your Vista address book.

Throughout the development cycle of Vista we've seen various versions of the sidebar. I still remember seeing some awesome WPF gadgets up on Channel9 when Vista still was known as Longhorn, and all we had was early CTP builds. However, as most of you know the final version of the Sidebar is limited to HTML, CSS and JavaScript. To many (including me) this was quite a disappointment…

To be honest, it's not fair to say that Vista Gadgets can't run .NET code. You can expose your .NET code as COM object, and it's fairly easy to create COM instances from script languages.

The real problem is to register your .NET code for COM interop. This involves modifying your code to become COM compatible and to create a MSI installation package to register and distribute your code. This is to much hassle for a simple gadget.

Thankfully Tyler (he doesn't include his full name) have found a really elegant solution to .NET Interop in Gadgets, and have posted an excellent article on this on "The Code Project". You should definitely check out the article. His solution to the problems involves creating a general purpose GadgetAdapter, which is a .NET assembly, that supports COM interop, that can load other .NET assemblies dynamically using reflection. The GadgetAdapter assembly is registered on the end users machine using shell scripting from JavaScript. So the first time you use the interop layer the GadgetAdapter gets registered on the clients machine. Once the GadgetAdapter is registered you can create an instance of it from your own gadget script and load up any .NET class you want from your own assembly.

So to backup for a second, your Gadget folder structure looks something like this:

In your Gadget Script file all you have to do to create a new instance of a .NET type is this:

// Instance of the GadgetBuilder to load/unload .NET assemblies. See GadgetInterop.js.
var builder = new GadgetBuilder();         
    
// Initialize the adapter to call .NET assemblies.
builder.Initialize();

// Use the builder to add the username and password as constructor argument values.
builder.AddConstructorParam(username);
builder.AddConstructorParam(password);
    
// Load the Ung1881.dll assembly and create an instance of the Ung1881.Ung1881Client type.
ung1881Client = builder.LoadType(System.Gadget.path + "\\bin\\Ung1881.dll", "Ung1881.Ung1881Client");
    
//Get values from the UI.
var number = txtPhoneNumber.value;
var message = txtMessage.innerText;    
    
//Sending the message
var status = ung1881Client.SendMessage(number, message);

The Ung1881Client is a new class I added to the library to make it even easier to use it from a Gadget. The class takes care of wrapping long messages into smaller chunks, and it returns a status code instead of throwing exceptions when something goes wrong.

During testing of the gadget I discovered one bug/issue with the GadgetInterop JavaScript library provider by Tyler. If you turn of UAC (the "cancel or allow" stuff in Vista), or right click and run Sidebar.exe as administrator, the gadget stops working. After doing some debugging I figured out that I was unable to load the GadgetAdapter. After digging some more I located the bug in the RegisterGadgetInterop function in the GadgetInterop.js file. The problem is that if you run with out UAC, or run sidebar.exe as an administrator, you can't write to HKCU (Current User). Instead you have to register the GadgetAdapter under HKLM (Local Machine). I have notified Tyler on the Code Project message board, but article isn't updated. I've included the updated version of the RegisterGadgetInterop function below:

////////////////////////////////////////////////////////////////////////////////
//
// Add the Gadget.Interop dll to the registry so it can be used by COM and
// created in javascript as an ActiveX object
//
////////////////////////////////////////////////////////////////////////////////
function RegisterGadgetInterop()
{
    try
    {
        // Full path to the Gadget.Interop.dll assembly
        var fullPath = System.Gadget.path + assemblyStore;
        var asmPath = fullPath + assemblyName;
            
        // Register the interop assembly under the Current User registry key
        RegAsmInstall("HKCU", progID, "Gadget.Interop.GadgetAdapter", guid,
            "Gadget.Interop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9389e9f4d8844504",
            "1.0.0.0", asmPath);
            
        if(InteropRegistered() == false)
        {
            // Try Register the interop assembly under the Local Machine registry key
            RegAsmInstall("HKLM", progID, "Gadget.Interop.GadgetAdapter", guid,
                "Gadget.Interop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9389e9f4d8844504",
                "1.0.0.0", asmPath);
         }            
    }
    catch(e)
    {
        System.Debug.outputString("RegisterGadgetInterop fails: " + e.message);
    }    
}

Another interesting feature of the gadget is the Vista Contacts integration. Since this is an SMS gadget you obviously want to access your address book to look up mobile phone numbers of your friends and family. This is fairly straight forward, since contact support is included in the Vista Sidebar Object Model. The function reading the address book and adding contacts who have a mobile phone to a drop down list is included below:

///////////////////////////////////////////////////////////////
//
// Load contacts from the Vista address book.
//
///////////////////////////////////////////////////////////////
function loadContacts()
{
    var contactMgr = System.ContactManager;
    var contacts = contactMgr.Contacts;
    var contact = null;
    var element = null;
        
    for(var i=0; i < contacts.count; i++)
    {
        contact = contacts.item(i);        
        if(contact.mobilePhone != "")
        {            
            element = document.createElement("option");
            element.text = contact.name;
            element.value = contact.mobilePhone;
            ddlContacts.add(element, ddlContacts.options.length);
        }
    }
    
    element = document.createElement("option");
    element.value = "";
    
    if(ddlContacts.options.length > 0)
    {
        element.text = "<Velg kontakt>";
        ddlContacts.disabled = false;
    }
    else
    {
        element.text = "<Ingen kontakter>";    
        ddlContacts.disabled = true;
    }
    ddlContacts.add(element, 0);    
    ddlContacts.selectedIndex = 0;
}

Gadget floating on desktop showing contacts

I've gotten a few requests from friends who want their Outlook 2007 contacts to show up in the gadget. Since this isn't supported directly by the Vista Sidebar Object Model I'd have to do the Outlook 2007 interop my self. I assume this wouldn't be too hard, but I haven't had time to figure this out yet. Drop me a comment if you have any good resources on how to read the Outlook 2007 address book from script. However, if you're running Outlook 2007 I have something far cooler up my sleeves for the next part of this series on how to make the most fun out the SMS library!

The download link points to the Windows Live Gallery site, so if you download and like the gadget please rate it. Feel free to post any comments, suggestions, questions or feedback.

This might not interest my 33 RSS subscribers (more on that number later), or perhaps it's a reason to peek outside your RSS reader?

Because of bad weather I've spent most of the Easter indoor in front of the computer, which actually have been really nice. Finally I had time to finish off some personal projects I've planned for some time. One of them is upgrading this blog with a new theme.

The new theme is inspired by Alexander Groß great looking theme over at www.therightstuff.de.

As well as making the blog look cooler with a custom theme, the main focus have been on readability.

Some of the readability enhancements include brand new cool looking quotation boxes…

…a way better way to handle code snippets, using "scrolling" windows and CSS styled color highlighting

using System;
using System.Collections.Generic;
using System.Text;

namespace MyBlog
{
    /// <summary>
    /// Syntaxt coloring example
    /// </summary>
    public class MyClass
    {
        private string message = "This is my new theme...";

        public void Test()
        {
            Console.WriteLine(message);
        }
        
    }
}

…and a cleaner way to include downloads in the blog posts.

I've also changed the way the blog display comments. If you have a Gravatar it will be displayed next to your post and replies (comments) from me are colored different than comments from readers.
 
I've added a few Gadgets to the sidebar, such as my Facebook profile, my Gamer Card, my Flickr pictures, and a visitor map.

Another update to the blog is that my RSS feed is now handled by FeedBurner. This offers me better statistics on how many people actually subscribe to the blog. Currently I have 33 subscribers, which isn't too impressive… But at least I know someone is reading my posts.

So, what do you think of the new design? Any comments or suggestions are welcome!

This blog post is the first one in a series of posts covering how to send free SMS messages using the Ung1881 web site. This first post discuss how to sign into a "Forms Authentication" protected ASP.NET web site, store an authentication cookie, and programmatically post web forms. Even if you're not interested in the free SMS messages you might still find the article interesting. The next part will be on how to use the .NET Class Library in a Windows Vista Gadget.

Unlimited free SMS messages, exposed as a .NET Class Library… Sounds to good to be true? Well, It's not, but as with everything else that's free (except Open Source?) it has a catch.  You can only send messages containing 130 characters. The last 30 characters are reserved for commercials. The good thing is that you can send as many messages as you want, and your own number show up as the sender. The service is offered by "Opplysningen 1881"  (Norwegian Number Enquiry) through their new portal "Ung1881", a page aimed at young people. In order to use their SMS service you need to be a have a Norwegian social security number, and a phone number. They need your social to do a lookup and verify that you're a real person. Even though you might not be able to register for an account at "Ung1881" you might still find the code and article useful since the concepts apply for any web application.

I got interested in the "Ung1881" after Håvard pointed me to it some weeks back. After doing some re-search it turned out someone had written a Mac OSX Widget letting you send SMS messages directly from your Mac desktop. My immediate idea was to port this widget to the Windows Vista Sidebar, but after looking at the JavaScript code of the widget I soon realized this was a bad idea. The Mac OSX Widget is depending on a third party server doing the screen scrapping server side, so all your SMS messages (including your username and password) are sent through a third party using HTTP GET like this: http://www.theretard.net/smss.pl?u=username&p=password&n=number&m=message. I don't know the guys behind theretard.net, but there's no way I'm trusting them with my username, password and every SMS message I ever send. Just imagine the password harvesting possibilities! On top of this they don't even use HTTPS for communication.

I decided I had to write a .NET Assembly wrapping the "Ung1881" service, so that I could re-use the functionality in other applications, like a Windows Vista Sidebar Gadget, a console application, Outlook 2007, PowerShell etc.

The technique of accessing web sites programmatically is commonly refereed to as  screen scrapping. Since the Ung1881 portal doesn't offer any kind of programming interface, you need to tap in to it at the HTTP level, and "pretend" that you're a regular user accessing the page with a browser. Since you're depending on the actual HTML structure page you're application might become unstable, and if the owner of the source you're scrapping change their HTML it might break your application. You also need to be careful that you're not violating copyright regulations, by for instance downloading weather information and displaying it as your own. In the case of "Ung1881" terms don't say anything about "automatic access", and as long as you have a valid account they still get their 30 character commercials included in every SMS message you send. I don't think you'll get into trouble by using this code, but if you do don't blame me!

The "Ung1881" portal is running on the .NET-based Content Management System EPiServer, and uses ASP.NET Forms Authentication to authenticate users on the portal. Forms Authentication normally works by using an authentication cookie. When you logon the server authenticates your username and password. If your credentials are valid, it issues a cookie your browser sends with subsequent requests to the site. So in order to wrap the SMS service in a C# class you basically need to write a "non visual" Web Browser. You need to make a request to their login page, use HTTP POST to post a username and password to the server and store the authentication cookie sent back in the response. On subsequent requests you need to attach the authentication cookie in order to access protected pages (like the send SMS page).

The first thing I did when implementing the "Ung1881" proxy class was to analyze the HTTP traffic going between server and client. There are several tools you can use to monitor network traffic at different levels. My preferred HTTP monitor is Fiddler. Fiddler act as a HTTP Proxy, so all you're HTTP requests are routed through Fiddler. Using Fiddler you can look at the raw requests, the headers, the posted form values etc. New in Fiddler v2.0 is support for HTTPS, which is excellent since the "Ung1881" portal is using HTTPS for secure communication. Another excellent tool for network monitoring is oSpy, written by Ole André Vadla Ravnås - a brilliant programmer, reverse engineer and in general a really nice guy!

The above screenshot shows all the HTTP traffic between Internet Explorer and the "Ung1881" web server. As you can see in the left column the site is quite "chatty" because of all the pictures, advertisements, script, style sheets etc. If you enter your username, password and hit the login button, and look at the request made to the URL https://www.ung1881.no/default____3.aspx you can figure out which form elements that are being posted to the server. The site contains quite a few form elements, but the interesting parts are the following:

Content-Disposition: form-data; name="defaultframework:login:tbxUsername"
myusername

Content-Disposition: form-data; name="defaultframework:login:tbxPassword"
mypassword

Content-Disposition: form-data; name="defaultframework:login:LoginButton.x"
0

Content-Disposition: form-data; name="defaultframework:login:LoginButton.y"
0

Content-Disposition: form-data; name="__VIEWSTATE"
dDw5NDE0MjMxMzc7O2w8ZGVmYXVsdGZyYW1ld29yazpsb2dpbjpMb2dpbk
J1dHRvbjtkZWZhdWx0ZnJhbWV3b3JrOnNlbmRzbXM6YnRuU2VuZDs+Pp5c
kvQYH64y3L+4/9ebcQzi7GmX

I've highlighted the names of the form elements. You could have figured out most of this just by looking at the HTML source, but I find it easier to use Fiddler. The thing that might not be too obvious just by looking at the HTML source, is what form value get posted when you click the login image button. The HTML fragment looks like this:

<input type="image" name="defaultframework:login:LoginButton" id="defaultframework_login_LoginButton" class="..." src="..." alt="" />

If you look at the HTTP POST values above you can see that there are two values posted back to the server when you click the login button, defaultframework:login:LoginButton.x and defaultframework:login:LoginButton.y. Both have the value 0. I took a few seconds before I figured what was happening, but apparently the HTML specifications says that <input type="image"> should post back the x and y values with the coordinates of where the user clicked the image. For accessibility reasons this is deprecated, and if you need x and y values from an image you should use an <imgemap> element instead. In order to confirm with the HTML standard the browser posts an x and y value back to the server.

Another important thing to note is that "Ung1881" is an ASP.NET application, and therefore is depending on the "__VIEWSTATE" form element. This hidden form value holds an encoded string representing the state of the application on the server. If we don't include this value in our scrapper the ASP.NET application can't figure out what state it's in, and how to process the request correctly.

If you look at the response sent back from the server you see that the server issues three cookies:

ASP.NET_SessionId=jnq5hh45zuuu0xyigc1jtm45; path=/

.EPiServerLogin=
6E1DBAC98D4073F956DA2000EBF122056E335441CCC7756F98B2
A229387EC47E446701A29
D36C4497553A5409F40322142C84B140E93C25CFC468C81
5B25CCC35648CE9B03C96XXXXXXXXXXXX; path=/;HttpOnly

ung1881.no=3568924299.20480.0000; expires=Sun, 25-Mar-2007 16:22:15 GMT; path=/

The interesting part is the .EPiServerLogin-cookie which is the authentication cookie. By adding this cookie to my subsequent requests, the server can tell that you're an authenticated user.

Now that we know what's going on when login into the page it's time to send an SMS message. I click the "Send SMS" link on the page, which takes me to the following URL: https://www.ung1881.no/Templates/SMS____24.aspx. I enter a phone number and message, and hit the button to send the message. The requests gets picked up by Fiddler, and by analyzing the request I figure out which form elements I need to post to the server in order to send a message:

Content-Disposition: form-data; name="defaultframework:_ctl2:Smssend:txtPhonenumber"
myNumber

Content-Disposition: form-data; name="defaultframework:_ctl2:Smssend:txtText"
myMessage

Content-Disposition: form-data; name="defaultframework:_ctl2:Smssend:butSend.x"
46

Content-Disposition: form-data; name="defaultframework:_ctl2:Smssend:butSend.y"
9

Content-Disposition: form-data; name="__VIEWSTATE"
*LARGE CHUNK OF STATE*

So after analyzing the application I now know the following about the communication between browser and server:

  • The login URL is: https://www.ung1881.no/default____3.aspx
  • The username form element is named: defaultframework:login:tbxUsername
  • The password form element is named: defaultframework:login:tbxPassword
  • The login button posts two values: defaultframework:login:LoginButton.x and defaultframework:login:LoginButton.y
  • The server issues an authentication cookie named .EPiServerLogin
  • The send SMS URL is: https://www.ung1881.no/Templates/SMS____24.aspx
  • The number form element is named: defaultframework:_ctl2:Smssend:txtPhonenumber
  • The message form element is named: defaultframework:_ctl2:Smssend:txtText
  • The send SMS button posts two values: defaultframework:_ctl2:Smssend:butSend.x and defaultframework:_ctl2:Smssend:butSend.y

Now that I know everything I need to know about the form elements It's time to write a C# class wrapping the site. The code is fairly well commented, so I won't describe it in detail. The key classes involved in the scrapper are the HttpWebRequest, HttpWebResponse, CookieContainer, StreamReader and StreamWriter classes. Another interesting part of the code is the private GetViewState method which extracts the view state of the page so that you can post it back to the server.

 

// Copyright (c) 2007, Jonas Follesø
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the Jonas Follesø nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY Jonas Follesø ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL Jonas Follesø BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Security.Authentication;

namespace Ung1881
{
    /// <summary>
    /// Proxy class wrapping the Ung1881 site for free SMS messaging.
    /// </summary>
    public class Ung1881Proxy
    {
        /// <summary>
        /// Variable used to store the authentication cookie.
        /// </summary>
        private CookieContainer cookies;

        /// <summary>
        /// Variable used to store the base uri of the page.
        /// </summary>
        private string baseUri = "https://www.ung1881.no/";

        /// <summary>
        /// Default constructor.
        /// </summary>
        public Ung1881Proxy()
        {
            cookies = new CookieContainer();
        }

        /// <summary>
        /// Login on Ung1881 using username and password.
        /// Authenticates against the site and keeps the auth cookie for next request.
        /// </summary>
        /// <param name="username">Username used to logon.</param>
        /// <param name="password">Password used to logon.</param>
        public void Login(string username, string password)
        {
            //Validate arguments.
            if (username == null || username.Length == 0)
                throw new ArgumentException("You must provide a username!", "username");

            if (password == null || password.Length == 0)
                throw new ArgumentException("You must provide a password!", "password");
            
            string loginUri = baseUri + "default____3.aspx";

            // Perform the first http request against the asp.net application login site.
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(loginUri);

            // Get the response object, so that we may get the session cookie.
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            // Populate the cookie container.
            request.CookieContainer = cookies;
            response.Cookies = request.CookieContainer.GetCookies(request.RequestUri);            

            // Read the incoming stream containing the login dialog page.
            StreamReader reader = new StreamReader(response.GetResponseStream());
            string loginDlgPage = reader.ReadToEnd();
            reader.Close();            

            // Extract the viewstate value from the login dialog page. 
            // We need to post this back, along with the username and password
            string viewState = GetViewState(loginDlgPage);

            // Build postback string.
            // This string will vary depending on the page. The best way to find out what your postback 
            // should look like is to monitor a normal login using a utility like Fiddler.
            string postback = String.Format("__VIEWSTATE={0}&defaultframework:login:tbxUsername={1}" +
                                            "&defaultframework:login:tbxPassword={2}" + 
                                            "&defaultframework:login:LoginButton.x=0&defaultframework:login:LoginButton.y=0",
                                            viewState, username, password);


            // Our second request is the POST of the username / password data.
            request = (HttpWebRequest)WebRequest.Create(loginUri);
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.CookieContainer = cookies;            

            // Write our postback data into the request stream
            StreamWriter writer = new StreamWriter(request.GetRequestStream());
            writer.Write(postback);
            writer.Close();

            reader = new StreamReader(request.GetResponse().GetResponseStream());
            loginDlgPage = reader.ReadToEnd();
            reader.Close();

            int index = loginDlgPage.IndexOf("Logg ut", StringComparison.OrdinalIgnoreCase);

            if (!CheckAuthenticationCookies() || index == -1)
            {
                throw new AuthenticationException("Unable to authenticate user. Check your username and password.");
            }            
        }

        /// <summary>
        /// Method sending a new SMS message trough Ung1881.
        /// </summary>
        /// <param name="phoneNumber">The phone number of the receiver.</param>
        /// <param name="message">The message to send.</param>
        /// <returns>True if the message was sendt sucsessfully.</returns>
        public void SendSms(string phoneNumber, string message)
        {
            //Validate arguments
            if (phoneNumber == null || phoneNumber.Length == 0)
                throw new ArgumentException("You need to provide a phone number!");

            if (message == null || message.Length == 0)
                throw new ArgumentException("You need to provide a message!");

            //Check that we have an authentication cookie.
            if (!CheckAuthenticationCookies())
                throw new AuthenticationException("User not authenticated. Call Login first!");

            //our third request is for the actual webpage after the login. 
            string smsUrl = baseUri + "/Templates/SMS____24.aspx";
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(smsUrl);
            request.CookieContainer = cookies;

            //and read the response
            StreamReader reader = new StreamReader(request.GetResponse().GetResponseStream());
            string page = reader.ReadToEnd();
            string viewState = GetViewState(page);

            string postback = String.Format("__VIEWSTATE={0}&defaultframework:_ctl2:Smssend:txtPhonenumber={1}" +
                                            "&defaultframework:_ctl2:Smssend:txtText={2}&defaultframework:_ctl2:Smssend:butSend.x=0" +
                                            "&defaultframework:_ctl2:Smssend:butSend.y=0", viewState, phoneNumber, message);

            reader.Close();

            request = (HttpWebRequest)WebRequest.Create(smsUrl);
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.CookieContainer = cookies;

            //Write our postback data into the request stream
            StreamWriter writer = new StreamWriter(request.GetRequestStream());
            writer.Write(postback);
            writer.Close();

            //Execute the request and read the response.
            reader = new StreamReader(request.GetResponse().GetResponseStream());
            page = reader.ReadToEnd();
            reader.Close();

            //Verify that the message was sent.
            if (!page.Contains("SMS sendt"))
            {
                throw new Ung1881Exception("Unable to send SMS message. Unknown error.");
            }            
        }

        /// <summary>
        /// Check if the user is authenticated.
        /// </summary>
        /// <returns>True if the user is authenticated.</returns>
        private bool CheckAuthenticationCookies()
        {
            bool authenticated = false;

            //Check that we have cookies.
            if (cookies != null)
            {
                //Check all cookies for the EpiServerLogin cookie.
                foreach (Cookie cookie in cookies.GetCookies(new Uri(baseUri)))
                {
                    if (cookie.Name != null && 
                        cookie.Name.Equals(".EPiServerLogin", StringComparison.OrdinalIgnoreCase))
                        authenticated = true;
                }
            }
            return authenticated;
        }

        /// <summary>
        /// Extract the viewstate data from a page.
        /// </summary>
        /// <param name="aspxPage">The raw HTML of the page.</param>
        /// <returns>Thew viewstate data of the page.</returns>
        private string GetViewState(string aspxPage)
        {
            Regex regex = new Regex("(?<=(__viewstate\".value.\")).*(?=\"./>)", RegexOptions.IgnoreCase);
            Match match = regex.Match(aspxPage);
            return System.Web.HttpUtility.UrlEncode(match.Value);
        }
    }
}

To test the class I've created a simple console application accepting a username, password, number and message as it's argument. Using the console application you can send SMS messages by typing the command: "SMS username password number message". If you add the folder containing the .EXE to your environment path you can send SMS messages from any command prompt.

 

// Copyright (c) 2007, Jonas Follesø
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the Jonas Follesø nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY Jonas Follesø ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL Jonas Follesø BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Ung1881;
namespace ConsoleScraper
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                //Check that we have at least four arguments (username, password, number, message)
                if (args.Length < 4)
                {
                    Console.WriteLine("Usage: SMS username password number message");
                }
                else
                {
                    //Extract variables from arguments.
                    string username = args[0];
                    string password = args[1];
                    string number = args[2];
                    string message = string.Empty;

                    //Build up the message.
                    for (int i = 3; i < args.Length; ++i)
                    {
                        message += args[i];

                        //Add space if this isn't the last word of the message.
                        message += (i == args.Length - 1) ? string.Empty : " ";
                    }

                    Console.WriteLine("Sending message \"{0}\" to number {1}", message, number);

                    //Send the message.
                    Ung1881Client client = new Ung1881Client(username, password);
                    client.SendMessage(number, message);                    
                    Console.WriteLine("Message \"{0}\" sent to number {1}", message, number);
                }
            }
            catch (Exception ex)
            {
                //Simple exception handling.
                Console.WriteLine(ex.ToString());
            }
        }
    }
}

So that's about it. A simple C# library allowing you to send unlimited free SMS messages through "Ung1881". You can choose to either download the compiled binaries or the source code. In the next part of this article/post I'll discuss how to use the library in a Windows Vista Sidebar Gadget.

If you have any questions, comments or bugs, or find the library useful, please drop me a comment!

I love Team Trafikks "Bus Oracle". Basically it's a web site where you can ask about bus schedules using "natural language". So you can give the "oracle" questions like "when does the next buss from A to B leave?", or even more advanced questions like "when do I have to take the buss from A to be at B after 19.00 Monday?".  The "oracle" is implemented as a student project at NTNU, and made available by the bus company in Trondheim.

At the moment the "oracle" is available on Team Trafikks webpage or by SMS. There is no open service interface to implement your own clients, but I love to use this small, but brilliant service, as an example in various presentations. I've implemented both Live.com and Sidebar gadgets using the service previously, but I haven't gotten around publishing a version running on the final version of Windows Vista until now!

gadgetgallery.jpg

oraclegadget.jpg

The gadget is really simple and let you ask the "oracle" questions directly from your Windows Vista Sidebar. To install the Gadget simply click the button bellow:

Tip: A Gadget is just a zip compressed folder with a .gadget extension. In order to get the "proper" installation experience you need to add a new MIME header on your server. Simple register the application/x-windows-gadget MIME-type with the .gadget extension.

I've also written a MSN Messenger robot allowing you to ask the "oracle" questions directly using MSN Messenger. The robot have been a little unstable, but I've finally gotten around to make the code more robust and found a more reliable host for the server. To access the "oracle" on MSN, simply add bussorakel@hotmail.com as a new contact on MSN Messenger.

msnoracle.jpg

If you live in Oslo there is a similar service available from Trafikanten. A MSN Messenger robot is available at trafikanten@hotmail.com, and I'm currently working on a Sidebar Gadget version as well.

Olav (MS Norway), me, Rune (ADE MS Norway) and Kristine (Avanade)It's Monday night and I'm safely back home in Trondheim. I've spent the weekend recovering from a really exiting but still tiresome TechEd week in Barcelona.

Wednesday was all about interviews and demos. Early Wednesday Simon Brown and Arfa (that 11 year old Pakistan girl from the key note) dropped by our stand and asked for an Imagine Cup demo. Arfa was really interested in the project, but most of all she wanted to compete in the Imagine Cup her self, even tough she have to wait four more years till she turns 16…

During the day we gave three video interviews, one with Virtual TechEd, one with my mate Dave McMahon and finally a Channel9 interview. I'll post links as soon as the interviews are available online. Just after the Channel9 interview Anders Hejlsberg dropped by the Imagine Cup stand to check out our and the Italian project. Me and Hans Olav got a chance to give him the demo, and talk to him about technologies used to implement the project, Anders sessions at TechEd and LINQ. It was great to get a chance to meet Anders and chat with him.

Wednesday evening was all about the infamous, annual Norwegian TechEd party at the Hard Rock Cafe. More than 200 Norwegian delegates where attending TechEd this year, and the Norwegian party is know for being the best TechEd party, so quite a few speakers dropped by as well. As you can imagine, the place was quite crowded and the atmosphere was great!

Thursday was the "Microsoft Student Partner Program" day. 120 students from around the EMEA region was invited to attend TechEd during the day. Henrik, the Danish academic evangelist, was also in Barcelona, so it was fun seeing him again. Thursday after noon Caroline Phillips officially announced the Microsoft Student Partner Program at the first EMEA MSP meeting. During the meeting we gave a 25 minute presentation talking about our Imagine Cup project and most importantly the experience in India during the world finals.

After the meeting all 120 MSP, all the ADE's and a couple of other Microsoft people went over to "Lasermon" which has Barcelona's largest laser gun arena. We played laser death match, had all kinds of Spanish food and plenty of drinks. It was great to meet students from around the EMEA region and talk about how they run their local student community user groups.

During the party I also got a chance to catch up with Rob Burke from Microsoft Ireland. He's a really great guy, and has a really god blog up at http://blogs.msdn.com/robburke, and is allso a frequent Flickr poster.

Our flight back to Norway left Friday after noon, so we didn't have time to attend TechEd Friday. It was nice to get home Friday afternoon and have the weekend to recover  after TechEd.

As you can imagine after reading the posts TechEd this year was really busy for us. I didn't get a chance to attend as many sessions as I wanted, but then again we will be receiving the TechEd post conference DVD with all the sessions. You can cream all the great content into one DVD, but you cant capture the true atmosphere and all the people you meet at TechEd into one DVD. You'll have to be there your self.

Finally, a big shout out to everyone I meet during the TechEd week, and special thanks to Caroline for inviting us.

Oh, by the way, Hege and Caroline have uploaded a bunch of pictures on their Flickr sites. Be sure to check them out.

PS. I installed Office 2007 RTM today. Worked like a charm! Some really cool new features in OneNote 2007 I'll blog about later.


PPS: I have lots of great ideas after TechEd, just need time to put them in motion. One of the things I'm currently playing with involves IQueriable<T>… More to come on this one…

gameoflifeGame of Life is one of those simple, yet really fascinating mathematical ideas you sometime learn about. One of the assignments in the course "object oriented software development" is to first model the "Game of Life" and then implement it in Java.

The Game of Life was invented by Dr. John Conway, and is one of the simplest examples of what is sometimes called "emergent complexity" or "self-organizing systems." Life isn't a game in the traditional sense of the word. It's a grid filled with cells, either dead or alive. Some simple rules determines the state of a cell. The rules that rule the universe of "Life" are as follow:

  • A dead cell with exactly three live neighbors becomes a live cell (birth).
  • A live cell with two or three live neighbors stays alive (survival).
  • In all other cases, a cell dies or remains dead (overcrowding or loneliness).

I got really fascinated by this simple "game", and after doing some reading on the subject it turns out you can implement a "turing machine" in Live, which basically means you can implement any computer program as a pattern inside the "Life" game. For instance there are examples where people have implemented programs that finds prime numbers using the simple rules of "Life".

If you're interested in learning more about "The Game of Life" I recommend checking up the site "Wonders of Math". The Wikipedia article on the subject also gives a nice introduction to the game. If you want to get the latest and greatest discoveries of new and interested patterns in "Life" the "Game of Life News" site is the place to be. If you want to learn how to implement a touring machine in "Life" check out this PDF document. If you just want to check out the "code", check out this gif image showing the touring machine pattern.

If you want to play with Game of Life your self you can either run my compiled version directly (JAR) or download a ZIP file containing both the compiled version and the Java code.

I've uploaded the slides from yesterdays user group presentation in Trondheim. There wasn't really much example code worth uploading, so I just uploaded the Power Point slides. The example code that ships with ATLAS shows most of the stuff I demoed yesterday.

The presentation I gave was about a project me, Gøran and Espen have been working on since early spring. The project is an application that runs in 8 hospitals in the region helping them to track post surgery infections. In the application we used allot of Atlas to improve the user experience. So during the presentation I show cased some of the areas where we used Atlas, and demoed how to implement stuff such as the update panel, the auto complete textbox and the modal popup extender.

I also talked about contentious integration and Cruise Control .NET and how that was a success factor in our project. It turned out that very few knew about CC.NET, so I spent some time discussing it.

After the main presentation I fired up XNA and used the Spacewar starter kit for a friendly competition giving away Francesco Balenas book "Programming Microsoft Visual C# 2005: The Base Class Library".

I've added a set of links relevant to the presentations, including a link to the excellent book "Ship it! A Practical Guide to Successful Software Projects", which discuss continuous integration and other techniques to ship your software project on time.

Oh, and I have to mention that the Norwegian .NET User Group just released a brand new site which looks really promising. Now we just have to fill it with content.

We need more speakers to keep NNUG going, so if you'd like to give a presentation at NNUG Trondheim, drop a mail to trondheim@nnug.no.

If you have any questions or comment related to the presentation just add them as a comment to this blog post.

ScreenshotWant to congratulate Eric Carr (he need to get something up on his site) as the winner of the Gadget development competition I helped arrange as part of MSDN Live spring 2006. Eric wrote three really cool gadgets for Live.com (and MSN Spaces) that you definitely should check out:

Eric is the lucky winner of a Xbox 360! Looking forward to see you online on Xbox Live.

 

taj mahalThis is the last night in India. What an amazing week! We've had so much stuff to do all the time that It feels like we've been her for way more than 9 days.

The last few days have been just amazing! Wednesday evening we got the message that we made it trough to the final six. Together with Denmark, Italy, Brazil, China and Japan we where going to compete in the final championship round in Dehli. We left from Agra 5 in the morning on Thursday and went straight to the convention centre where the final round was held. We where the first team presenting our solution. The final round was an open presentation where the other students competing in the Imagine Cup was invited to watch the final 6 presentations. I don't know the exact number, but I guess there where between 200 and 300 people watching the final presentations.

Once we where done presenting our solution we spend the entire day at the convention watching the other teams giving their software design presentations. After the software design presentations we got a chance to watch the contributions in user interface design and short film. Some of the Windows Presentation Foundation applications where just amazing. Even better than Microsoft's own showcases! The films where great too. Will post a link as soon as the short film contributions are available online.

All the winners where announced Friday during the "World festival", where Microsoft executives, the Indian minister of technology, gave some great speeches.

After seeing the other teams final presentations we didn't have to high expectations, but man it felt good when we where announced as number three in the software design category! The price was 10.000$, a nice trophy, and an invitation to spend 14 days in Reading (UK) at Microsoft/BT's expenses to develop the idea further.

After the winners where announced we had to lots of interviews, Indian newspapers, Japanese computer magazines, Indonesian TV and all kinds of other strange Asian media. We've also gotten some good press back in Norway, so when I get back to Trondheim I'll collect all the online articles and put up some links. For now I'll just link to the Dagbladet article titled "geek bronze".

Later Friday night Microsoft threw a great pool party, with great food and free drinks. Because of Dehli regulations they had to turn down the music quite early, so later that night we went into Dehli city to one of the most popular nightclubs in the city. That was an really interesting experience, will post more pictures later. Was back at the hotel room 4AM.

Today we've been relaxing at the hotel before visiting a "Bazar", which basically was like an "underground" station with tons of shops selling all kind of fake crap. "iPod shulffles" with display, Sony 4gb mp4 player and TONS of copied PS2, Xbox and computer games. The only thing they couldn't copy was the Sony PSP games, so the price was about the same as in Norway. After some heavy barging i managed to get Syphon Filter Dark Mirror for one third of the Norwegian price, so good deal.

Anyhow, we're leaving for Norway Sunday morning, but because of terror threats we need to be at the airport 5 hours in advance. Will post more pictures and links when I'm back home in Trondheim… Looking forward to that after a tough, but amazing, week!

 

 

Monkeys aroundToday is the fourth day of the Imagine Cup in India. We arrived one day earlier than most of the other contestant, so during Sunday more and more students where arriving. On Sunday night we had the welcome party, with opening speeches and videos, music and food. The "band" that played on the opening night was an Indian version of the Norwegian band "Ralph Mayers and The Jack Harren Band". I don't remember the name so I'll look it up later. The Norwegian team left early from the party to work on out application, and we weren't in bed until 04 AM.

 

Monday was the first day of the contest. We started out by doing a 7 minute lightning round which didn't count. This round was held just to get us warmed up. Later that day we had the first real round of the Imagine Cup, a 20 minute presentation and 10 minutes of questions. The presentation went excellent and all the demos worked perfectly. Later that day we (team Norway), Japan and UK where invited to do a press briefing talking about our projects and our experience as contestant at the Imagine Cup world finals.

 

Tuesday morning was spent in our team booth giving presentations to media, other teams and guests of the competition. There where quite allot of people interested in our project, so we where quite really busy. The 12 teams who made it to the next round where announced around lunch. I don't remember all the other teams who made it, but both Norway and Denmark made it to the next round. 41 teams are now down to one. We did our second round presentations Tuesday afternoon, which now was 35 minutes and 15 minutes of questions. The judges gave us great feedback, and actually said that they where blown away… So no our fingers are crossed, and hopefully we'll move on to the final 6 teams to present tomorrow Thursday.

 

Today, Wednesday, we've been relaxing and visiting and old mausoleum for some important Indian guy from the early 1600's. I don't remember his name, so I'll post a Wikipedia link later on. We spend the day divided into groups doing different kinds of work at the site. Some people where working in the garden, while others where filling cracks in the floor and walls, or  where swiping dust. Now we just had lunch before heading over to Taj Mahal, something I'm definitely are looking forward to.

 

Gøran have posted som pictures on his Flickr site. Check them out over at: http://www.flickr.com/photos/22075141@N00/sets/72057594128196432/

Can you spot the monkey?This week I'll be attending the Imagine Cup world finals in India. We flew from Oslo early Friday morning, and arrived in Dehli late Friday night. After a short stop for some food and refreshments in Dehli we jumped in the buss and drew for four hours to Agra. The drive was _really_ interesting. Even tough we where driving in the middle of the night there were people walking along the road everywhere. People sleeping on the roof of their truck or buss. Crowds of cows walking in the middle of the street. A gang of monkeys looking at us from the rooftops of buildings that looked like the where going to collapse any moment. Jan Kristian took lots of pictures which he will upload to his Flickr site soon.

We arrived at the Jaypee Palace hotel early Saturday morning. After almost 24 hours of travelling. We've spent the first day in India relaxing in the sun, bathing, talking to the hotel monkey, and doing some preparations for the contest.

Later tonight we're going to check out the Hotell Spa and perhaps get a massage or something.

This weekend I was in Oslo for the final round in the “Microsoft days spring 2006” event. I’ve been traveling with Microsoft to the four largest cities in Norway giving presentations on .NET, Gadgets and Windows Presentation Foundation.

 

The presentations in Oslo went well and there where quite a few people who showed up for our “latest news” developer track. The slides and code are available on a previous post.

 

During the Oslo event I also recorded a trimmed down version of my Gadget presentation. I’ll write a new post as soon as the recording is available online. Be sure to check out Sondres ASP.NET 2.0 and RSS slides over at his blog.

 

Thanks to everyone who showed up, and good luck in the Gadget competition!

I’ve finally gotten around uploading the sample code and presentation slides from the MSDN Live presentations I’ve been doing with Microsoft over the last couple of weeks. For those of you who didn’t get a chance to attend MSDN Live / Microsoft days this spring we’ll be recording some of the content in Oslo may 15th. I’ll write a blog post as soon as the content is available online.

In the mean time you can download the slides and Gadget code, and perhaps throw together something your self for the Gadget competition.

Introduction to the .NET Framework
I’ve only uploaded the slides from this presentation. The demos are fairly straight forward, a simple web service and a simple client retrieving data from this service. If you attended this session, and want to learn more, my suggestion is to download the SDK, install VS2005 and play with some of the introduction tutorials. I also have two book recommendations:

These are easy to read, short, fun, and colorful introductions to web and windows development on the .NET platform. It walks you trough a full program, or a full website trough out the book.

The slides from the presentation is available here: Introduksjon til dotNET.ppt


Gadgets, Gadgets, Gadgets
I’ve uploaded the sample code, VS2005 code snippets and slides from this presentation. The sample code contains the “Bussoracle” for the Live.com platform and the Vista Sidebar. If you only want to run the gadget you can download the Sidebar version or click this link to add it to your Live.com start page.

Screenshot of the Live.com and Sidebar version of the Bussoracle Gadget

There are a few things you have to keep in mind when doing gadget development for Live.com:

  • For gadget development you need to add live.com and localhost to your trusted sites list.
  • If you’re doing gadget development on IE7 Beta2 you need to add the following registry key: [HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_XMLHTTP_RESPECT_ZONEPOLICY] "Iexplore.exe"=dword:00000001

By default IE7 Beta 2 will ignore your trusted sites for XMLHTTP requests, so in order for you to do local development you need to tell IE to look at your trusted sites before allowing/disallowing an XMLHTTP request.

To use the Visual Studio 2005 Code Snippets I showed during the presentation you need to copy the files to your local snippet folders. By default this is located under “Document and Settings\Your User\My Documents\Visual Studio 2005\Code Snippets\XML”. As I mentioned during the presentation, Visual Studio only supports code snippets for XML, C#, VB.NET and J#. How ever, you can create JavaScript code snippet as XML snippets, and add them to your code inside an XML comment tag, and then cut/paste into your JavaScript file. I’ll show this trick in the recorded version of the session.

For those of you who want to compete in the Gadget competition I’ll write a new post with content rules and details.

The code and slides are available here: Gadgets.zip

Better user experience with Windows Presentation Foundation 
The expression splash screenFor this presentation I’ve only uploaded the slides. The demo is basically a walkthrough of the Fabrikam tutorial that ships with the Expression Interactive Designer. I would strongly suggest walking trough these tutorials your self to get a feel of what Expression Interactive Designer can do.

The presentation is available here: WPF.ppt

I hope you all had a good  time at the MSDN Live / Microsoft Days Event. Any feedback is appreciated!

I gave three presentations in Bergen last Thursday. The presentations went fine, except there could have been a bit more people attending the sessions. I’ll upload the Powerpoints and example code once I get back from the Microsoft days event in Stavanger next week. Stay tuned!

I’ll also be publishing some more information on the Gadget Xbox 360 competition we’re throwing together.

I’ll be giving three presentations at the next round of the “Microsoft days”, a quarterly event held in the four largest cities in Norway. The event has three target groups; PC-users, IT management and technicians (TechNet) and developers (MSDN). The MSDN part of the event has two tracks, one on Team System and one on “the latest and greatest” in development for Office 2007 and Vista.

My first session is a breakfast seminar on “.NET introduction” for totally beginners. The next session is on “Microsoft Gadgets” (Sidebar, Live.com and SideShow), and my final session is on improving the user experience using Windows Presentation Foundation.

My good friend and fellow RD Sondre will be giving three presentations as well. An introduction to Team System, how to improve user experience online using Atlas, and finally “information to the people” using the RSS platform in Vista.

After the sessions there will be an “after tech” where you can hang out with fellow developers, get some food and beer and listen to some live music. All in all the agenda looks great!

The dates to spare are as follow:

  • Bergen 26.april
  • Stavanger 04.may
  • Trondheim 08.may
  • Oslo 15.may

You can read more about the event and sign up at http://www.microsoftdagene.no/. Oh, allmost forgot to mention: the event is absolutely free! Hope to see you there! 

SBGDevShowcaseEver since the Xbox 360 launch in December various third party community web sites accessing and tweaking the publicly available Gamer Card data have been available. Most of these sites have used screen scrapping to access the Gamer Card information available on the HTML site intended to integrate on your blog. I’ve previously blogged about MyGamerCard.net, which is an excellent community site that lets you create custom gamer card pictures you can use on your blog, as well as provide achievement leader boards.

The Xbox team has obviously taken this community interest in game statistics seriously, and has started something called the “Xbox Community Developer Program”. You can apply to become a member of this program to get access to a private forum on xbox.com, as well as a private XML feed with all the Gamer Card information, as well as a list of previously played games. This is way easier and faster than using screen scrapping to retrieve this information.

I applied by sending some reference projects and information about my self, and got approved to become a member of the program. You can get more information about the program, what you get and how to apply by clicking here. They also have a Xbox Community Developer Program showcase site, where you can check out what other people are using the feed for.

After I released the “Buss oracle” MSN bot I’ve gotten some great feedback, both from end users and other .NET developers. I’ve also posted an article up on msstudent.no on how to use the DotMSN library to build your own bot. I know some of the readers of my blog are interested in this topic, so this should be some very interesting news.

 

Conversagent, the company behind the Encarta MSN bot implementation is making their BuddyScript SDK available for free download for anyone who wants to try to build a bot or activity application. The free download offer is valid for at least 6 months, starting January 29, 2006. The limitation of bots built using this SDK is 50 000 sessions per month. If you’re building something really popular that requires more sessions they can evaluate your bots on a case by case basis and remove the limitations. The bot itself is hosted by Conversagent on one of their servers.

 

The website says nothing about what will happen after the 6 month period, if this will be made available for free on a permanent basis, or if it will be made available as an commercial product. There is allso a forum post written by MSN Product Manager Todd Biggs avilable at the Messenger API forum at MSDN.

 

I haven’t had time to download and check out the SDK my self yet, but I figured I had to get this post out there. Thanks to Jan Kristian for mentioning this. If you want an example of what you could possible build, just check out the Encarta bot by adding encarta@conversagent.com to your contact list in MSN Messenger.

 

I’ll keep you posted as I find out more about this SDK and what you can do with it!

About a week ago i released my MSN bot accessing a “bus oracle” set up by the bus company in Trondheim. It’s a service that lets you ask bus schedule questions using “natural language”. Tonight the bot got its user number 200! The cool thing is that i told 15 people about the bot and then the rumour started spreading! Wonder how long it will take to get 500 users..?

I’m currently working on a few updates, one of them being user specific variables. Like, “home”, “school”, “girl friend” etc, which will allow the users to ask questions like; “when does the next bus from home to school leave?”.

Being as passioned about computers and technologies as me, I figured it was about time I jumped the blog wagon. This is my first post, and it’s about my latest project; two MSN bots.

 This summer I came across a nice little .NET library wrapping the MSN Messenger protocol, but I haven’t had time to check it out until now. The library is called DotMSN and the compiled assembly, documentation and source code can be downloaded from http://www.xihsolutions.net/dotmsn/. The library is quite straight forward, you create a new Messenger object, set your credentials, connect to the name server, and start responding to events, such as conversation created, contact added etc. I’ll probably write an article about how to use the library later on.

 At the moment I’ve got two bots up and running, offering a really nifty little service. In Trondheim, the company offering bus service has a nice web application where you can ask about bus routes using natural language. The language interpretation is written by one of the professors in artificial intelligence at the local university, so it’s actually quite good. You can ask the “Bus Oracle” questions such as “When does the next buss from A to B leave, after 16.00 Saturday”. I’m using screen scrapping to access the web page offering this service, and the MSN bot acts as a gateway between messenger and the bus oracle. To access the bot, simply add bussorakel@hotmail.com to your messenger contact list.

 I’ve also wrapped the equivalent service in Oslo, called Trafikanten. Its understanding of natural language isn’t as good as the bus oracle, but you can ask questions like “From A to B”. To access the bot, simply add trafikanten@hotmail.com to your messenger contact list.

 Both bots accept the command “!hjelp” which will show you a list of available commands. Comments and suggestions are appreciated. 

<March 2010>
SunMonTueWedThuFriSat
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910