 |
FastCheck Get notified when you receive new emails!
|
| View previous topic :: View next topic |
| Author |
Message |
Jeremy Howard The "e" in e-mail
Joined: 09 Apr 2002 Posts: 325 Location: Melbourne
|
Posted: Fri Aug 29, 2003 4:03 am Post subject: Second test version of FastServices API |
|
|
Okay folks, good news, we've now changed the FastServices protocol so it should be much more easy to work with languages other than Perl, including Delphi, and .Net.
First, grab the latest Perl test script from here:
http://jhoward.fastmail.fm/fastcheck/testsoapfolders.pl
Now, create a directory called "SOAP" wherever you downloaded to the test script to, and then download the following module into that directory:
http://jhoward.fastmail.fm/fastcheck/MessagingEngine.pm
Next, open up a command prompt or terminal in the directory where you placed the Perl test script, and type the following command: | Code: | | perl -w scripts/fmtest/testsoapfolders.pl www.fastmail.fm username password |
You will see lots of SOAP communication start appearing on your screen, to help you with your debugging and understanding of the protocol. To turn this off, find the line which says "+trace => [qw(all -transport)]," in MessagingEngine.pm, and add a hash symbol (#) before it to comment it out.
I will now explain what each part of the SOAP communication means by showing the body of each request and response: | Code: | POST http://www.fastmail.fm/SOAP/
<namesp1:CreateSession xmlns:namesp1="http://www.fastmail.fm/SOAP/MessagingEngine">
<UserName xsi:type="xsd:string">testuser</UserName>
</namesp1:CreateSession>
<SOAP-ENV:Fault>
<faultcode xsi:type="xsd:string"
>SOAP-ENV:Client.Proxy</faultcode>
<faultstring xsi:type="xsd:string"
>Wrong server; please change to the correct endpoint for this user</faultstring>
<detail xsi:type="xsd:string"
>Wrong server specified; User: testuser; Required endpoint: http://www.fastmail.fm/SOAP2/; ServerName: 2; HostNum: 1</detail>
<faultactor xsi:type="xsd:string"
>http://www.fastmail.fm/SOAP2/</faultactor>
</SOAP-ENV:Fault> | This shows the code to create a session, which takes a single string parameter, of the username to create a session for. As you can see, in this case we used the wrong endpoint for this user. When you use FastServices, you must always check for this Fault, and change to the new endpoint requested. The " Faultactor" contains the new endpoint required. You should then save this value, and use it in the future for this username, since it will then make creating a session much faster.
| Code: | POST http://www.fastmail.fm/SOAP2/
<SOAP-ENV:Body>
<namesp2:CreateSession xmlns:namesp2="http://www.fastmail.fm/SOAP/MessagingEngine"
>
<UserName xsi:type="xsd:string"
>testuser</UserName>
</namesp2:CreateSession>
<namesp1:CreateSessionResponse xmlns:namesp1="http://www.fastmail.fm/SOAP/MessagingEngine">
<SessionStr xsi:type="xsd:string"
>301aca0d939ce71cc610/2e96aab9/35e341ae</SessionStr>
<OneTime xsi:type="xsd:string"
>6d4c4b9d26297e79</OneTime>
<Success xsi:type="xsd:int"
>1</Success>
</namesp1:CreateSessionResponse> |
We have now repeated to the call, changing only the endpoint in the post request. We have now been given a session string, and a challenge. From now on, every function that we call will return these two things as the first two parameters. Any additional return values will come after these two parameters; in this case there is a single return value indicating success or failure.
| Code: | <namesp4:URL_CreateURL xmlns:namesp4="http://www.fastmail.fm/SOAP/MessagingEngine">
<SessionStr xsi:type="xsd:string"
>301aca0d939ce71cc610/2e96aab9/35e341ae</SessionStr>
<OneTimeEnc xsi:type="xsd:string"
>OTgQ7byRXfx5/5L4DDEJag</OneTimeEnc>
<c-gensym12 xsi:type="xsd:string"
>Compose</c-gensym12>
</namesp4:URL_CreateURL>
<namesp1:URL_CreateURLResponse xmlns:namesp1="http://www.fastmail.fm/SOAP/MessagingEngine">
<SessionStr xsi:type="xsd:string"
>301aca0d939ce71cc610/2e96aab9/35e341ae</SessionStr>
<OneTime xsi:type="xsd:string"
>4db3051c6bb1008b</OneTime>
<HREF xsi:type="xsd:string"
>
http://www.fastmail.fm/mail2/?Ust=2e96aab9!35e341ae;Uid=301aca0d939ce71cc610!1062127348;MSignal=MC-Service@0
</HREF>
</namesp1:URL_CreateURLResponse> | Above you see us calling our first API function. The first parameter must be the session string which was returned by CreateSession. The second parameter is the challenge that we received earlier, concatenated with a ":", concatenated with the user's password, which is then encrypted with MD5, and encoded with Base64. The Perl code which does this is: | Code: | | md5_base64("$Self->{OneTime}:$OTPassword") | when you have ported this code snippet to your preferred language, please post it here.
After these two parameters, we pass any parameters that are required by the API function. The URL_CreateURL function takes one parameter, which is a string, showing the screen which a URL is required for.
As you can see, in the response we get the same two parameters that we always receive, to allow us to construct our next API call, followed by the actual return value or values from this API function. In this case, we get the URL that we requested in the third parameter. This API call returns a URL for an already open session, so going to this URL in a web browser is very fast indeed (no authentication or redirects required).
Finally, I will show one more example. | Code: | <namesp3:AccountInfo_GetFolderList xmlns:namesp3="http://www.fastmail.fm/SOAP/MessagingEngine">
<SessionStr xsi:type="xsd:string"
>301aca0d939ce71cc610/2e96aab9/35e341ae</SessionStr>
<OneTimeEnc xsi:type="xsd:string"
>S9TZOcu4zfu05oLR1XDSkA</OneTimeEnc>
</namesp3:AccountInfo_GetFolderList>
<namesp1:AccountInfo_GetFolderListResponse xmlns:namesp1="http://www.fastmail.fm/SOAP/MessagingEngine">
<SessionStr xsi:type="xsd:string"
>301aca0d939ce71cc610/2e96aab9/35e341ae</SessionStr>
<OneTime xsi:type="xsd:string"
>ec0b9194f2170e56</OneTime>
<FolderList xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="namesp2:SOAPStruct[4]">
<item xsi:type="namesp2:SOAPStruct">
<MessageCount xsi:type="xsd:int"
>6</MessageCount>
<NoSelect xsi:type="xsd:int"
>0</NoSelect>
<UnreadCount xsi:type="xsd:int"
>5</UnreadCount>
<FolderName xsi:type="xsd:string"
>Inbox</FolderName>
<FolderId xsi:type="xsd:int"
>1121269</FolderId>
</item>
<...>
</FolderList>
</namesp1:AccountInfo_GetFolderListResponse> | the AccountInfo_GetFolderList does not take any parameters, so only the usual session string and encoded password are passed to the function.
The only tricky bit here is in the return value. The return value uses a hash (known as a hashtable, map, dictionary, and various other things in other languages), for which there is no standard serialisation in SOAP. We are using the SOAPStruct type from the "http://xml.apache.org/xml-soap" namespace, which may not be supported in all languages. If you have better ideas for how to serialise these types of structure, in order to simplify interoperability, please let us know.
Once we have this basic framework ported to one or more other languages, we will begin expanding the API to provide rich functionality. Please do post here if you have any questions or comments. Once you have something in your preferred language, post a URL to your code, so we can all check it out!  |
|
| Back to top |
|
 |
rthomas
Joined: 25 Aug 2003 Posts: 11 Location: France, Lille
|
Posted: Fri Aug 29, 2003 7:58 am Post subject: Stiil have problem |
|
|
|
|
| Back to top |
|
 |
Kander
Joined: 22 Apr 2003 Posts: 31
|
Posted: Fri Aug 29, 2003 8:45 am Post subject: Re: Second test version of FastServices API |
|
|
[quote="Jeremy Howard"]The Perl code which does this is: | Code: | | md5_base64("$Self->{OneTime}:$OTPassword") |
PHP:
Not sure if/how this gives the same result as the Perl code... I don't know anything about Perl. Could someone run the perl script with inputs $Self->(OneTime) being set as Foobar and $OTPassword being set as 'mypassword' to compare results?
I assume OneTime is a property of the object $Self? and $OTPassword is just a variable?
| Code: |
base64_encode(md5($Self->OneTime.":".$OTPassword));
|
My output is: YzhlNzk3NzlhMWJjMzE4YTRhMGZlN2NiYjI5NDdhZGU=
Note: Not sure if Jeremy's Perl does the MD5 or the Base64 first, so just in case it's the other way around:
| Code: |
md5(base64_encode($Self->OneTime.":".$OTPassword));
|
Second output: c3cd5272cb722f2d9d08e52ea777c444
I hope this helps anyone a bit...
--K |
|
| Back to top |
|
 |
eric_thiebaut Site Admin
Joined: 07 Apr 2002 Posts: 1523 Location: Sydney, Australia
|
Posted: Fri Aug 29, 2003 9:43 am Post subject: Much better! |
|
|
Yep, much easier!
I can now send the first CreateSession request, get the redirection URL and send the second request, which succeeds!
The only problem: for the moment, I can't get the results. But I'm almost there, so I reckon it shouldn't take me too long!
Eric |
|
| Back to top |
|
 |
eric_thiebaut Site Admin
Joined: 07 Apr 2002 Posts: 1523 Location: Sydney, Australia
|
Posted: Fri Aug 29, 2003 10:42 am Post subject: |
|
|
Yeah baby, Yeah! Got it!
The problem was because perl doesn't return fully qualified attributes. So by removing 'elementFormDefault="qualified"' it all works!
So here's the wsdl:
| Code: | <?xml version="1.0" encoding="utf-8"?>
<definitions
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:s0="http://www.fastmail.fm/SOAP/MessagingEngine"
xmlns:soapenc="http://schemas.xmlsoap.org/SOAP/encoding/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
targetNamespace="http://www.fastmail.fm/SOAP/MessagingEngine"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<xsd:schema targetNamespace="http://www.fastmail.fm/SOAP/MessagingEngine">
<xsd:element name="CreateSession">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="1" maxOccurs="1" name="UserName" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="CreateSessionResponse">
<xsd:complexType>
<xsd:all>
<xsd:element name="SessionStr" type="xsd:string" />
<xsd:element name="OneTime" type="xsd:string" />
<xsd:element name="Success" type="xsd:int" />
</xsd:all>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</types>
<message name="CreateSessionSoapIn">
<part name="parameters" element="s0:CreateSession" />
</message>
<message name="CreateSessionSoapOut">
<part name="parameters" element="s0:CreateSessionResponse" />
</message>
<portType name="FastServicesSoap">
<operation name="CreateSession">
<input message="s0:CreateSessionSoapIn" />
<output message="s0:CreateSessionSoapOut" />
</operation>
</portType>
<binding name="FastServicesSoap" type="s0:FastServicesSoap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
<operation name="CreateSession">
<soap:operation soapAction="http://www.fastmail.fm/SOAP/MessagingEngine/CreateSession" style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
<service name="FastServices">
<port name="FastServicesSoap" binding="s0:FastServicesSoap">
<soap:address location="http://www.fastmail.fm/SOAP/MessagingEngine" />
</port>
</service>
</definitions> |
And the C# client code:
| Code: | using System;
using System.Xml;
using System.Web.Services.Protocols;
namespace TestSoap
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
TestSoap.FastServices.FastServices c=new TestSoap.FastServices.FastServices();
bool bRetry=false;
string SessionStr;
string OneTime;
int Success;
try
{
SessionStr=c.CreateSession("johndoe",out OneTime,out Success);
}
catch(SoapException s)
{
c.Url=s.Actor+"MessagingEngine";
bRetry=true;
}
if (bRetry)
{
SessionStr=c.CreateSession("johndoe",out OneTime,out Success);
System.Console.Out.WriteLine(
"Session: {0}\nOneTime: {1}\nSuccess: {2}",
SessionStr,
OneTime,
Success);
}
}
}
}
|
That's it!
I'm going to try to GetFolder call now... |
|
| Back to top |
|
 |
