Table of Contents


 


Before beginning


Why to code in native language for EWS


Why to NOT use native language for EWS


The setup used

For the example below, I used Visual Studio Express 2010 SP1 under Windows.


What you will need

 A lot of other options exist for the NTLM library and to handle SSL (like libcurl or WinHTTP)

Exchange answer in XML, so you can use xmllite, minixml or just decode the XML manually, it's your choice.


What to do

#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include "ntlm.h" 

struct hostent *hp;
struct sockaddr_in addr;
WORD wVersionRequested = MAKEWORD(2,2);
int sock;
WSADATA wsaData;

           
WSAStartup(wVersionRequested, &wsaData);

if
(!(hp=gethostbyname("server_host")))
    return 0;
memset(&addr,0,
sizeof(addr));
addr.sin_addr=*(
structWORD wVersionRequested = MAKEWORD(2,2);
int sock;
WSADATA wsaData;

           
WSAStartup(wVersionRequested, &wsaData);

if
(!(hp=gethostbyname("server_host")))
in_addr*)
hp->h_addr_list[0];
addr.sin_family=AF_INET;
addr.sin_port=htons(443);
if((sock=socket(AF_INET,SOCK_STREAM, IPPROTO_TCP))<0)
   return 0;
if(connect(sock,(struct sockaddr *)&addr, sizeof(addr))<0)
   return 0;
return 1;

SSL_set_bio(ssl,sbio,sbio);
SSL_connect(ssl);

SSL_write(ssl,"GET /EWS/Services.wsdl HTTP/1.1\r\nUser-Agent: test\r\nHost: serverhost:443\r\n\r\n",strlen("GET /EWS/Services.wsdl HTTP/1.1\r\nUser-Agent: test\r\nHost: serverhost:443\r\n\r\n"));

Check the answer for "WWW-Authenticate: NTLM". If it's not there, be sure it's enabled on your IIS of your Exchange Server with the CAS role.

 

string encoded, encodedpass, decoded, sBuffer;

char cRequest[1024];
char cBuffer[1024];
tSmbNtlmAuthRequest request;
tSmbNtlmAuthResponse response;

ZeroMemory(cRequest, 1024);
buildSmbNtlmAuthRequest (&request, "username", "domain");
if (SmbLength(&request) > 1024)
    
return 0;
encoded = enc.Base64enc((
unsigned char *) &request, SmbLength(&request));
_snprintf(cRequest, 1024,
"GET /EWS/Services.wsdl HTTP/1.1\r\nHost: serverhost\r\nConnection: Keep-Alive\r\nAuthorization: NTLM %s\r\n\r\n", encoded.c_str());
SSL_write(ssl, cRequest);

// read the answer, sBuffer = NTLM answer

decoded = enc.Base64dec(sBuffer);
buildSmbNtlmAuthResponse((tSmbNtlmAuthChallenge *)decoded.c_str(), &response, "username", "password");
encodedpass = enc.Base64enc((unsigned char *) &response, SmbLength(&response));
_snprintf(cRequest, 1024,
"GET /EWS/Services.wsdl HTTP/1.1\r\nHost: servername\r\nConnection: Keep-Alive\r\nAuthorization: NTLM %s\r\n\r\n", encodedpass.c_str());
SSL_write(ssl, cRequest);

// If IIS answer with 200 then your password was ok !

Like to receive a distribution group member's list:

char cRequest[1024];
char request[1024] =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
"<soap:Envelope xmlns:soap=\http://schemas.xmlsoap.org/soap/envelope//
" xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">"
" <soap:Body>"
" <ExpandDL xmlns=\http://schemas.microsoft.com/exchange/services/2006/messages/
" xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">"
" <Mailbox xmlns=\"http://schemas.microsoft.com/exchange/services/2006/messages\">"
" <EmailAddress xmlns=\"http://schemas.microsoft.com/exchange/services/2006/types\">test@constoco.com</EmailAddress>"
" </Mailbox>"
" </ExpandDL>"
" </soap:Body>"
"</soap:Envelope>";

ZeroMemory(cRequest, 1024);
_snprintf(cRequest, 1024, "POST /ews/Exchange.asmx HTTP/1.1\r\n"
"Host: servername\r\n"
"Content-Length: %d\r\n"
"Content-Type: text/xml\r\n\r\n%s", strlen(request), request);

 // send it and decode the answer...


 


Reference

Quick and Dirty UNIX Shell Scripting with EWS - The idea that started it all for me was there.
EWSEditor - To generate some SOAP message easily.
Exchange Web Services (EWS) - MSDN referance with a lot of examples.
theForger's Win32 API Programming Tutorial - A really good tutorial for direct API programming.

Other Languages

This article is also available the following languages: