none
[E2007][EWS - AutoGen][C++][Windows 7] - How to access Exchange mailbox and extract attachments RRS feed

  • Question

  • I have a C++ program that extracts attachments from mails received by a specific mail account and decodes the attachments with a C++ API. So far, the program has just been running on my local PC, handling the mail access through Outlook/COM, by #import MSO.DLL etc. But now the program needs to be moved to a server, why it needs to be updated to 'direct' access to the Exchange Server without using an Outlook instance.

    I have generated an interface with svcutil and wsutil and managed to execute a successfull ExchangeServiceBinding_FindItem() call. But now I have been stuck for too long trying to figure out where and how to dig the mails and their attachments out from the returned FindItemResponseType struct.  

    I believe the code below should enable access to my own Inbox for a start. The processWS_FIELD_DESCRIPTION() simply prints the content of the structs to a console but I have not been able to find a hint on how to locate the mails from the inbox in the struct. An neither how to access the mail account the program need to monitor in the end...

    Any help that can get me closer to the solution is much appreciated.

      WS_CHANNEL_PROPERTY channelProperties[2];
      ULONG nChannelPropertyCount = 0;
    
      WS_ENVELOPE_VERSION soapVersion = WS_ENVELOPE_VERSION_SOAP_1_1;
      channelProperties[nChannelPropertyCount].id = WS_CHANNEL_PROPERTY_ENVELOPE_VERSION;
      channelProperties[nChannelPropertyCount].value = &soapVersion;
      channelProperties[nChannelPropertyCount].valueSize = sizeof(soapVersion);
      ++nChannelPropertyCount;
    
      WS_ADDRESSING_VERSION addressingVersion = WS_ADDRESSING_VERSION_TRANSPORT;
      channelProperties[nChannelPropertyCount].id = WS_CHANNEL_PROPERTY_ADDRESSING_VERSION;
      channelProperties[nChannelPropertyCount].value = &addressingVersion ;
      channelProperties[nChannelPropertyCount].valueSize = sizeof(addressingVersion );
      ++nChannelPropertyCount;
    
      WS_STRING url = WS_STRING_VALUE(L"https://[Our Exchange Server]/ews/Exchange.asmx");
      DWORD dwWS_HTTP_HEADER_AUTH_SCHEME = WS_HTTP_HEADER_AUTH_SCHEME_NEGOTIATE;
      WS_DEFAULT_WINDOWS_INTEGRATED_AUTH_CREDENTIAL intAuthCredential = {}; 
      intAuthCredential.credential.credentialType = WS_DEFAULT_WINDOWS_INTEGRATED_AUTH_CREDENTIAL_TYPE;
    
      WS_SECURITY_BINDING_PROPERTY rgSecBindingProp[1];
      rgSecBindingProp[0].id = WS_SECURITY_BINDING_PROPERTY_HTTP_HEADER_AUTH_SCHEME;
      rgSecBindingProp[0].valueSize = sizeof(DWORD);
      rgSecBindingProp[0].value = (void*)&dwWS_HTTP_HEADER_AUTH_SCHEME;
       
      WS_HTTP_HEADER_AUTH_SECURITY_BINDING  authBinding = {};
      authBinding.binding.bindingType = WS_HTTP_HEADER_AUTH_SECURITY_BINDING_TYPE;
      authBinding.binding.properties = rgSecBindingProp;
      authBinding.binding.propertyCount = WsCountOf(rgSecBindingProp); 
      authBinding.clientCredential =&intAuthCredential.credential;
    
      // Ignore ssl error related to certificate validation
      DWORD dwIgnoreCnSertValue = WS_CERT_FAILURE_CN_MISMATCH;
      WS_SECURITY_BINDING_PROPERTY rgSslProp[1];
      rgSslProp[0].id = WS_SECURITY_BINDING_PROPERTY_CERT_FAILURES_TO_IGNORE;
      rgSslProp[0].valueSize = sizeof(DWORD);
      rgSslProp[0].value = (void*)&dwIgnoreCnSertValue;
    
      // Declare and initialize an SSL transport security binding
      WS_SSL_TRANSPORT_SECURITY_BINDING sslBinding = {};
      sslBinding.binding.bindingType = WS_SSL_TRANSPORT_SECURITY_BINDING_TYPE;
      sslBinding.binding.properties = rgSslProp;
      sslBinding.binding.propertyCount = WsCountOf(rgSslProp); 
    
      // Declare and initialize the array of all security bindings
      WS_SECURITY_BINDING* securityBindings[2] = { &sslBinding.binding, &authBinding.binding };
    
      // Declare and initialize the security description
      WS_SECURITY_DESCRIPTION securityDescription = {}; // zero out the struct
      securityDescription.securityBindings = securityBindings;
      securityDescription.securityBindingCount = WsCountOf(securityBindings);
      securityDescription.properties = NULL;
      securityDescription.propertyCount = 0;
          
      WS_ENDPOINT_ADDRESS address = {}; 
      address.url=url; 
      
      WS_ERROR* pError = NULL;
      if (SUCCEEDED(WsCreateError(NULL, 0, &pError))) // Error object
      {
        WS_HEAP* pHeap = NULL; // Create a heap to store deserialized data
        if (SUCCEEDED(WsCreateHeap( 8*65536, 128 , NULL, 0, &pHeap, pError)))
        {
          WS_SERVICE_PROXY* pProxy = NULL; // Create the proxy
          if (SUCCEEDED(WsCreateServiceProxy(WS_CHANNEL_TYPE_REQUEST, WS_HTTP_CHANNEL_BINDING,
                                             &securityDescription,NULL, 0, channelProperties,
                                             nChannelPropertyCount, &pProxy, pError)))
          {
            if (SUCCEEDED(WsOpenServiceProxy(pProxy, &address, NULL, pError))) 
            { 
              // Below interface generated as follows:
              // (svcutil and wsutil executed in local project path from "Developer Command Prompt for VS2012")
              // 1. svcutil.exe /t:metadata https://[Our Exchange Server]/ews/Exchange.asmx
              //    Downloads the following 3 files
              //    schemas.microsoft.com.exchange.services.2006.types.xsd
              //    schemas.microsoft.com.exchange.services.2006.messages.xsd
              //    schemas.microsoft.com.exchange.services.2006.messages.wsdl
              // 2. wsutil /xsd:schemas.microsoft.com.exchange.services.2006.messages.xsd /xsd:schemas.microsoft.com.exchange.services.2006.types.xsd /wsdl:schemas.microsoft.com.exchange.services.2006.messages.wsdl
              // 3. Renamed extentions of generated source files from .c to .cpp
              // 4. Added #include "stdafx.h" to top of .cpp files 
              // 5. Added the 3 header and the 3 source files to the project
      
              FindItemType findItemReq = {0};
              FindItemType_Init(&findItemReq);
              findItemReq.Traversal = ItemQueryTraversalTypeShallow; 
    
              findItemReq._choice.choice = _FindItemTypeChoice_none;
              findItemReq._choice0.choice = _FindItemTypeChoice_none0;
    
              ItemResponseShapeType responseShape;
              memset(&responseShape, 0, sizeof(responseShape));
              responseShape.BaseShape = DefaultShapeNamesTypeAllProperties;
              responseShape.IncludeMimeContent = FALSE;
              responseShape.BodyType = BodyTypeResponseTypeText;
              responseShape.FilterHtmlContent = FALSE;
              responseShape.ConvertHtmlCodePageToUTF8 = FALSE;
              findItemReq.ItemShape = &responseShape;
    
              DistinguishedFolderIdType inbox = {0};
              DistinguishedFolderIdType_Init(&inbox);
              inbox.Id = DistinguishedFolderIdNameTypeinbox;
    
              _NonEmptyArrayOfBaseFolderIdsType_Choice _nonEmptyArrayOfBaseFolderIdsType_Choice[1];
              _nonEmptyArrayOfBaseFolderIdsType_Choice[0].choice = _NonEmptyArrayOfBaseFolderIdsType_Choice_DistinguishedFolderId;
              _nonEmptyArrayOfBaseFolderIdsType_Choice[0].u.DistinguishedFolderId = &inbox;
    
              findItemReq.ParentFolderIds = _nonEmptyArrayOfBaseFolderIdsType_Choice;
              findItemReq.ParentFolderIdsCount = WsCountOf(_nonEmptyArrayOfBaseFolderIdsType_Choice);
    
              FindItemResponseType *pfr;
              if (SUCCEEDED(ExchangeServiceBinding_FindItem(pProxy, &findItemReq, &pfr, pHeap, NULL, 0, NULL, pError)))
              {
                if(pfr->_base.ResponseMessages[0].u.FindItemResponseMessage->_base.ResponseClass == ResponseClassTypeError)
                  wprintf(L"FindItemResponseType - Error\n");
                else if(pfr->_base.ResponseMessages[0].u.FindItemResponseMessage->_base.ResponseClass == ResponseClassTypeWarning)
                  wprintf(L"FindItemResponseType - Warning\n");
                else
                {
                  for(unsigned int i = 0; i < pfr->_base._type->fieldCount; ++i)
                    processWS_FIELD_DESCRIPTION(pfr->_base._type->fields[i], 0);
                  for(unsigned int j = 0; j < pfr->_base.ResponseMessagesCount; ++j)
                    for(unsigned int k = 0; k < pfr->_base.ResponseMessages[j].u.FindItemResponseMessage->_base._type->fieldCount; ++k)
                      processWS_FIELD_DESCRIPTION(pfr->_base.ResponseMessages[j].u.FindItemResponseMessage->_base._type->fields[k], 0);
                }
              } // if (SUCCEEDED(ExchangeServiceBinding_Find...
              else
              {
                WS_STRING errMsg;
                ULONG n=0;
                while (SUCCEEDED(WsGetErrorString(pError,n,&errMsg)))
                {
                  wprintf(L"Error message = %.*s\n", errMsg.length, errMsg.chars);
                  ++n;
                }
              }
              WsCloseServiceProxy(pProxy,NULL, pError);
            } // if (SUCCEEDED(WsOpenServiceProxy() 
            WsFreeServiceProxy(pProxy); 
          } //if (SUCCEEDED(WsCreateServiceProxy()
          WsFreeHeap(pHeap); 
        } // if (SUCCEEDED(WsCreateHeap()
        WsFreeError(pError); 
      } // if (SUCCEEDED(WsCreateError()
    
    Sunday, October 27, 2013 10:36 PM