eric_thiebaut Site Admin
Joined: 07 Apr 2002 Posts: 1523 Location: Sydney, Australia
|
Posted: Fri Aug 29, 2003 10:43 am Post subject: |
|
|
Of course replace johndoe by your account name...
 |
|
| Back to top |
|
 |
rthomas
Joined: 25 Aug 2003 Posts: 11 Location: France, Lille
|
Posted: Fri Aug 29, 2003 10:50 am Post subject: |
|
|
It's working, great !  |
|
| Back to top |
|
 |
Jeremy Howard The "e" in e-mail
Joined: 09 Apr 2002 Posts: 325 Location: Melbourne
|
Posted: Fri Aug 29, 2003 12:17 pm Post subject: |
|
|
Well done gang!
I'm thinking that for the hash/map problem, maybe we shouldn't use them in the API at all. Instead, anywhere we'd normally use a hash, instead return 2 arrays, one of the keys, one of the values. Slightly less convenient, but much more portable. What do you think? |
|
| Back to top |
|
 |
Jeremy Howard The "e" in e-mail
Joined: 09 Apr 2002 Posts: 325 Location: Melbourne
|
Posted: Fri Aug 29, 2003 12:18 pm Post subject: |
|
|
It's MD5, then Base64.
If you need more details, see the source of Digest::MD5 on CPAN. |
|
| Back to top |
|
 |
eric_thiebaut Site Admin
Joined: 07 Apr 2002 Posts: 1523 Location: Sydney, Australia
|
Posted: Fri Aug 29, 2003 12:44 pm Post subject: |
|
|
MD5 & Base64 sources are widely available in C, so this should be OK. (the current version of FastCheck already uses MD5 by the way). I reckon there must be a C# implementation somewhere too if needed.
I'll try to see about the hashes.
I'm of scuba diving this WE - preparing my instructor course .
So I won't be able to work on it until Sunday night at best... |
|
| Back to top |
|
 |
rthomas
Joined: 25 Aug 2003 Posts: 11 Location: France, Lille
|
Posted: Fri Aug 29, 2003 1:15 pm Post subject: |
|
|
Eric, this should work but I didn't test it "live".
| Code: | static string GetOneTime(string oneTimeInit, string password)
{
System.Text.UTF8Encoding utf8 = new System.Text.UTF8Encoding();
System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
return Convert.ToBase64String(md5.ComputeHash(utf8.GetBytes(oneTimeInit+":"+password)));
} |
Jeremy for hash table the hash code you provide can be the hash key for us (the client side) and then can be easier for you.
Rémi |
|
| Back to top |
|
 |
Jeremy Howard The "e" in e-mail
Joined: 09 Apr 2002 Posts: 325 Location: Melbourne
|
Posted: Fri Aug 29, 2003 4:23 pm Post subject: |
|
|
| rthomas wrote: | | Eric, this should work but I didn't test it "live". | We won't be hearing from Eric until next week I think... Let me know if you try this over the weekend.
| Quote: | | Jeremy for hash table the hash code you provide can be the hash key for us (the client side) and then can be easier for you. | Sorry, don't follow you. I'm talking up data structures that map from a key to a value, called 'dictionary', 'map', 'hashtable', etc in various languages. You know what I mean? |
|
| Back to top |
|
 |
Jeremy Howard The "e" in e-mail
Joined: 09 Apr 2002 Posts: 325 Location: Melbourne
|
Posted: Mon Sep 01, 2003 2:44 am Post subject: |
|
|
| Eric, can you show me the complete code to build your example with the .Net SDK, not with VS.Net? I assume there's some other code to link the class to the WSDL file? |
|
| Back to top |
|
 |
Jeremy Howard The "e" in e-mail
Joined: 09 Apr 2002 Posts: 325 Location: Melbourne
|
|
| Back to top |
|
 |
robmueller
Joined: 01 Sep 2003 Posts: 1
|
Posted: Mon Sep 01, 2003 4:54 am Post subject: GetFolderList... |
|
|
Currently with the GetFolderList() call, it returns a bunch of folder info, including folder names something like this:
| Code: |
<Folder>
<Name>inbox</Name>
<Unread>10</Unread>
</Folder>
<Folder>
<Name>inbox.blah</Name>
<Unread>5</Unread>
</Folder>
<Folder>
<Name>inbox.whatever</Name>
<Unread>3</Unread>
</Folder>
<Folder>
<Name>inbox.whatever.sub</Name>
<Unread>1</Unread>
</Folder>
|
I'm not sure that making it a flat 'array' sort of thing, with the folder name showing the hierarchy nature is the best idea, namely because it assumes that '.' is the path separator, and why get a flat list for something that really is a hierarchy.
Would it be better to return something like:
| Code: |
<Folder>
<Name>inbox</Name>
<Unread>10</Unread>
<SubFolders>
<Folder>
<Name>blah</Name>
<Unread>5</Unread>
</Folder>
<Folder>
<Name>whatever</Name>
<Unread>3</Unread>
<SubFolders>
<Folder>
<Name>sub</Name>
<Unread>1</Unread>
</Folder>
</SubFolders>
</Folder>
</SubFolders
</Folder>
|
???
Rob |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|