home *** CD-ROM | disk | FTP | other *** search
- //////////////////////////////////////////////////////////////////////////////
- //
- // File Name
- // XPLOGON.CPP
- //
- // Description
- // This file implements the IXPLogon interface with the methods specified
- // in the MAPI SPI 1.0.
- //
- // Authors
- // Irving De la Cruz
- // Les Thaler
- //
- // Revision: 1.7
- //
- // Written for Microsoft Windows Developer Support
- // Copyright (c) 1995-1996 Microsoft Corporation. All rights reserved.
- //
- //
- #include "XPWDSR.H"
-
- #define DO_INFO_TRACES
- #ifdef DO_INFO_TRACES
- #define InfoTrace(a) TraceInfoMessage(a)
- #else
- #define InfoTrace(a)
- #endif // DO_INFO_TRACES
-
- // Remark this line to turn verbose tracing OFF
- MAPIUID guidABEntries = AB_UID_PROVIDER;
- MAPIUID guidXPABEntries = XP_WINDS_AB_ENTRIES;
- MAPIUID * puidWINDSEntries;
- TCHAR gszProviderName[] = TEXT("WINDS Transport Service");
- LPTSTR gszWINDSAddressType = WINDS_ADDRESS_TYPE;
- LPTSTR * gpszXPAddressTypes;
-
- void CALLBACK UploadTimerProc (HWND hOwnerWnd,
- UINT Message,
- UINT idEvent,
- DWORD dwTime);
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::CXPLogon()
- //
- // Parameters
- // hInstance Instance of the provider DLL
- // pSupObj Pointer to IMAPISupport object used in
- // CXPLogon methods
- // pszHeadersFile Full file path where the remote headers are
- // store in the local computer.
- // fGetHeaders Weather or not to get the headers of the
- // mailbox during a scheduled connection.
- // pUserMailboxInfo Pointer to a MAILBOX_INFO structure with the
- // information of the logged user as store in
- // the WINDS server.
- // dwMailboxID ID of the user in the WINDS system.
- // pszRemoteServer Name of the remote WINDS server to which
- // this transport communicates
- // hUIMutex Handle to a WINDS mutex to allow single access
- // to the UI configuration of this provider.
- //
- // Purpose
- // Constructor of the object. Parameters are passed to initialize the
- // data members with the appropiate values.
- //
- // Return Value
- // None
- //
- CXPLogon::CXPLogon (HINSTANCE hInstance,
- LPMAPISUP pSupObj,
- LPTSTR pszHeadersFile,
- BOOL fGetHeaders,
- PMAILBOX_INFO pUserMailboxInfo,
- DWORD dwMailboxID,
- LPTSTR pszRemoteServer,
- HANDLE hUIMutex)
- {
- InfoTrace ("CXPLogon: Constructor called");
- m_cRef = 1;
- m_pIdentityProps = NULL;
- m_hInstance = hInstance;
- m_pSupObj = pSupObj;
- m_pStatusObj = NULL;
- m_pIdentityProps = NULL;
- ZeroMemory (&m_stDelivTime, sizeof(SYSTEMTIME));
- m_uTimerID = 0;
- m_hTimerWnd = NULL;
- m_fABWDSInstalled = FALSE;
- m_fGetHeaders = fGetHeaders;
- m_hUIMutex = hUIMutex;
- m_raAction = REMOTE_ACTION_IDLE;
- m_UserInfo = *pUserMailboxInfo;
- ZeroMemory (&m_UserEID, CB_PRIVATE_EID);
- m_UserEID.uidGlobal = guidABEntries;
- m_UserEID.bVersion = ENTRYID_VERSION;
- m_UserEID.bObject = MAPI_MAILUSER;
- m_UserEID.dwObjID = dwMailboxID;
-
- m_pSupObj->AddRef();
-
- lstrcpy (m_szHeaders, pszHeadersFile);
- lstrcpy (m_szServer, pszRemoteServer);
-
- wsprintf (m_szAddress, TEXT("%s\\%s"), m_szServer, m_UserInfo.szMailboxName);
-
- // Initialize the messages download list object
- m_List.SetLogon(this);
- if (!m_List.Init())
- {
- throw CException (E_OUTOFMEMORY);
- }
- SetTransportState (WAITING);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::~CXPLogon()
- //
- // Parameters
- // None
- //
- // Purpose
- // Destructor of CXPLogon. Releases memory allocated for internal
- // properties during the life of this transport logon object.
- //
- // Return Value
- // None
- //
- CXPLogon::~CXPLogon()
- {
- InfoTrace ("CXPLogon: Destructor called");
- gpfnFreeBuffer (m_pIdentityProps);
- CloseHandle (m_hUIMutex);
-
- EmptyInboundQueue();
-
- // Delete CMAPIStatus Object
- /* if (m_pStatusObj)
- {
- m_pStatusObj->Release();
- m_pStatusObj = NULL;
- }
- */
- // Release the IMAPISupport object
- m_pSupObj->Release();
- m_pSupObj = NULL;
-
- // Just as a safety precaution, make sure the timer is off.
- StopUploadTimer();
-
- // Just in case the DLL is still hanging around
- PrivUninitialize3DCtl (m_hInstance);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::QueryInterface()
- //
- // Parameters
- // { Refer to OLE Documentation on this method }
- //
- // Purpose
- // Returns a pointer to a interface requested if the interface is
- // supported and implemented by this object. If it is not supported, it
- // returns NULL
- //
- // Return Value
- // An HRESULT
- //
- STDMETHODIMP CXPLogon::QueryInterface (REFIID riid, LPVOID * ppvObj)
- {
- // OLE requires NULLing parameter
- *ppvObj = NULL;
- // If this is one of the two IID return an interface pointer to it
- if (riid == IID_IXPLogon || riid == IID_IUnknown)
- {
- *ppvObj = (LPVOID)this;
- // Increase usage count of this object
- AddRef();
- return S_OK;
- }
- // This object does not support the interface requested
- return E_NOINTERFACE;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // IXPLogon virtual member functions implementation
- //
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::AddressType()
- //
- // Parameters
- // { Refer to MAPI Documentation on this method }
- //
- // Purpose
- // Called by the MAPI Spooler when initializing this XP logon object to
- // allow the transport to register the address it will handle
- //
- // Return Value
- // S_OK always
- //
- STDMETHODIMP CXPLogon::AddressTypes (ULONG * pulFlags,
- ULONG * pcAdrType,
- LPTSTR ** pppAdrTypeArray,
- ULONG * pcMAPIUID,
- LPMAPIUID ** pppMAPIUIDArray)
- {
- InfoTrace ("CXPLogon::AddressTypes method called");
- CheckParameters_IXPLogon_AddressTypes (this,
- pulFlags,
- pcAdrType,
- pppAdrTypeArray,
- pcMAPIUID,
- pppMAPIUIDArray);
-
- // This is how many address type strings we are returning in pppAdrTypeArray
- *pcAdrType = 1;
-
- // Copy address types back to the MAPI pointer
- gpszXPAddressTypes = &gszWINDSAddressType;
- *pppAdrTypeArray = gpszXPAddressTypes;
- *pulFlags = fMapiUnicode;
-
- // The UID for routing message has to be set here. If it is not used, set it NULL.
- // In the case of WINDS transport registers support for the UID of
- // the WINDS address book's entry ID
- puidWINDSEntries = &guidABEntries;
- *pcMAPIUID = 1;
- *pppMAPIUIDArray = &puidWINDSEntries;
- return S_OK;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::RegisterOptions()
- //
- // Parameters
- // { Refer to MAPI Documentation on this method }
- //
- // Purpose
- // This transport does not registers any per-recipient or per-message
- // option processing, so we return 0 options. And NULL in the OPTIONDATA
- // structure pointer.
- //
- // Return Value
- // An HRESULT
- //
- STDMETHODIMP CXPLogon::RegisterOptions (ULONG * pulFlags,
- ULONG * pcOptions,
- LPOPTIONDATA * ppOptions)
- {
- InfoTrace ("CXPLogon::RegisterOptions method called");
- CheckParameters_IXPLogon_RegisterOptions (this,
- pulFlags,
- pcOptions,
- ppOptions);
- *pulFlags = 0;
- *pcOptions = 0;
- *ppOptions = NULL;
- return S_OK;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::TransportNotify()
- //
- // Parameters
- // { Refer to MAPI Documentation on this method }
- //
- // Purpose
- // Update the status row registered by this transport with MAPI
- //
- // Return Value
- // An HRESULT
- //
- STDMETHODIMP CXPLogon::TransportNotify (ULONG * pulFlags, LPVOID * ppvData)
- {
- InfoTrace ("CXPLogon::TransportNotify method called");
- CheckParameters_IXPLogon_TransportNotify (this,
- pulFlags,
- ppvData);
-
- ULONG ulOldStatus = GetTransportStatusCode();
- // Set appropriate status flags and re-register status row
- if (*pulFlags & NOTIFY_BEGIN_INBOUND)
- {
- InfoTrace ("CXPLogon::TransportNotify: Begin INBOUND logic");
- AddStatusBits (STATUS_INBOUND_ENABLED);
- }
- if (*pulFlags & NOTIFY_END_INBOUND)
- {
- InfoTrace ("CXPLogon::TransportNotify: Terminate INBOUND logic");
- RemoveStatusBits (STATUS_INBOUND_ENABLED);
- }
- if (*pulFlags & NOTIFY_BEGIN_OUTBOUND)
- {
- InfoTrace ("CXPLogon::TransportNotify: Begin OUTBOUND logic");
- AddStatusBits (STATUS_OUTBOUND_ENABLED);
- InitializeTimer();
- StartUploadTimer();
- }
- if (*pulFlags & NOTIFY_END_OUTBOUND)
- {
- InfoTrace ("CXPLogon::TransportNotify: Terminate OUTBOUND logic");
- RemoveStatusBits (STATUS_OUTBOUND_ENABLED);
- StopUploadTimer();
- }
- if (*pulFlags & NOTIFY_BEGIN_OUTBOUND_FLUSH)
- {
- InfoTrace ("CXPLogon::TransportNotify: Begin OUTBOUND flush");
- // If the spooler need to flush us for some reason, we put ourselves
- // in FLUSH and tell the spooler to give us any deferred messages
- // it has queued up for us.
- AddStatusBits (UPLOADING_MESSAGES); // Add these bits to the status code
- SetTransportState (READY);
- m_pSupObj->SpoolerNotify (NOTIFY_SENTDEFERRED, NULL);
- }
- if (*pulFlags & NOTIFY_END_INBOUND_FLUSH)
- {
- InfoTrace ("CXPLogon::TransportNotify: Terminate INBOUND flush");
- if (FALSE == m_List.AreTherePendingDownloads())
- {
- RemoveStatusBits (DOWNLOADING_MESSAGES); // Tell the spooler to take us off from inbound flush
- AddStatusBits (STATUS_OFFLINE); // The transport is now OFF line
- UpdateStatus (TRUE, TRUE);
- }
- }
- if (*pulFlags & NOTIFY_END_OUTBOUND_FLUSH)
- {
- InfoTrace ("CXPLogon::TransportNotify: Terminate OUTBOUND flush");
- if (GetTransportStatusCode() & UPLOADING_MESSAGES)
- {
- // When the spooler finished sending messages to our CXPLogon::SubmitMessage
- // method, he will call us to let us know there is nothing else we need to
- // flush, and we need to reset our status row.
- RemoveStatusBits (UPLOADING_MESSAGES); // Tell the spooler to take us off from outbound flush
- AddStatusBits (STATUS_OFFLINE); // The transport is now OFF line
- if (PENDING_RETURN_CODE != GetTransportState())
- {
- SetTransportState (WAITING);
- }
- }
- }
-
- // We get called here if user deletes/modifies queued msg in Outbox.
- // If the user modifies and resends it, we get called again at SubmitMessage.
- // If the user closes the message viewer or just saves it, it's removed
- // from the spooler queue and discarded.
- if (*pulFlags & NOTIFY_ABORT_DEFERRED)
- {
- InfoTrace ("CXPLogon::TransportNotify: Abort deferred message");
- }
- if (*pulFlags & NOTIFY_CANCEL_MESSAGE)
- {
- InfoTrace ("CXPLogon::TransportNotify: Cancel message");
- }
- if (ulOldStatus != GetTransportStatusCode())
- {
- UpdateStatus();
- }
- if (*pulFlags & NOTIFY_BEGIN_INBOUND)
- {
- // If we have pending message from a previous session, notify the
- // spooler that we are ready to give them to the store.
- if (m_List.AreTherePendingDownloads())
- {
- // Put ourselves into flush mode and have the spooler call us until
- // we are finished putting the downloaded messages into the default store.
- AddStatusBits (DOWNLOADING_MESSAGES); // Add these bits to the status code
- UpdateStatus();
- }
- }
- return S_OK;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::Idle()
- //
- // Parameters
- // { Refer to MAPI Documentation on this method }
- //
- // Purpose
- // Stub method. We should not get called here, because we told
- // the spooler not to call us here.
- //
- // Return Value
- // S_OK always.
- //
- STDMETHODIMP CXPLogon::Idle (ULONG ulFlags)
- {
- InfoTrace ("CXPLogon::Idle method called");
- CheckParameters_IXPLogon_Idle (this, ulFlags);
- return S_OK;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::TransportLogoff()
- //
- // Parameters
- // ulFlags Priority with which the transport should log off
- //
- // Purpose
- // This method is called by the spooler when the transport should do final
- // arragements before it gets released.
- //
- // Return Value
- // An HRESULT
- //
- STDMETHODIMP CXPLogon::TransportLogoff (ULONG ulFlags)
- {
- InfoTrace ("CXPLogon::TransportLogoff method called");
- CheckParameters_IXPLogon_TransportLogoff (this, ulFlags);
- StopUploadTimer();
-
- EmptyInboundQueue();
-
- // We should attempt to remove the transport's status row from
- // the system, but if we fail we won't fail the call.
- HRESULT hResult = m_pSupObj->ModifyStatusRow (0, NULL, 0);
- TraceResult ("CXPLogon::TransportLogoff: Failed to remove status row", hResult);
-
- if (m_pStatusObj)
- {
- m_pStatusObj->Release();
- m_pStatusObj = NULL;
- }
-
- return S_OK;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::SubmitMessage()
- //
- // Parameters
- // { Refer to MAPI Documentation on this method }
- //
- // Purpose
- // This method is called by the spooler when a client submits a
- // message to a recipient whose address type this transport handles.
- // The spooler calls this method twice for each deferred message.
- // The first time (before the delivery time) when the message is
- // submitted by the client, we simply return. The message is then queued
- // by the spooler for later delivery. We keep track of when it's time
- // to send deferred messages.
- //
- // The second time we're called, the state variable will be 'READY' and
- // we go ahead and start the actual transmission. While we're in the
- // body of this function, the implied state is 'SENDING'
- //
- // If the client logs out of this session, any pending messages get
- // queued again the next time it logs in.
- //
- // In this transport we get a recipient table, we restrict the table for
- // unmarked recipients. After the table is ready we invoke a helper
- // method to do the actual transmission.
- //
- // Return Value
- // An HRESULT
- //
- STDMETHODIMP CXPLogon::SubmitMessage (ULONG ulFlags,
- LPMESSAGE pMsgObj,
- ULONG * pulMsgRef,
- ULONG * pulReturnParm)
- {
- InfoTrace ("CXPLogon::SubmitMessage method called");
- CheckParameters_IXPLogon_SubmitMessage (this,
- ulFlags,
- pMsgObj,
- pulMsgRef,
- pulReturnParm);
-
- #ifdef _DEBUG
- // Before we get called in SubmitMessage or StartMessage, the spooler should have called
- // us in TransportNotify() to let us know which logic (IN, OUT, BOTH) of the
- // transporting mechanism should be activated for this IXPLogon session.
- if (!(GetTransportStatusCode() & STATUS_OUTBOUND_ENABLED))
- {
- TraceMessage ("CXPLogon::SubmitMessage: We can't send a message if the outbound is not enabled");
- ASSERTMSG (FALSE, "We can't submit a message if we have not started OUTBOUND logic");
- return MAPI_E_NOT_ME;
- }
- #endif // _DEBUG
-
- // Lock the object against the timer thread re-entrancy. Timer events are handle
- // in a separate thread. This section will get unlocked in the CPXLogon::EndMessage() call
- if (WAITING == GetTransportState())
- {
- // Not scheduled upload time, return and let IXPLogon::EndMessage() defer the message
- InfoTrace ("CXPLogon::SubmitMessage: Deferring message for scheduled submission");
- return S_OK;
- }
- InfoTrace ("CXPLogon::SubmitMessage: Processing deferred message");
-
- CheckSpoolerYield (TRUE);
-
- // Notify the MAPI spooler the transport is going to flush any queued up messages and submit them.
- // Transport to used shared resources, such as COM ports, should put them selves into flush mode
- // when submitting a batch of messages. This gives the transport the advantage of locking shared
- // resources across submitted messages and ensures that the spooler does not call other
- // transports while another is flushing because it could have something locked.
- // This transport does not uses any shared resources that we would need to lock, but for the
- // purposes of demonstration, we put our selves into flush mode until the MAPI spooler
- // tells us to step down.
- if (!(GetTransportStatusCode() & UPLOADING_MESSAGES))
- {
- AddStatusBits (UPLOADING_MESSAGES);
- UpdateStatus();
- }
-
- // Get the recipient table from the message
- LPMAPITABLE pTable = NULL;
- HRESULT hResult = pMsgObj->GetRecipientTable (fMapiUnicode, &pTable);
- if (hResult)
- {
- TraceResult ("CXPLogon::SubmitMessage: Failed to get the recipient table", hResult);
- goto ErrorExit;
- }
-
- // The spooler marks all the message recipients this transport has to
- // handle with PR_RESPONSIBILITY set to FALSE
- SPropValue spvRecipUnsent;
- spvRecipUnsent.ulPropTag = PR_RESPONSIBILITY;
- spvRecipUnsent.Value.b = FALSE;
-
- SRestriction srRecipientUnhandled;
- srRecipientUnhandled.rt = RES_PROPERTY;
- srRecipientUnhandled.res.resProperty.relop = RELOP_EQ;
- srRecipientUnhandled.res.resProperty.ulPropTag = PR_RESPONSIBILITY;
- srRecipientUnhandled.res.resProperty.lpProp = &spvRecipUnsent;
-
- hResult = pTable->Restrict (&srRecipientUnhandled, 0L);
- if (hResult)
- {
- TraceResult ("CXPLogon::SubmitMessage: Failed to restrict the recipient table", hResult);
- goto ErrorExit;
- }
-
- // Let the MAPI spooler do other things
- CheckSpoolerYield();
-
- hResult = HrAddColumns (pTable,
- (LPSPropTagArray)&sptRecipTable,
- gpfnAllocateBuffer,
- gpfnFreeBuffer);
- if (hResult)
- {
- TraceResult ("CXPLogon::SubmitMessage: Failed to expand the columns in the recipient table", hResult);
- goto ErrorExit;
- }
-
- LPSRowSet pRecipRows;
- hResult = HrQueryAllRows (pTable,
- NULL,
- NULL,
- NULL,
- 0,
- &pRecipRows);
- if (!hResult)
- {
- // Let the MAPI spooler do other things
- CheckSpoolerYield();
- // Send to the recipients which we can reach, and generate NDR's for the ones we can't
- hResult = SendMailMessage (pMsgObj, pRecipRows);
- FreeProws (pRecipRows);
- if (!hResult)
- {
- // Now we need to save changes on the message and close it.
- // After this, the message object can't be used.
- hResult = pMsgObj->SaveChanges (0);
- TraceResult ("CXPLogon::SubmitMessage: Failed to save the message object", hResult);
- }
- }
-
- ErrorExit:
- // Release the table, we're finished with it
- if (pTable)
- {
- pTable->Release();
- }
-
- // Release the spooler's message if needed to
- if (pMsgObj)
- {
- pMsgObj->Release ();
- }
-
- // In case there is a warning or error floating around, don't let it escape to the spooler.
- if (FAILED(hResult))
- {
- // We default to MAPI_E_NOT_ME so that the spooler would attempt handle
- // the message to other transport (currently running in this profile)
- // that handle the same address type as ours.
- TraceMessage ("CXPLogon::SubmitMessage: An error occurred in the submission, returning MAPI_E_NOT_ME");
- hResult = MAPI_E_NOT_ME;
- }
- else
- {
- hResult = S_OK;
- }
- return hResult;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::EndMessage()
- //
- // Parameters
- // { Refer to MAPI Documentation on this method }
- //
- // Purpose
- // This method is called by the spooler for each message we're to
- // deliver. It's the mate to SubmitMessage. We're called here twice
- // for each deferred message and once for non-deferred (realtime)
- // messages.
- //
- // We first check the transport state, and if we're
- // WAITING for the scheduled delivery time to arrive, we return
- // END_DONT_RESEND in *pulFlags, which tells the spooler to queue this
- // message for deferred delivery.
- //
- // If the state is SENDING, we're getting called here after
- // a message has been dequeued and delivered. Return 0 in *pulFlags
- // to tell the spooler the message has been delivered.
- //
- // Return Value
- // An HRESULT
- //
- STDMETHODIMP CXPLogon::EndMessage (ULONG ulMsgRef, ULONG * pulFlags)
- {
- InfoTrace ("CXPLogon::EndMessage method called");
- CheckParameters_IXPLogon_EndMessage (this, ulMsgRef, pulFlags);
-
- if (WAITING == GetTransportState())
- {
- // Tell spooler to queue msg for deferred delivery
- *pulFlags = END_DONT_RESEND;
- }
- else
- {
- *pulFlags = 0;
- }
- return S_OK;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::Poll()
- //
- // Parameters
- // { Refer to MAPI Documentation on this method }
- //
- // Purpose
- // Stub method. We should not get called here, because we told
- // the spooler not to call us here.
- //
- // Return Value
- // An HRESULT
- //
- STDMETHODIMP CXPLogon::Poll (ULONG * pulIncoming)
- {
- InfoTrace ("CXPLogon::Poll method called");
- CheckParameters_IXPLogon_Poll (this, pulIncoming);
- return S_OK;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::StartMessage()
- //
- // Parameters
- // { Refer to MAPI Documentation on this method }
- //
- // Purpose
- // This method gets called when an incoming message is pending to be
- // processed.
- //
- // Return Value
- // An HRESULT
- //
- STDMETHODIMP CXPLogon::StartMessage (ULONG ulFlags,
- LPMESSAGE pMsgObj,
- ULONG * pulMsgRef)
- {
- InfoTrace ("CXPLogon::StartMessage method called");
- CheckParameters_IXPLogon_StartMessage (this, ulFlags, pMsgObj, pulMsgRef);
-
- // Initialize the pseudo-timer for the SpoolerYield() call
- CheckSpoolerYield (TRUE);
-
- HRESULT hResult = S_OK;
- LPSTREAM pFileStream = NULL;
- CCachedStream * pStream = NULL;
- LPITNEF pTNEFObj = NULL;
- SPropTagArray sptExcludedProps = { 0 };
-
- PLIST_NODE pNode = m_List.GetDownloadNode();
- if (!pNode)
- {
- RemoveStatusBits (DOWNLOADING_MESSAGES); // Remove these bits from the status code
- UpdateStatus();
- if (READY == GetTransportState())
- {
- SetTransportState (WAITING);
- }
- goto ErrorExit;
- }
- // Close the file so that we may open it in the call below
- if (pNode->hFile)
- {
- CloseHandle (pNode->hFile);
- // NULL the handle to avoid closing the file again during cleanup.
- pNode->hFile = NULL;
- }
- // Open the stream where the message properties are.
- hResult = OpenStreamOnFile (gpfnAllocateBuffer,
- gpfnFreeBuffer,
- STGM_READ,
- pNode->szFileName,
- NULL,
- &pFileStream);
- if (hResult)
- {
- TraceResult ("CXPLogon::StartMessage: Failed to open stream on the message file", hResult);
- goto ErrorExit;
- }
- try
- {
- // Create a buffer IStream interface for the TNEF decoding
- pStream = new CCachedStream (pFileStream, XPSOF_READ);
- if (!pStream)
- {
- TraceMessage ("CXPLogon::StartMessage: Failed to allocate cached stream object");
- hResult = E_OUTOFMEMORY;
- }
- }
- catch (CException & Exception)
- {
- hResult = Exception.GetError();
- }
- pFileStream->Release();
- pFileStream = NULL;
- if (hResult)
- {
- goto ErrorExit;
- }
- hResult = OpenTnefStream (m_pSupObj,
- pStream,
- TNEF_FILE_NAME,
- TNEF_DECODE,
- pMsgObj,
- 0, // Not needed when decoding TNEF
- &pTNEFObj);
- if (hResult)
- {
- TraceResult ("CXPLogon::StartMessage: Failed to open TNEF stream object", hResult);
- goto ErrorExit;
- }
-
- // Let the MAPI spooler do other things
- CheckSpoolerYield();
-
- // Get the properties for the message which are encoded in the TNEF
- // message stream. The sptExcludedProps argument, is just a stub,
- // we are not excluding any properties
- LPSTnefProblemArray pProblems;
- pProblems = NULL;
- hResult = pTNEFObj->ExtractProps (TNEF_PROP_EXCLUDE, &sptExcludedProps, &pProblems);
- if (pProblems)
- {
- gpfnFreeBuffer (pProblems);
- pProblems = NULL;
- }
- if (hResult)
- {
- TraceResult ("CXPLogon::StartMessage: Failed to open TNEF stream", hResult);
- goto ErrorExit;
- }
- if (MAPI_E_CORRUPT_DATA == SetIncomingProps (pMsgObj, pNode))
- {
- pNode = NULL; // To avoid deleting it below.
- }
-
- // Save all chages and new properties, back on the message
- // Don't release the message object. The spooler is still using it.
- // After this, the message object can't be used by this transport.
- hResult = pMsgObj->SaveChanges (0);
- TraceResult ("CXPLogon::StartMessage: Failed to save the message object", hResult);
-
- // Let the MAPI spooler do other things
- CheckSpoolerYield();
-
- ErrorExit:
- // Release used objects
- if (pTNEFObj)
- {
- pTNEFObj->Release();
- }
- if (pStream)
- {
- pStream->Release();
- }
- if (pNode)
- {
- if (pNode->hFile)
- {
- CloseHandle (pNode->hFile);
- }
- // Delete the file ONLY if the we were successful putting the
- // file data into the message. Otherwise leave the file in
- // the directory, and it will be picked up later
- if (S_OK == hResult)
- {
- DeleteFile (pNode->szFileName);
- }
- delete pNode;
- }
- m_List.UpdateProgress();
- return hResult;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::OpenStatusEntry()
- //
- // Parameters
- // { Refer to MAPI Documentation on this method }
- //
- // Purpose
- // This method is called to get an IMAPIStatus object for this XPLOGON
- // session.
- //
- // Return Value
- // An HRESULT
- //
- STDMETHODIMP CXPLogon::OpenStatusEntry (LPCIID pInterface,
- ULONG ulFlags,
- ULONG * pulObjType,
- LPMAPISTATUS * ppEntry)
- {
- InfoTrace ("CXPLogon::OpenStatusEntry method called");
- CheckParameters_IXPLogon_OpenStatusEntry (this,
- pInterface,
- ulFlags,
- pulObjType,
- ppEntry);
- if (MAPI_MODIFY & ulFlags)
- {
- TraceMessage ("CXPLogon::OpenStatusEntry: We don't support WRITE access to the status object");
- return E_ACCESSDENIED;
- }
-
- HRESULT hResult = S_OK;
- // Now, if we already have created a status object on this logon context,
- // we'll just use QueryInterface to get a new copy (AddRef() it) of the object
- if (!m_pStatusObj)
- {
- // Get the profile section of the PROVIDER so that we may get some properties,
- // assigned by MAPI to this provider, directly on the status object.
- LPPROFSECT pProfileObj = NULL;
- m_pSupObj->OpenProfileSection (NULL, 0, &pProfileObj);
- // If we don't have an object, create it, and save a copy in the logon object
- m_pStatusObj = new CMAPIStatus (this, pProfileObj);
- if (!m_pStatusObj)
- {
- TraceMessage ("CXPLogon::OpenStatusEntry: Could not allocate new CMAPIStatus object");
- hResult = E_OUTOFMEMORY;
- }
- // The constructor of CMAPIStatus AddRef()'ed this object
- if (pProfileObj)
- {
- pProfileObj->Release();
- }
- }
- if (!hResult)
- {
- // The transport will return *ppEntry == NULL or a pointer to the new memory allocated
- m_pStatusObj->AddRef();
- *ppEntry = m_pStatusObj;
- *pulObjType = MAPI_STATUS;
- }
- return hResult;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::ValidateState()
- //
- // Parameters
- // { Refer to MAPI Documentation on this method }
- //
- // Purpose
- // This function gets caller by a client in order to validate the
- // transport logon properties. This function open the profile with the
- // most up-to-date properties and then compares them to what the transport
- // has stored internally
- //
- // Return Value
- // An HRESULT
- //
- STDMETHODIMP CXPLogon::ValidateState (ULONG ulUIParam, ULONG ulFlags)
- {
- InfoTrace ("CXPLogon::ValidateState method called");
- CheckParameters_IXPLogon_ValidateState (this,
- ulUIParam,
- ulFlags);
-
- // Try to open the transport profile section
- LPPROFSECT pProfileObj;
- HRESULT hResult = OpenServiceProfileSection (m_pSupObj, &pProfileObj, gpfnFreeBuffer);
- if (hResult)
- {
- return hResult;
- }
-
- LPSPropValue pProps = NULL;
- ULONG ulPropCount;
- // Read the properties stored in the profile of this user
- hResult = pProfileObj->GetProps ((LPSPropTagArray)&sptLogonProps,
- fMapiUnicode,
- &ulPropCount,
- &pProps);
- TraceResult ("CXPLogon::ValidateState: Failed to get profile properties", hResult);
- if (!hResult)
- {
- // Now, compare what the transport thinks the information in the profile is
- // to the real data. If they are different, tell the spooler the transport
- // would like to be reloaded
- if (lstrcmp (m_UserInfo.szMailboxName, pProps[MAILBOX_NAME].Value.LPSZ)||
- lstrcmp (m_UserInfo.szPassword, pProps[PASSWORD].Value.LPSZ) ||
- lstrcmp (m_UserInfo.szFullName, pProps[USER_NAME].Value.LPSZ) ||
- lstrcmpi (m_szServer, pProps[SERVER_NAME].Value.LPSZ))
- {
- hResult = m_pSupObj->SpoolerNotify (NOTIFY_CONFIG_CHANGE, NULL);
- TraceResult ("CXPLogon::ValidateState: Failed to notify the spooler", hResult);
- }
- }
- pProfileObj->Release();
- gpfnFreeBuffer (pProps);
- return hResult;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::FlushQueues()
- //
- // Parameters
- // { Refer to MAPI Documentation on this method }
- //
- // Purpose
- // Called by the MAPI spooler when, upon request of the client or
- // ourselves, we need to flush the inbound or outbound queue.
- // Here we make connections to the server to download messages, refresh
- // the remote message headers, and request the spooler to send us any
- // deferred messages.
- // Transport connecting only in FlushQueues() allow the MAPI spooler to
- // better manage contention of multiple transport accessing common
- // communication resources (such as COM ports) and let the spooler give us
- // messages to process when is best for the overall subsystem.
- //
- // Return Value
- // An HRESULT
- //
- STDMETHODIMP CXPLogon::FlushQueues (ULONG ulUIParam,
- ULONG cbTargetTransport,
- LPENTRYID pTargetTransport,
- ULONG ulFlags)
- {
- InfoTrace ("CXPLogon::FlushQueues method called");
- CheckParameters_IXPLogon_FlushQueues (this,
- ulUIParam,
- cbTargetTransport,
- pTargetTransport,
- ulFlags);
-
- HRESULT hResult = S_OK;
- // Update status flags and then update update the transport status rows
- if (ulFlags & FLUSH_UPLOAD)
- {
- // If the remote server is offline, the transport is not going to send the deferred messages
- if (TRUE == IsWINDSServerAvailable (m_szServer))
- {
- // If we are already in delivery mode submitted messages will not get deferred,
- // so don't bother the spooler asking for deferred messages.
- if (READY != GetTransportState())
- {
- // Guard against re-entrancy from the timer call back which happens on a separate thread
- if (PROCESSING_TIMER_EVENT != GetTransportState())
- {
- SetTransportState (READY);
- }
- // We pass NULL for the entry ID so that the spooler would resend ALL the
- // deferred messages. Transport may pass individual entry IDs for specific messages.
- hResult = m_pSupObj->SpoolerNotify (NOTIFY_SENTDEFERRED, NULL);
- }
- }
- }
- if (ulFlags & FLUSH_DOWNLOAD)
- {
- if (HEADERS_AND_DOWNLOAD == GetTransportState())
- {
- m_hRemoteActionErr = ProcessHeaders();
- if (!m_hRemoteActionErr && !m_fCancelPending)
- {
- m_pSupObj->SpoolerYield (0);
- if (m_List.AreTherePendingDownloads())
- {
- // Put ourselves into flush mode and have the spooler call us until
- // we are finished putting the downloaded messages into the default store.
- AddStatusBits (DOWNLOADING_MESSAGES); // Add these bits to the status code
- }
- if (!m_fCancelPending)
- {
- // Upload any deferred messages the spooler has for our transport
- if (IsWINDSServerAvailable (m_szServer))
- {
- m_pSupObj->SpoolerNotify (NOTIFY_SENTDEFERRED, NULL);
- }
- if (!m_fCancelPending)
- {
- m_hRemoteActionErr = DownloadMessageHeaders();
- if (!m_hRemoteActionErr && !(GetTransportStatusCode() & DOWNLOADING_MESSAGES))
- {
- RemoveStatusBits (STATUS_INBOUND_FLUSH);
- UpdateStatus (TRUE, TRUE);
- m_pSupObj->SpoolerYield (0);
- }
- }
- }
- }
- SetTransportState (PENDING_RETURN_CODE);
- AddStatusBits (STATUS_OFFLINE);
- if (m_hRemoteActionErr)
- {
- RemoveStatusBits (STATUS_INBOUND_FLUSH);
- UpdateStatus (TRUE, TRUE);
- }
- else
- {
- if (m_fCancelPending)
- {
- UpdateStatus (TRUE, TRUE);
- }
- else
- {
- UpdateStatus();
- }
- }
- }
- else
- {
- if (PROCESSING_TIMER_EVENT == GetTransportState())
- {
- if (m_fGetHeaders)
- {
- RemoveStatusBits (STATUS_OFFLINE);
- UpdateStatus();
- DownloadMessageHeaders();
- AddStatusBits (STATUS_OFFLINE);
- UpdateStatus();
- }
- }
- else
- {
- if (m_List.AreTherePendingDownloads())
- {
- // Put ourselves into flush mode and have the spooler call us until
- // we are finished putting the downloaded messages into the default store.
- AddStatusBits (DOWNLOADING_MESSAGES); // Add these bits to the status code
- UpdateStatus();
- }
- }
- }
- }
- return hResult;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::ProcessHeaders()
- //
- // Parameters
- // None.
- //
- // Purpose
- // This method is called from the status object's ValidateState when
- // it's passed PROCESS_XP_HEADER_CACHE. It starts the download processing.
- // First we get the header folder contents table and restrict it to rows
- // where PR_MSG_STATUS is >= MSGSTATUS_REMOTE_DOWNLOAD. These are rows
- // for messages that have the MSGSTATUS_REMOTE_DOWNLOAD, or
- // MSGSTATUS_REMOTE_DELETE, or both, bits set.
- //
- // We then connect to the server to obtain the download named pipe and
- // start the download.
- //
- // Return Value
- // An HRESULT
- //
- STDMETHODIMP CXPLogon::ProcessHeaders()
- {
- // If we don't have a folder in the status object or the folder doesn't
- // have an initialized contents table, there is nothing to do.
- if (!m_pStatusObj->m_pHeaderFolder || !m_pStatusObj->m_pHeaderFolder->m_pTableData)
- {
- return S_OK;
- }
-
- // Get headers folder contents table, some are marked for download
- LPMAPITABLE pTable;
- HRESULT hResult = m_pStatusObj->m_pHeaderFolder->m_pTableData->HrGetView (NULL, NULL, 0, &pTable);
- if (hResult)
- {
- TraceResult ("CXPLogon::ProcessHeaders: Failed to get a view on the contents table", hResult);
- return hResult;
- }
-
- // we only want rows marked for download, form restriction
- SPropValue spvFilter = { 0 };
- spvFilter.ulPropTag = PR_MSG_STATUS;
- spvFilter.Value.l = MSGSTATUS_REMOTE_DOWNLOAD;
-
- // This restriction relies in the current values of the flags in PR_MSG_STATUS
- SRestriction srStatus = { 0 };
- srStatus.rt = RES_PROPERTY;
- srStatus.res.resProperty.relop = RELOP_GE;
- srStatus.res.resProperty.ulPropTag = PR_MSG_STATUS;
- srStatus.res.resProperty.lpProp = &spvFilter;
-
- hResult = pTable->Restrict (&srStatus, 0);
- if (hResult)
- {
- // This is a non-fatal error (i.e. the implementation does not support restrictions)
- TraceResult ("CXPLogon::ProcessHeaders: Failed to restrict the table", hResult);
- }
- ULONG ulRowCount;
- // Providers and client should not, when ever possible, use IMAPITable::GetRowCount()
- // because depending on the implementation of the table, the returned count by not
- // be exact.
- // We use it here for convenience knowing the fact the MAPI's ITableData implementation
- // returns and EXACT count of the rows in the memory table.
- hResult = pTable->GetRowCount (0, &ulRowCount);
- if (hResult)
- {
- goto ErrorExit;
- }
- // Nothing to do.
- if (0 == ulRowCount)
- {
- goto ErrorExit;
- }
- else
- {
- // Make sure our download directory is around.
- TCHAR szTmpDir[_MAX_PATH], szDownloadDir[_MAX_PATH];
- GetTempPath (_MAX_PATH, szTmpDir);
- lstrcat (szTmpDir, WINDS_DATA_DIRECTORY);
- wsprintf (szDownloadDir, WINDS_DOWNLOAD_DIR_NAME_FORMAT, szTmpDir, m_UserInfo.szMailboxName);
- CreateDirectory (szDownloadDir, NULL);
- }
-
- // Initialize the progress property in the status row of this transport.
- UpdateProgress (0, REMOTE_ACTION_DOWNLOADING_MSGS);
-
- // Make a call to the remote server to open the connection
- HANDLE hPipe;
- hResult = OpenRemoteServerDownLoadPipe (m_szServer, m_UserInfo.szMailboxName, &hPipe);
- if (hResult)
- {
- goto ErrorExit;
- }
- // Do the actual download transmission now.
- hResult = m_List.DownLoadMsgs (pTable, ulRowCount, hPipe);
- CloseHandle (hPipe);
-
- TerminateRemoteConnections();
-
- ErrorExit:
- TraceResult ("CXPLogon::ProcessHeaders", hResult);
- pTable->Release();
- return hResult;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::UpdateProgress()
- //
- // Parameters
- // lPercentComplete Percent completion of download
- // raFlag Flag that indicate to what remote action the
- // update is tied to, so that we may properly
- // update PR_REMOTE_PROGRESS_TEXT.
- //
- // Purpose
- // Sets the status row property PR_REMOTE_PROGRESS with a number from
- // 0-100. In example, if 10 messages are queued and 5 have been
- // downloaded, lPercentComplete will be 50, regardless of individual
- // messages' sizes.
- //
- // Return Value
- // None.
- //
- void WINAPI CXPLogon::UpdateProgress (long lPercentComplete,
- REMOTE_ACTION raFlag)
- {
- SPropValue spProgress[2] = { 0 };
- ULONG cProps = 1;
- TCHAR szRemoteProgress[64] = { 0 };
- spProgress[0].ulPropTag = PR_REMOTE_PROGRESS;
- spProgress[0].Value.l = lPercentComplete;
- if (raFlag != m_raAction)
- {
- spProgress[1].ulPropTag = PR_REMOTE_PROGRESS_TEXT;
- spProgress[1].Value.LPSZ = szRemoteProgress;
- DWORD idString;
- m_raAction = raFlag;
- switch (raFlag)
- {
- case REMOTE_ACTION_DOWNLOADING_MSGS :
- idString = IDS_REMOTE_DOWNLOADING;
- break;
- case REMOTE_ACTION_PROCESSING_MSGS :
- idString = IDS_REMOTE_PROCESSING_MSGS;
- break;
- case REMOTE_ACTION_HEADER_REFRESH :
- idString = IDS_REMOTE_REFRESHING_HEADERS;
- break;
- case REMOTE_ACTION_IDLE :
- idString = 0;
- break;
- }
- if (idString)
- {
- LoadString (m_hInstance, idString, szRemoteProgress, 64);
- }
- cProps++;
- }
-
- HRESULT hResult = m_pSupObj->ModifyStatusRow (cProps, spProgress, STATUSROW_UPDATE);
- TraceResult ("CXPLogon::UpdateProgress: Failed to modify the status row", hResult);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::LoadStatusString()
- //
- // Parameters
- // pString Pointer to a string which will hold the status string
- // uStringSize Maximum number of characters allowed in the string
- //
- // Purpose
- // Loads a string from the transport's stringtable. This method is called
- // by the CXPLogon::UpdateStatus method when updating a status row. This
- // method loads the string based on the status bits of the transport
- // status code
- //
- // Return Value
- // TRUE If the string was found in the string table.
- // FALSE The string was not found. The String indicated by
- // pString is set to hold 0 characters
- //
- BOOL WINAPI CXPLogon::LoadStatusString (LPTSTR pString, UINT uStringSize)
- {
- UINT uStringID;
- DWORD dwStatusCode = GetTransportStatusCode();
- if (dwStatusCode & (DOWNLOADING_MESSAGES | UPLOADING_MESSAGES))
- {
- uStringID = IDS_XP_STATUS_TIMER_EVENT;
- }
- else
- {
- if (dwStatusCode & DOWNLOADING_MESSAGES)
- {
- if (dwStatusCode & STATUS_OFFLINE)
- {
- uStringID = IDS_XP_STATUS_FLUSHING_INBOUND;
- }
- else
- {
- uStringID = IDS_XP_STATUS_INBOUND_AND_HEADERS;
- }
- }
- else
- {
- if (dwStatusCode & UPLOADING_MESSAGES)
- {
- uStringID = IDS_XP_STATUS_FLUSHING_OUTBOUND;
- }
- else
- {
- if (dwStatusCode & STATUS_INBOUND_ENABLED &&
- dwStatusCode & STATUS_OUTBOUND_ENABLED)
- {
- uStringID = IDS_XP_STATUS_READY;
- }
- else
- {
- uStringID = IDS_XP_STATUS_AVAILABLE;
- }
- }
- }
- }
- if (LoadString (m_hInstance, uStringID, pString, uStringSize))
- {
- return TRUE;
- }
- pString[0] = '\0';
- return FALSE;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::MakeSearchKey()
- //
- // Parameters
- // pParentMemBlock Pointer the a block of memory allocated with the
- // MAPI Mem. alloc. functions.
- // pszAddress String with the actual mail address
- // pcbSearchKey Pointer to a ULONG which returns the size
- // (in bytes) of the newly created search key
- // ppSearchKey Pointer to an array ob BYTES
- //
- // Purpose
- // Returns a MAPI search key of the form TYPE:ADDRESS in upper case.
- // The string is allocated with the MAPI Mem Alloc functions and linked
- // to the block of memory indicated by pParentMemBlock
- //
- // Return Value
- // An HRESULT
- //
- STDMETHODIMP CXPLogon::MakeSearchKey (LPVOID pParentMemBlock,
- LPTSTR pszAddress,
- ULONG * pcbSearchKey,
- LPBYTE * ppSearchKey)
- {
- LPTSTR pszSearchKey;
- // The 2 is for the COLON and the NULL terminator
- ULONG cbStrSize = sizeof (TCHAR) * (2 + lstrlen (WINDS_ADDRESS_TYPE) + lstrlen (pszAddress));
- HRESULT hResult = gpfnAllocateMore (cbStrSize, pParentMemBlock, (LPVOID *)&pszSearchKey);
- TraceResult ("CXPLogon::MakeSearchKey: Failed to allocate search key string", hResult);
- if (!hResult)
- {
- // We need to convert the address to upper case
- wsprintf (pszSearchKey, TEXT("%s:%s"), WINDS_ADDRESS_TYPE, pszAddress);
- CharUpper (pszSearchKey);
- *pcbSearchKey = cbStrSize;
- *ppSearchKey = (LPBYTE)pszSearchKey;
- }
- return hResult;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::UpdateStatus()
- //
- // Parameters
- // fAddValidate
- // fValidateOkState
- //
- // Purpose
- // Updates the transport status row of this transport in the MAPI Mail
- // subsystem. Updates the flags according the internal state flags
- // maintained in status code of the transport and loads a readable status
- // string to reset the status row. The caller of this method should update
- // the status code member variable prior to calling UpdateStatus()
- //
- // Return Value
- // None
- //
- void WINAPI CXPLogon::UpdateStatus (BOOL fAddValidate, BOOL fValidateOkState)
- {
- ULONG cProps = 1;
- SPropValue rgProps[3] = { 0 };
- // Store the new Transport Provider Status Code
- rgProps[0].ulPropTag = PR_STATUS_CODE;
- rgProps[0].Value.l = GetTransportStatusCode();
-
- TCHAR szStatus[64];
- if (LoadStatusString (szStatus, sizeof(szStatus) - 1 ))
- {
- rgProps[1].ulPropTag = PR_STATUS_STRING;
- rgProps[1].Value.LPSZ = szStatus;
- cProps++;
- }
- if (fAddValidate)
- {
- ULONG index;
- if (2 == cProps)
- {
- index = 2;
- }
- else
- {
- index = 1;
- }
- rgProps[index].ulPropTag = PR_REMOTE_VALIDATE_OK;
- rgProps[index].Value.b = fValidateOkState;
- cProps++;
- }
- // OK. Notify the messaging subsystem of state changes in this transport.
- HRESULT hResult = m_pSupObj->ModifyStatusRow (cProps, rgProps, STATUSROW_UPDATE);
- TraceResult ("CXPLogon::UpdateStatus: ModifyStatusRow failed", hResult);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::InitializeTransportStatusFlags()
- //
- // Parameters
- // ulFlags Flags passed in to initialize the transport status flags.
- //
- // Purpose
- // Initialize the transport status flags with the flags passed in by the
- // MAPI spooler. This method gets called when initializing a CXPLogon
- // object in the CXPProvider::TransportLogon method.
- //
- // Return Value
- // None
- //
- void WINAPI CXPLogon::InitializeTransportStatusFlags (ULONG ulFlags)
- {
- AddStatusBits (STATUS_AVAILABLE | STATUS_OFFLINE | STATUS_REMOTE_ACCESS);
- if (!(ulFlags & LOGON_NO_INBOUND))
- {
- AddStatusBits (STATUS_INBOUND_ENABLED);
- }
- if (!(ulFlags & LOGON_NO_OUTBOUND))
- {
- AddStatusBits (STATUS_OUTBOUND_ENABLED);
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::SetIdentityProps()
- //
- // Parameters
- // None
- //
- // Purpose
- // Initializes the transport ID array with the properties found in the
- // profile for the user.
- // If the ABWDS address book is installed, we open an entry in it to
- // supply the identity properties.
- //
- // Return Value
- // An HRESULT
- //
- STDMETHODIMP CXPLogon::SetIdentityProps()
- {
- // Allocate the property array for transport. This memory block is freed
- // in the destructor of the CXPLogon object
- HRESULT hResult = gpfnAllocateBuffer (sizeof(SPropValue)*NUM_IDENTITY_PROPS, (LPVOID *)&m_pIdentityProps);
- if (hResult)
- {
- TraceResult ("CXPLogon::SetIdentityProps: Failed to allocate property array", hResult);
- return hResult;
- }
- LPMAILUSER pUser;
- ULONG ulObjType;
- TCHAR szSearchKey[128];
- LPTSTR pStr;
- // Try to open out entry ID in the ABWDS address book (see if it is around)
- // If the call fails, we must create a one-off for our identity.
- hResult = m_pSupObj->OpenEntry (CB_PRIVATE_EID,
- (LPENTRYID)&m_UserEID,
- NULL,
- 0,
- &ulObjType,
- (LPUNKNOWN *)&pUser);
- if (S_OK == hResult)
- {
- ASSERTMSG (MAPI_MAILUSER == ulObjType, "What kind object is this?");
-
- // Looks like ABWDS is around, mark the internal flag.
- // ABWDS is the native WINDS address book service provider. If present,
- // instead of creating a one-off entry for the transport identity, we
- // will simply open an entry in the WINDS address book and get the
- // necessary properties out from it.
- m_fABWDSInstalled = TRUE;
-
- m_pIdentityProps[XPID_NAME].ulPropTag = PR_SENDER_NAME;
- m_pIdentityProps[XPID_NAME].Value.LPSZ = m_UserInfo.szFullName;
- m_pIdentityProps[XPID_EID].ulPropTag = PR_SENDER_ENTRYID;
- m_pIdentityProps[XPID_EID].Value.bin.cb = CB_PRIVATE_EID;
- m_pIdentityProps[XPID_EID].Value.bin.lpb = (LPBYTE)&m_UserEID;
- wsprintf (szSearchKey,
- TEXT("%s:%s\\%s"),
- WINDS_ADDRESS_TYPE,
- m_szServer, // this is already in the format "\\<servername>"
- m_UserInfo.szMailboxName);
- CharUpper (szSearchKey);
- hResult = gpfnAllocateMore (Cbtszsize(szSearchKey), m_pIdentityProps, (LPVOID *)&pStr);
- if (hResult)
- {
- TraceResult ("CXPLogon::SetIdentityProps: Failed to allocate string for native search key", hResult);
- m_pIdentityProps[XPID_SEARCH_KEY].ulPropTag = PROP_TAG (PT_ERROR, PROP_ID (PR_SENDER_SEARCH_KEY));
- }
- else
- {
- lstrcpy (pStr, szSearchKey);
- m_pIdentityProps[XPID_SEARCH_KEY].ulPropTag = PR_SENDER_SEARCH_KEY;
- m_pIdentityProps[XPID_SEARCH_KEY].Value.bin.cb = Cbtszsize(pStr);
- m_pIdentityProps[XPID_SEARCH_KEY].Value.bin.lpb = (LPBYTE)pStr;
- }
- pUser->Release();
- return hResult;
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // Set the PR_SENDER_ENTRYID property. Create an entry for the user and
- // set it in the property array
- m_pIdentityProps[XPID_EID].ulPropTag = PR_SENDER_ENTRYID;
- LPBYTE lpeid = NULL;
- ULONG cbeid = 0;
- hResult = m_pSupObj->CreateOneOff (m_UserInfo.szFullName,
- WINDS_ADDRESS_TYPE,
- m_szAddress,
- fMapiUnicode,
- &cbeid,
- (LPENTRYID *)&lpeid);
- if (hResult)
- {
- TraceResult ("CXPLogon::SetIdentityProps: Failed to create a one off identity", hResult);
- m_pIdentityProps[XPID_EID].ulPropTag = PROP_TAG (PT_ERROR, PROP_ID (PR_SENDER_ENTRYID));
- return hResult;
- }
-
- hResult = gpfnAllocateMore(cbeid, m_pIdentityProps,
- (LPVOID *)&m_pIdentityProps[XPID_EID].Value.bin.lpb);
- if(hResult)
- {
- TraceResult ("CXPLogon::SetIdentityProps: Failed to allocate memory", hResult);
- m_pIdentityProps[XPID_EID].ulPropTag = PROP_TAG (PT_ERROR, PROP_ID (PR_SENDER_ENTRYID));
- gpfnFreeBuffer(lpeid);
- lpeid = NULL;
- return hResult;
- }
-
- m_pIdentityProps[XPID_EID].Value.bin.cb = cbeid;
- CopyMemory(m_pIdentityProps[XPID_EID].Value.bin.lpb, lpeid, cbeid);
-
- gpfnFreeBuffer(lpeid);
- lpeid = NULL;
-
- //////////////////////////////////////////////////////////////////////////
- // Set the PR_SENDER_NAME property
- m_pIdentityProps[XPID_NAME].ulPropTag = PR_SENDER_NAME;
- LPTSTR pStr1, pStr2 = m_UserInfo.szFullName;
- hResult = gpfnAllocateMore (Cbtszsize(pStr2), m_pIdentityProps, (LPVOID *)&pStr1);
- if (hResult)
- {
- TraceResult ("CXPLogon::SetIdentityProps: Memory allocation failed for display name string", hResult);
- m_pIdentityProps[XPID_NAME].ulPropTag = PROP_TAG (PT_ERROR, PROP_ID (PR_SENDER_NAME));
- return hResult;
- }
- lstrcpy (pStr1, pStr2);
- m_pIdentityProps[XPID_NAME].Value.LPSZ = pStr1;
-
- //////////////////////////////////////////////////////////////////////////
- // Set the PR_SENDER_SEARCH_KEY property
- m_pIdentityProps[XPID_SEARCH_KEY].ulPropTag = PR_SENDER_SEARCH_KEY;
- // First, create the search key
- hResult = MakeSearchKey (m_pIdentityProps,
- m_szAddress,
- &m_pIdentityProps[XPID_SEARCH_KEY].Value.bin.cb,
- &m_pIdentityProps[XPID_SEARCH_KEY].Value.bin.lpb);
- if (hResult)
- {
- m_pIdentityProps[XPID_SEARCH_KEY].ulPropTag = PROP_TAG (PT_ERROR, PROP_ID (PR_SENDER_SEARCH_KEY));
- }
- return hResult;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::SetSessionFlags()
- //
- // Parameters
- // [IN, OUT] pulFlags Flags returned to caller
- //
- // Purpose
- // To set the flags we will return to the spooler during the CXPLogon
- // initialization in the CXPProvider::TransportLogon method. The ulFlags
- // parameter is filled as a return value to the caller
- //
- // Return Value
- // None
- //
- void WINAPI CXPLogon::SetSessionFlags (ULONG * pulFlags)
- {
- if (*pulFlags & LOGON_NO_CONNECT)
- {
- // Nothing is set
- *pulFlags = 0;
- }
- else
- {
- // We DON'T want the MAPI spooler to call our IXPLogon::Idle method (LOGON_SP_IDLE not added)
- // We DON'T want the MAPI spooler to call our IXPLogon::Poll method (LOGON_SP_POLL not added)
- // Also the names have to be fully resolved (LOGON_SP_RESOLVE)
- *pulFlags = LOGON_SP_RESOLVE;
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::SendMailMessage()
- //
- // Parameters
- // pMsgObj Pointer to an IMessage object passed to us by the
- // MAPI spooler.
- // pRecipRows Row set with ALL the rows from the recipient table which
- // have the properties of the recipients we are sending the
- // message to.
- //
- // Purpose
- // This method gets called by SubmitMessage() to do the delivery of the
- // message to the list of recipients. Each recipient will have the
- // PR_RESPONSIBILITY property set indicating weather or not message
- // reached the recipient.
- //
- // Return Value
- // An HRESULT
- //
- STDMETHODIMP CXPLogon::SendMailMessage (LPMESSAGE pMsgObj, LPSRowSet pRecipRows)
- {
- LPSPropValue pMsgProps = NULL;
- LPADRLIST pAdrList = NULL, pAdrListFailed = NULL;
- LPSTnefProblemArray pProblems = NULL;
- CCachedStream * pStream = NULL;
- LPSTREAM pFileStream;
- HANDLE hMsgFile = NULL;
- HRESULT hOpenConnect, hUploadError;
- BOOL fErrorInServer, fSentSuccessfully;
- ULONG ulRow, ulCount1 = 0 , ulCount2 = 0;
- LPTSTR pszServer, pszMailbox;
- LPSPropValue pProps;
- TCHAR szHeaderText[1024], szTmpFile[_MAX_PATH], szConnectInfo[MAX_STRING_SIZE+1] = { 0 };
- if (!GetMsgTempFileName (szTmpFile)) // Not the Win32 API, but an internal implementation
- {
- return E_FAIL;
- }
-
- // Create a stream where all message information will be saved.
- HRESULT hResult = OpenStreamOnFile (gpfnAllocateBuffer,
- gpfnFreeBuffer,
- STGM_CREATE | STGM_READWRITE,
- szTmpFile,
- NULL,
- &pFileStream);
- if (hResult)
- {
- TraceResult ("CXPLogon::SendMailMessage: Failed to create stream object", hResult);
- return hResult;
- }
- try
- {
- pStream = new CCachedStream (pFileStream, XPSOF_READWRITE);
- if (!pStream)
- {
- TraceMessage ("CXPLogon::SendMailMessage: Failed to allocate cached stream object");
- hResult = E_OUTOFMEMORY;
- }
- }
- catch (CException & Exception)
- {
- hResult = Exception.GetError();
- }
- pFileStream->Release();
- pFileStream = NULL;
- if (hResult)
- {
- return hResult;
- }
-
- // The wKey is a key used to identify the TNEF property stream. Transports
- // should generate a pseudo-random number for this field. Here we get
- // a number based upon the system's tic count
- // Note that this number cannot be zero of the OpenTnefStream call will be fail.
- WORD wKey = LOWORD (GetTickCount());
- if (!wKey)
- {
- ASSERTMSG (FALSE, "I'll be darn! It's zero!!!");
- wKey = LOWORD (GetTickCount()) + 1;
- ASSERTMSG (0 != wKey, "No way! What is going on!?!?");
- }
- LPITNEF pTNEFObj = NULL;
- hResult = OpenTnefStream (m_pSupObj,
- pStream,
- TNEF_FILE_NAME,
- TNEF_ENCODE | TNEF_PURE,
- pMsgObj,
- wKey,
- &pTNEFObj);
- if (hResult)
- {
- TraceResult ("CXPLogon::SendMailMessage: Failed to create TNEF object", hResult);
- goto ErrorExit;
- }
-
- // Let the MAPI spooler do other things
- CheckSpoolerYield();
-
- // Get the current time. We need to set some properties that require the time
- SYSTEMTIME st;
- FILETIME ft;
- GetSystemTime (&st);
- SystemTimeToFileTime (&st, &ft);
-
- SetOutgoingProps (pMsgObj, ft);
-
- // Check what properties there are and exclude the Non-Transmittables ones
- LPSPropTagArray pTags;
- hResult = pMsgObj->GetPropList (fMapiUnicode, &pTags);
- if (hResult)
- {
- TraceResult ("CXPLogon::SendMailMessage: Failed to get the message property tags", hResult);
- goto ErrorExit;
- }
-
- // Let the MAPI spooler do other things
- CheckSpoolerYield();
-
- // In this sample transport we opted to let TNEF encapsulate
- // the table of recipients of this message. This has a side effect: The
- // addresses of the recipients get munged into the TNEF stream. So, for
- // example, if the TNEF file goes through a foreign mail system and it
- // needs to translate the address of the recipients, it will not be
- // able to. A tranport using TNEF which trasmits messages to a foreign
- // mail system, must do custom processing of the recipients and their
- // address so the receiving side will understands them.
- // This sample code must be modified if you want it as the base code
- // for a gateway transport.
- // Here we also let TNEF encode all the attachments we want to send.
- ULONG cValues, i;
- cValues = 0;
- for (i=0; i<pTags->cValues; i++)
- {
- // Use the FIsTransmittable macro in MAPI to determine if a
- // property is transmittable or not.
- if (!FIsTransmittable(pTags->aulPropTag[i]) &&
- PR_MESSAGE_RECIPIENTS != pTags->aulPropTag[i] &&
- PR_MESSAGE_ATTACHMENTS != pTags->aulPropTag[i])
- {
- pTags->aulPropTag[cValues++] = pTags->aulPropTag[i];
- }
- }
- pTags->cValues = cValues;
-
- // Encode the properties now
- hResult = pTNEFObj->AddProps (TNEF_PROP_EXCLUDE, 0, NULL, pTags);
- gpfnFreeBuffer (pTags);
- if (FAILED(hResult)) // There could be warnings
- {
- TraceResult ("CXPLogon::SendMailMessage: Failed to Add the TNEF properties to the message stream", hResult);
- goto ErrorExit;
- }
-
- hResult = pTNEFObj->Finish (0, &wKey, &pProblems);
- if (FAILED(hResult)) // There could be warnings
- {
- TraceResult ("CXPLogon::SendMailMessage: Failed to save the TNEF props", hResult);
- goto ErrorExit;
- }
- if (pProblems)
- {
- TraceMessage ("CXPLogon::SendMailMessage: Some problem(s) occurred while finishing the TNEF encoding");
- gpfnFreeBuffer (pProblems);
- pProblems = NULL;
- // Don't have to fail submission
- }
-
- // Release used objects and NULL the object pointers to avoid re-releasing them during cleanup
- if (NULL != pTNEFObj)
- {
- pTNEFObj->Release();
- pTNEFObj = NULL;
- }
- if (NULL != pStream)
- {
- pStream->Release();
- pStream = NULL;
- }
-
- hMsgFile = CreateFile (szTmpFile,
- GENERIC_READ,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_TEMPORARY |
- FILE_FLAG_DELETE_ON_CLOSE |
- FILE_FLAG_SEQUENTIAL_SCAN,
- NULL);
- if (INVALID_HANDLE_VALUE == hMsgFile)
- {
- TraceResult ("CXPLogon::SendMailMessage: Failed to open local msg file", GetLastError());
- hResult = E_FAIL;
- goto ErrorExit;
- }
-
- // Get some properties in the message need to send the message
- // and delivery report information
- hResult = pMsgObj->GetProps ((LPSPropTagArray)&sptPropsForHeader,
- fMapiUnicode,
- &cValues,
- &pMsgProps);
- if (FAILED(hResult))
- {
- TraceResult ("CXPLogon::SendMailMessage: Failed to get message props", hResult);
- goto ErrorExit;
- }
-
- // We need to check if the sender requeste a delivery report or not.
- BOOL fNeedDeliveryReport;
- if (PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED == pMsgProps[MSG_DR_REPORT].ulPropTag &&
- pMsgProps[MSG_DR_REPORT].Value.b)
- {
- fNeedDeliveryReport = TRUE;
- }
- else
- {
- fNeedDeliveryReport = FALSE;
- }
-
- // Create the header that we transmit to the server. The remote host will
- // store this information and make it available to us when then recipients
- // of the message ask for a headers update on their remote mailboxes.
- CreateMsgHeaderTextLine (pMsgProps, szHeaderText, ft);
-
- // Let the MAPI spooler do other things
- CheckSpoolerYield();
-
- hOpenConnect = OpenServerUploadPipe (m_szServer,
- m_UserInfo.szMailboxName,
- hMsgFile,
- szConnectInfo,
- &fErrorInServer);
- for (ulRow=0; ulRow<pRecipRows->cRows; ulRow++)
- {
- pProps = pRecipRows->aRow[ulRow].lpProps;
-
- // Assume the worst. If hOpenConnect is not S_OK, the fSentSuccessfully
- // must be FALSE to generate NDR for each recipient.
- fSentSuccessfully = FALSE;
- if (S_OK == hOpenConnect)
- {
- if (IsValidAddress (pProps[RECIP_EMAIL_ADR].Value.LPSZ, &pszServer, &pszMailbox))
- {
- // pszServer should be the same as m_szServer
- hUploadError = SendMsgToAccount (pszServer,
- pszMailbox,
- szHeaderText,
- szConnectInfo,
- &fErrorInServer);
- if (!hUploadError)
- {
- // If we got here, we assume the message has been received in the server
- fSentSuccessfully = TRUE;
- }
- }
- else
- {
- hUploadError = MAKE_HRESULT(1, FACILITY_WIN32, ERROR_INVALID_ADDRESS);
- }
- }
- else
- {
- hUploadError = hOpenConnect;
- }
-
- // Let the MAPI spooler do other things
- CheckSpoolerYield();
-
- // Set the PR_RESPONSIBILITY flag to indicated we have handled this
- // recipient (row). If the flag is not modified, MAPI will pass this
- // message to the next transport in the profile that knows how to
- // handle the address types this transport knows.
- // In this case WE want to be the last to handle the message. If
- // we fail the submission, we should tell MAPI to generate an NDR.
- pProps[RECIP_RESPONSIBILITY].ulPropTag = PR_RESPONSIBILITY;
- pProps[RECIP_RESPONSIBILITY].Value.b = TRUE;
-
- // Set the report time for DR's and NDR's
- pProps[RECIP_REPORT_TIME].ulPropTag = PR_REPORT_TIME;
- pProps[RECIP_REPORT_TIME].Value.ft = ft;
-
- if (!fSentSuccessfully)
- {
- // Make the spooler generate an NDR instead of DR
- pProps[RECIP_DELIVER_TIME].ulPropTag = PR_NULL;
-
- // The Spooler will generate an NDR report and will fill in
- // all required properties in the StatusRecips call. The only
- // thing we need to do is to fill in a specific per-recipient
- // text description of the problem. It's good to have real
- // info from the transport indicating the real cause for the
- // failure
- wsprintf (szHeaderText,
- TEXT("\tThe WINDS transport service failed to deliver the message to this recipient.\r\n"
- "\tRecipient Address: Server: %s Mailbox: %s. Delivery error: %#08X. %s"),
- (pszServer ? pszServer : ""),
- (pszMailbox ? pszMailbox : ""),
- hUploadError,
- (fErrorInServer ? TEXT("The error occurred in the server host.") :
- TEXT("The error occurred in local processing.")));
- if (fErrorInServer && hUploadError)
- {
- DWORD dwServerErrorIDS = 0;
- switch (hUploadError)
- {
- case HRESULT_FROM_WIN32(ERROR_INVALID_ACCOUNT_NAME) :
- dwServerErrorIDS = IDS_DELIVERY_ERROR_INVALID_ACCT;
- break;
- case HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER) :
- dwServerErrorIDS = IDS_DELIVERY_ERROR_NO_SUCH_USER;
- break;
- case HRESULT_FROM_WIN32 (ERROR_HOST_UNREACHABLE) :
- dwServerErrorIDS = IDS_DELIVERY_ERROR_OFFLINE_SERVER;
- break;
- case HRESULT_FROM_WIN32 (ERROR_INVALID_ADDRESS) :
- dwServerErrorIDS = IDS_DELIVERY_ERROR_INVALID_ADDRESS;
- break;
- case E_OUTOFMEMORY :
- dwServerErrorIDS = IDS_DELIVERY_ERROR_OUTOFMEMORY;
- break;
- case E_INVALIDARG :
- dwServerErrorIDS = IDS_DELIVERY_ERROR_INVALID_PARAM;
- break;
- }
- if (!dwServerErrorIDS && FACILITY_STORAGE == HRESULT_FACILITY(hUploadError))
- {
- dwServerErrorIDS = IDS_DELIVERY_ERROR_ISTORAGE;
- }
- if (!dwServerErrorIDS && FACILITY_WIN32 == HRESULT_FACILITY(hUploadError))
- {
- dwServerErrorIDS = IDS_DELIVERY_ERROR_WIN32;
- }
- if (dwServerErrorIDS)
- {
- TCHAR szBuffer[256];
- if (LoadString (m_hInstance, dwServerErrorIDS, szBuffer, 255))
- {
- lstrcat (szHeaderText, TEXT("\r\n\t"));
- lstrcat (szHeaderText, szBuffer);
- }
- }
- }
- LPTSTR pStr;
- hResult = gpfnAllocateMore (Cbtszsize(szHeaderText), pProps, (LPVOID *)&pStr);
- if (SUCCEEDED(hResult))
- {
- // Copy the formatted string and hook it into the
- // pre-allocated (by MAPI) column
- lstrcpy (pStr, szHeaderText);
- pProps[RECIP_REPORT_TEXT].ulPropTag = PR_REPORT_TEXT;
- pProps[RECIP_REPORT_TEXT].Value.LPSZ = pStr;
- }
- else
- {
- pProps[RECIP_REPORT_TEXT].ulPropTag = PROP_TAG (PT_ERROR, PROP_ID (PR_REPORT_TEXT));
- pProps[RECIP_REPORT_TEXT].Value.err = hResult;
- TraceResult ("CXPLogon::SendMailMessage: memory allocation failed for the NDR report string", hResult);
- }
- }
- else
- {
- // For delivery report, each recipient must have this property set.
- // Otherwise the spooler will default to generate an NDR instead.
- pProps[RECIP_DELIVER_TIME].ulPropTag = PR_DELIVER_TIME;
- pProps[RECIP_DELIVER_TIME].Value.ft = ft;
-
- pProps[RECIP_REPORT_TEXT].ulPropTag = PROP_TAG (PT_ERROR, PROP_ID (PR_REPORT_TEXT));
- pProps[RECIP_REPORT_TEXT].Value.err = S_OK;
- }
-
- // Based on the result of the submission to the remote host we determine into
- // which address list to add this recipient
- LPADRLIST * ppTmpList = (fSentSuccessfully ? &pAdrList : &pAdrListFailed);
- ULONG ulTmpCount = (fSentSuccessfully ? ulCount1 : ulCount2);
-
- // Does the list where this recipient goes have enough room for one more entry?
- // If not, resize the address list to hold QUERY_SIZE more entries.
- if (!(*ppTmpList) || ((*ppTmpList)->cEntries + 1 > ulTmpCount))
- {
- hResult= GrowAddressList (ppTmpList, 10, &ulTmpCount);
- if (hResult)
- {
- goto ErrorExit;
- }
- ulCount1 = (fSentSuccessfully ? ulTmpCount : ulCount1);
- ulCount2 = (!fSentSuccessfully ? ulTmpCount : ulCount2);
- }
-
- // We have room now so store the new ADRENTRY. As part of the
- // storage, we're going to copy the SRow pointer from the SRowSet
- // into the ADRENTRY. Once we've done this, we won't need the
- // SRowSet any more ... and the SRow will be released when
- // we unwind the ADRLIST
- (*ppTmpList)->aEntries[(*ppTmpList)->cEntries].cValues = pRecipRows->aRow[ulRow].cValues;
- (*ppTmpList)->aEntries[(*ppTmpList)->cEntries].rgPropVals = pRecipRows->aRow[ulRow].lpProps;
-
- // Increase the number of entries in the address list
- (*ppTmpList)->cEntries++;
-
- // Now that we are finished with this row (it is in the right
- // adrlist) we want to disassociate it from the rowset
- // so we don't delete this before we modify the recipients list
- pRecipRows->aRow[ulRow].lpProps = NULL;
- pRecipRows->aRow[ulRow].cValues = 0;
-
- }
-
- // Let the MAPI spooler do other things
- CheckSpoolerYield();
-
- // Do we have some recipients that the message arrived to?
- if (pAdrList)
- {
- hResult = pMsgObj->ModifyRecipients (MODRECIP_MODIFY, pAdrList);
- TraceResult ("CXPLogon::SendMailMessage: ModifyRecipients failed (DELIVERED)", hResult);
- hResult = S_OK; // We'll drop the error code from the modify recipients call
- if (fNeedDeliveryReport)
- {
- hResult = m_pSupObj->StatusRecips (pMsgObj, pAdrList);
- TraceResult ("CXPLogon::SendMailMessage: StatusRecips (DR) failed", hResult);
- if (!HR_FAILED(hResult))
- {
- // If we were successful, we should null out the pointer becase MAPI released
- // the memory for this structure. And we should not try to release it
- // again in the cleanup code.
- pAdrList = NULL;
- }
- }
- }
- // Do we have some recipients that the message DID NOT arrived to?
- if (pAdrListFailed)
- {
- hResult = pMsgObj->ModifyRecipients (MODRECIP_MODIFY, pAdrListFailed);
- // We'll drop the error code from the modify recipients call
- TraceResult ("CXPLogon::SendMailMessage: ModifyRecipients failed (NON-DELIVERED)", hResult);
-
- // The address list has the entries with the PR_RESPONSIBILITY set, so the
- // spooler will know if it has to generate NDR reports.
- hResult = m_pSupObj->StatusRecips (pMsgObj, pAdrListFailed);
- TraceResult ("CXPLogon::SendMailMessage: StatusRecips (NDR) failed", hResult);
- if (!HR_FAILED(hResult))
- {
- // If we were successful, we should null out the pointer becase MAPI released
- // the memory for this structure. And we should not try to release it
- // again in the cleanup code.
- pAdrListFailed = NULL;
- }
- }
-
- ErrorExit:
- gpfnFreeBuffer (pProblems);
- gpfnFreeBuffer (pMsgProps);
- FreePadrlist (pAdrList);
- FreePadrlist (pAdrListFailed);
-
- // Release used objects
- if (pTNEFObj)
- {
- pTNEFObj->Release();
- }
- if (pStream)
- {
- pStream->Release();
- }
- // Close the file if it has been opened
- CloseHandle (hMsgFile);
-
- // Delete the message file in case the function fails before the call to CreateFile() above
- DeleteFile (szTmpFile);
-
- // Call the sender function will NULL parameters to reset internal data buffers
- if (lstrlen(szConnectInfo))
- {
- FinishUploadConnection (m_szServer, szConnectInfo);
- }
-
- // Once we have sent all messages to the remote server(s), terminate all connections
- TerminateRemoteConnections();
-
- // Let the MAPI spooler do other things
- CheckSpoolerYield();
-
- return hResult;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::SetOutgoingProps()
- //
- // Parameters
- // pMsgObj Pointer to the IMessage object we are processing.
- // ft FILETIME structure with the time the message is
- // being delivered.
- //
- // Purpose
- // This function checks that the sender information is on the message
- // so that we may get replies from the intended recipients.
- //
- // Return Value
- // None.
- //
- void WINAPI CXPLogon::SetOutgoingProps (LPMESSAGE pMsgObj, FILETIME ft)
- {
- LPSPropValue pSender;
- ULONG ulValues;
- HRESULT hResult = pMsgObj->GetProps ((LPSPropTagArray)&sptOutMsgProps, fMapiUnicode, &ulValues, &pSender);
- if (FAILED(hResult))
- {
- TraceResult ("CXPLogon::SetOutgoingProps: Failed to get properties from the message", hResult);
- pSender = NULL; // So that we may recover and continue using default values
- }
- ASSERT (2 == ulValues);
- #define NUM_OUTGOING_PROPS 11
- SPropValue spvProps[NUM_OUTGOING_PROPS] = { 0 };
- ULONG i = 0;
- // If no sender has been stamped on the message use the identity of the transport
- if (!pSender || PR_SENDER_ENTRYID != pSender[0].ulPropTag)
- {
- spvProps[i].ulPropTag = PR_SENDER_NAME;
- spvProps[i++].Value.LPSZ = m_UserInfo.szFullName;
-
- spvProps[i].ulPropTag = PR_SENDER_EMAIL_ADDRESS;
- spvProps[i++].Value.LPSZ = m_szAddress;
-
- spvProps[i].ulPropTag = PR_SENDER_ADDRTYPE;
- spvProps[i++].Value.LPSZ = WINDS_ADDRESS_TYPE;
-
- spvProps[i].ulPropTag = PR_SENDER_ENTRYID;
- spvProps[i++].Value.bin = m_pIdentityProps[XPID_EID].Value.bin;
-
- spvProps[i].ulPropTag = PR_SENDER_SEARCH_KEY;
- spvProps[i++].Value.bin = m_pIdentityProps[XPID_SEARCH_KEY].Value.bin;
- }
- // The MS Exchange mail viewer requires these properties
- if (!pSender || PR_SENT_REPRESENTING_NAME != pSender[1].ulPropTag)
- {
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_NAME;
- spvProps[i++].Value.LPSZ = m_UserInfo.szFullName;
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_SEARCH_KEY;
- spvProps[i++].Value.bin = m_pIdentityProps[XPID_SEARCH_KEY].Value.bin;
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_ENTRYID;
- spvProps[i++].Value.bin = m_pIdentityProps[XPID_EID].Value.bin;
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_ADDRTYPE;
- spvProps[i++].Value.LPSZ = WINDS_ADDRESS_TYPE;
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_EMAIL_ADDRESS;
- spvProps[i++].Value.LPSZ = m_szAddress;
- }
- gpfnFreeBuffer (pSender);
-
- // Set the time when this transport actually transmitted the message
- spvProps[i].ulPropTag = PR_MESSAGE_DELIVERY_TIME;
- spvProps[i++].Value.ft = ft;
- spvProps[i].ulPropTag = PR_PROVIDER_SUBMIT_TIME;
- spvProps[i++].Value.ft = ft;
-
- ASSERT (i <= NUM_OUTGOING_PROPS);
- hResult = pMsgObj->SetProps (i, spvProps, NULL);
- TraceResult ("CXPLogon::SetOutgoingProps: Failed to set properties in the message", hResult);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::SetIncomingProps()
- //
- // Parameters
- // pMsgObj Pointer to the IMessage object we are processing.
- //
- // Purpose
- // This function sets the PR_SENT_REPRESENTING_xxx properties in an
- // incoming message if those properties aren't already in the message.
- // For these properties we use the values for the sender of the message.
- // We also walk the recipient list restricted to the address type of our
- // transport looking for us, the recipient of the message, s that we may
- // set the PR_MESSAGE_TO_xxx and PR_MESSAGE_RECIP_ME properties in
- // the message.
- //
- // Return Value
- // An HRESULT
- //
- HRESULT WINAPI CXPLogon::SetIncomingProps (LPMESSAGE pMsgObj, PLIST_NODE pNode)
- {
- // This is the maximum number of properties that we could set in the message
- #define NUM_INCOMING_PROPS 28
- SPropValue spvProps[NUM_INCOMING_PROPS] = { 0 };
- ULONG ulValues, i = 0;
- BOOL fNameIsMissing = FALSE, fAddressIsMissing = FALSE;
- TCHAR szUnknown[] = TEXT("Unknown"), szAddress[128];
- TCHAR szUnknownAddress[] = TEXT("\\\\Unknown\\Unknown"), szSender[MAX_STRING_SIZE+1];
- LPTSTR pszAlias, pszServer;
- LPSPropValue pProps = NULL, pSenderSKEY = NULL, pSenderEID = NULL, pObjProps = NULL;
- LPVOID lpToBeFreed = NULL;
-
- HRESULT hResult = pMsgObj->GetProps ((LPSPropTagArray)&sptNewMsgProps, fMapiUnicode, &ulValues, &pProps);
- if (FAILED(hResult))
- {
- TraceResult ("CXPLogon::SetIncomingProps: Failed to get the message changes", hResult);
- goto RecoverAndContinue;
- }
- hResult = S_OK; // Get rid of any warnings
- // These properties should ALWAYS be in an incoming message, but just in case, we have a backup plan.
- if ((PR_SENDER_NAME != pProps[NEW_SENDER_NAME].ulPropTag ||
- PR_SENDER_EMAIL_ADDRESS != pProps[NEW_SENDER_EMAIL].ulPropTag) && !pNode->fRetry)
- {
- pNode->fRetry = TRUE;
- m_List.ReQueueNode (pNode);
- gpfnFreeBuffer (pProps);
- return MAPI_E_CORRUPT_DATA;
- }
-
- if (PR_SENDER_NAME != pProps[NEW_SENDER_NAME].ulPropTag)
- {
- fNameIsMissing = TRUE;
- pProps[NEW_SENDER_NAME].ulPropTag = PR_SENDER_NAME;
- if (PR_SENDER_EMAIL_ADDRESS == pProps[NEW_SENDER_EMAIL].ulPropTag)
- {
- // Decompose the address and get the alias. At least this is better that UNKNOWN!
- lstrcpy (szAddress, pProps[NEW_SENDER_EMAIL].Value.LPSZ);
- DecomposeAddress (szAddress, &pszServer, &pszAlias);
- lstrcpy (szSender, pszAlias);
- pProps[NEW_SENDER_NAME].Value.LPSZ = szSender;
- }
- else
- {
- // This is the best we can do.
- pProps[NEW_SENDER_NAME].Value.LPSZ = szUnknown;
- }
- }
- if (PR_SENDER_EMAIL_ADDRESS != pProps[NEW_SENDER_EMAIL].ulPropTag)
- {
- pProps[NEW_SENDER_EMAIL].ulPropTag = PR_SENDER_EMAIL_ADDRESS;
- pProps[NEW_SENDER_EMAIL].Value.LPSZ = szUnknownAddress;
- fAddressIsMissing = TRUE;
- }
- spvProps[i].ulPropTag = PR_SENDER_ADDRTYPE;
- spvProps[i++].Value.LPSZ = WINDS_ADDRESS_TYPE;
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_ADDRTYPE;
- spvProps[i++].Value.LPSZ = WINDS_ADDRESS_TYPE;
-
- // Looks like ABWDS is around, mark the internal flag.
- // ABWDS is the native WINDS address book service provider. If present,
- // instead of creating a one-off entry for the sender, we
- // will simply open the entry in the WINDS address book and get the
- // necessary properties out from it.
- // Note that in other to open an entry in the ABWDS address book provider
- // we need to have at least the email address of the sender, otherwise we
- // will default to create one-off entries in the sender (and delagate sender)
- if (m_fABWDSInstalled && !fAddressIsMissing)
- {
- PRIVATE_XP_ENTRYID eidEntry = { 0 };
- eidEntry.uidGlobal = guidXPABEntries;
- eidEntry.uidWINDSEntries = guidABEntries;
- // Decompose the address and get the alias.
- DecomposeAddress (pProps[NEW_SENDER_EMAIL].Value.LPSZ, &pszServer, &pszAlias);
- lstrcpy (eidEntry.szObjectAlias, pszAlias);
- // Put the Email address back to what it was
- RecomposeAddress (pszServer, pszAlias, pProps[NEW_SENDER_EMAIL].Value.LPSZ);
- LPMAILUSER pUser = NULL;
- ULONG ulObjType;
- const static SizedSPropTagArray (3, sptWINDSObjProps) =
- {
- 3,
- {
- PR_DISPLAY_NAME,
- PR_SEARCH_KEY,
- PR_ENTRYID
- }
- };
-
- HRESULT hTmpResult = m_pSupObj->OpenEntry (CB_PRIVATE_XP_EID,
- (LPENTRYID)&eidEntry,
- NULL,
- 0,
- &ulObjType,
- (LPUNKNOWN *)&pUser);
- if (!hTmpResult)
- {
- hTmpResult = pUser->GetProps ((LPSPropTagArray)&sptWINDSObjProps,
- fMapiUnicode,
- &ulValues,
- &pObjProps);
- if (SUCCEEDED(hTmpResult)) // We might get warnings
- {
- if (PR_DISPLAY_NAME == pObjProps[0].ulPropTag &&
- PR_SEARCH_KEY == pObjProps[1].ulPropTag &&
- PR_ENTRYID == pObjProps[2].ulPropTag)
- {
- if (fNameIsMissing)
- {
- spvProps[i].ulPropTag = PR_SENDER_NAME;
- spvProps[i++].Value.LPSZ = pObjProps[0].Value.LPSZ;
- }
- spvProps[i].ulPropTag = PR_SENDER_SEARCH_KEY;
- spvProps[i++].Value.bin = pObjProps[1].Value.bin;
- spvProps[i].ulPropTag = PR_ENTRYID;
- spvProps[i++].Value.bin = pObjProps[2].Value.bin;
- if (PR_SENT_REPRESENTING_NAME != pProps[NEW_SENT_NAME].ulPropTag &&
- PR_SENT_REPRESENTING_EMAIL_ADDRESS != pProps[NEW_SENT_EMAIL].ulPropTag)
- {
- // If the message doesn't have PR_SENT_REPRESENTING_xxx use the sender
- // properties for the delagate sender properties
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_NAME;
- spvProps[i++].Value.LPSZ = pObjProps[0].Value.LPSZ;
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_SEARCH_KEY;
- spvProps[i++].Value.bin = pObjProps[1].Value.bin;
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_ENTRYID;
- spvProps[i++].Value.bin = pObjProps[2].Value.bin;
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_ADDRTYPE;
- spvProps[i++].Value.LPSZ = WINDS_ADDRESS_TYPE;
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_EMAIL_ADDRESS;
- spvProps[i++].Value.LPSZ = pProps[NEW_SENDER_EMAIL].Value.LPSZ;
- }
- }
- else
- {
- // We couldn't find the properties needed from the WINDS
- // address book entry. Continue with one-off entries
- hTmpResult = MAPI_W_ERRORS_RETURNED;
- }
- }
- pUser->Release();
- }
- if (S_OK == hTmpResult)
- {
- goto ContinueAddingProps;
- }
- }
-
- // We need to make a search key for this recipient.
- spvProps[i].ulPropTag = PR_SENDER_SEARCH_KEY;
- hResult = MakeSearchKey (pProps,
- pProps[NEW_SENDER_EMAIL].Value.LPSZ,
- &spvProps[i].Value.bin.cb,
- &spvProps[i].Value.bin.lpb);
- if (!hResult)
- {
- pSenderSKEY = &spvProps[i];
- i++;
- // We need to create a one-off entry in the address book so that we may
- // reply to this recipient. If the recipient already exist, its
- // entry Id will be returned instead.
- spvProps[i].ulPropTag = PR_SENDER_ENTRYID;
-
- //else
- {
- hResult = m_pSupObj->CreateOneOff (pProps[NEW_SENDER_NAME].Value.LPSZ,
- WINDS_ADDRESS_TYPE,
- pProps[NEW_SENDER_EMAIL].Value.LPSZ,
- fMapiUnicode,
- &spvProps[i].Value.bin.cb,
- (LPENTRYID *)&spvProps[i].Value.bin.lpb);
- }
- if (hResult)
- {
- i--; // Ignore this property and the previous
- }
- else
- {
- pSenderEID = &spvProps[i];
- i++;
- }
- }
- TraceResult ("CXPLogon::SetIncomingProps: Failed to create a one-off for the sender", hResult);
-
- if (PR_SENT_REPRESENTING_NAME == pProps[NEW_SENT_NAME].ulPropTag &&
- PR_SENT_REPRESENTING_EMAIL_ADDRESS == pProps[NEW_SENT_EMAIL].ulPropTag)
- {
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_SEARCH_KEY;
- hResult = MakeSearchKey (pProps,
- pProps[NEW_SENT_EMAIL].Value.LPSZ,
- &spvProps[i].Value.bin.cb,
- &spvProps[i].Value.bin.lpb);
- if (!hResult)
- {
- i++;
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_ENTRYID;
- hResult = m_pSupObj->CreateOneOff (pProps[NEW_SENT_NAME].Value.LPSZ,
- WINDS_ADDRESS_TYPE,
- pProps[NEW_SENT_EMAIL].Value.LPSZ,
- fMapiUnicode,
- &spvProps[i].Value.bin.cb,
- (LPENTRYID *)&spvProps[i].Value.bin.lpb);
- if (hResult)
- {
- i--; // Ignore this property and the previous
- }
- else
- {
- lpToBeFreed = spvProps[i].Value.bin.lpb;
- i++;
- }
- }
- // We trace the error but is not fatal
- TraceResult ("CXPLogon::SetIncomingProps: Failed to create a oneoff for the delegated sender", hResult);
- }
- else
- {
- // If the message doesn't have PR_SENT_REPRESENTING_xxx properties AND we were
- // successful at creating the one-off for the sender, we set PR_SENT_REPRESENTING_xxx
- // to the same values as PR_SENDER_xxx
- if (!hResult)
- {
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_NAME;
- spvProps[i++].Value.LPSZ = pProps[NEW_SENDER_NAME].Value.LPSZ;
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_ADDRTYPE;
- spvProps[i++].Value.LPSZ = WINDS_ADDRESS_TYPE;
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_EMAIL_ADDRESS;
- spvProps[i++].Value.LPSZ = pProps[NEW_SENDER_EMAIL].Value.LPSZ;
-
- ASSERT (PR_SENDER_ENTRYID == pSenderEID->ulPropTag);
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_ENTRYID;
- spvProps[i++].Value = pSenderEID->Value;
-
- ASSERT (PR_SENDER_SEARCH_KEY == pSenderSKEY->ulPropTag);
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_SEARCH_KEY;
- spvProps[i++].Value = pSenderSKEY->Value;
- }
- }
-
- ContinueAddingProps:
- // If the sender's address is the same as our address (the recipient), then the message
- // was sent from us, to ourselves, therefore we must set the flag bit in the message.
- if (0 == lstrcmpi (pProps[NEW_SENDER_EMAIL].Value.LPSZ, m_szAddress))
- {
- ASSERT (PR_MESSAGE_FLAGS == pProps[NEW_MSG_FLAGS].ulPropTag);
- spvProps[i].ulPropTag = PR_MESSAGE_FLAGS;
- spvProps[i++].Value.l = pProps[NEW_MSG_FLAGS].Value.l | MSGFLAG_FROMME;
- }
-
- RecoverAndContinue:
- // We must stamp the message with this properties since we (this transport)
- // were the ones who processed the incoming message.
- spvProps[i].ulPropTag = PR_RECEIVED_BY_ENTRYID;
- spvProps[i++].Value.bin = m_pIdentityProps[XPID_EID].Value.bin;
- spvProps[i].ulPropTag = PR_RECEIVED_BY_NAME;
- spvProps[i++].Value.LPSZ = m_pIdentityProps[XPID_NAME].Value.LPSZ;
- spvProps[i].ulPropTag = PR_RECEIVED_BY_SEARCH_KEY;
- spvProps[i++].Value.bin = m_pIdentityProps[XPID_SEARCH_KEY].Value.bin;
- spvProps[i].ulPropTag = PR_RECEIVED_BY_ADDRTYPE;
- spvProps[i++].Value.LPSZ = WINDS_ADDRESS_TYPE;
- spvProps[i].ulPropTag = PR_RECEIVED_BY_EMAIL_ADDRESS;
- spvProps[i++].Value.LPSZ = m_szAddress;
-
- // In this transport we set PR_RCVD_xxx with the values of PR_RECEIVED_xxx
- spvProps[i].ulPropTag = PR_RCVD_REPRESENTING_ENTRYID;
- spvProps[i++].Value.bin = m_pIdentityProps[XPID_EID].Value.bin;
- spvProps[i].ulPropTag = PR_RCVD_REPRESENTING_NAME;
- spvProps[i++].Value.LPSZ = m_pIdentityProps[XPID_NAME].Value.LPSZ;
- spvProps[i].ulPropTag = PR_RCVD_REPRESENTING_SEARCH_KEY;
- spvProps[i++].Value.bin = m_pIdentityProps[XPID_SEARCH_KEY].Value.bin;
- spvProps[i].ulPropTag = PR_RCVD_REPRESENTING_ADDRTYPE;
- spvProps[i++].Value.LPSZ = WINDS_ADDRESS_TYPE;
- spvProps[i].ulPropTag = PR_RCVD_REPRESENTING_EMAIL_ADDRESS;
- spvProps[i++].Value.LPSZ = m_szAddress;
-
- SYSTEMTIME st;
- FILETIME ftTime;
- GetSystemTime (&st);
- SystemTimeToFileTime (&st, &ftTime);
- spvProps[i].ulPropTag = PR_MESSAGE_DOWNLOAD_TIME;
- spvProps[i++].Value.ft = ftTime;
-
- LPMAPITABLE pTable;
- LPSRowSet pRows;
- BOOL fFoundCC, fFoundTO;
- fFoundCC = fFoundTO = FALSE;
- LPSPropValue pRecip;
- SPropValue spvFilter = { 0 };
- spvFilter.ulPropTag = PR_ADDRTYPE;
- spvFilter.Value.LPSZ = WINDS_ADDRESS_TYPE;
-
- SRestriction srRecips = { 0 };
- srRecips.rt = RES_PROPERTY;
- srRecips.res.resProperty.relop = RELOP_EQ;
- srRecips.res.resProperty.ulPropTag = PR_ADDRTYPE;
- srRecips.res.resProperty.lpProp = &spvFilter;
-
- hResult = pMsgObj->GetRecipientTable (fMapiUnicode, &pTable);
- if (!hResult)
- {
- hResult = HrQueryAllRows (pTable,
- (LPSPropTagArray)&sptMsgRecipProps,
- &srRecips,
- NULL,
- 0,
- &pRows);
- if (!hResult)
- {
- ASSERTMSG (pRows->cRows > 0, "Huh?, Zero rows?");
- for (ULONG ulIndex=0; ulIndex<pRows->cRows; ulIndex++)
- {
- pRecip = pRows->aRow[ulIndex].lpProps;
- ASSERTMSG (PR_EMAIL_ADDRESS == pRecip[0].ulPropTag, "Where is the PR_EMAIL_ADDRESS?");
- ASSERTMSG (PR_RECIPIENT_TYPE == pRecip[1].ulPropTag, , "Where is the PR_RECIPIENT_TYPE?");
- if (PR_EMAIL_ADDRESS == pRecip[0].ulPropTag)
- {
- // We use the address for the comparison because the sender might
- // have create a one-off to send us this message and the only thing that this
- // transport can count on being the same across all computers
- // is the email address. The display name is modifyable by the user.
- if (0 == lstrcmpi (pRecip[0].Value.LPSZ, m_szAddress))
- {
- if (PR_RECIPIENT_TYPE == pRecip[1].ulPropTag)
- {
- if (MAPI_TO == pRecip[1].Value.l)
- {
- fFoundTO = TRUE;
- }
- else
- {
- if (MAPI_CC == pRecip[1].Value.l)
- {
- fFoundCC = TRUE;
- }
- }
- }
- }
- }
- }
- FreeProws (pRows);
- }
- pTable->Release();
- }
- TraceResult ("CXPLogon::SetIncomingProps: Something went wrong setting PR_MESSAGE_xxx", hResult);
-
- if (!hResult)
- {
- spvProps[i].ulPropTag = PR_MESSAGE_TO_ME;
- spvProps[i++].Value.b = fFoundTO;
-
- spvProps[i].ulPropTag = PR_MESSAGE_CC_ME;
- spvProps[i++].Value.b = fFoundCC;
-
- spvProps[i].ulPropTag = PR_MESSAGE_RECIP_ME;
- spvProps[i++].Value.b = fFoundTO || fFoundCC;
- }
- ASSERT (i <= NUM_INCOMING_PROPS);
- hResult = pMsgObj->SetProps (i, spvProps, NULL);
- TraceResult ("CXPLogon::SetIncomingProps: Failed to set properties in the message", hResult);
- gpfnFreeBuffer(lpToBeFreed);
- if(pSenderEID)
- gpfnFreeBuffer(pSenderEID->Value.bin.lpb);
- gpfnFreeBuffer (pProps);
- gpfnFreeBuffer (pObjProps);
- return S_OK;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::GetMsgTempFileName()
- //
- // Parameters
- // pszFileName Pointer to a buffer allocated by the caller where the
- // function returns a fully qualified path and file for
- // a uniquely named temporary file.
- //
- // Purpose
- // This function creates a temporary file name. The file name will be
- // returned in the pszFileName buffer which must have been allocated by
- // the caller. The file will have a fully qualified path to its location.
- // The location of the file is on the TEMP directory, as set in the system,
- // and within it, in the directory for the downloads of the WINDS
- // message transport
- //
- // Return Value
- // TRUE if the function is successful at creating a temporary
- // unique file name. FALSE otherwise.
- //
- BOOL WINAPI CXPLogon::GetMsgTempFileName (LPTSTR pszFileName)
- {
- TCHAR szTmpDir[_MAX_PATH], szDownloadDir[_MAX_PATH];
- // Ask the system for the TEMP directory
- DWORD dwChars = GetTempPath (_MAX_PATH, szTmpDir);
- if (dwChars)
- {
- lstrcat (szTmpDir, WINDS_DATA_DIRECTORY);
- wsprintf (szDownloadDir, WINDS_DOWNLOAD_DIR_NAME_FORMAT, szTmpDir, m_UserInfo.szMailboxName);
- dwChars = ::GetTempFileName (szDownloadDir, // Call the Win32 API
- XP_MSG_FILE_PREFIX, // Our transport's fixed prefix for temp files
- 0, // Use the time to create a pseudo-random number
- pszFileName); // Destination buffer
- }
- if (!dwChars)
- {
- TraceResult ("CXPLogon::GetMsgTempFileName: Failed to get temp path or file name", GetLastError());
- }
- return (0 != dwChars ? TRUE : FALSE);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::CreateMsgHeaderTextLine()
- //
- // Parameters
- // pProps Array of properties of the message being
- // submitted where we get the information to create a
- // message header string to send to the server
- // pszBuffer Buffer where the function copies the formated data
- // for the server message header string
- // time Reference to a FILETIME structure with the time
- // the transport is delivering the message.
- //
- // Purpose
- // This function creates a string with the data needed in the server
- // side to update the remote server mailboxes message header file of
- // the recipients.
- //
- // Return Value
- // None
- //
- void WINAPI CXPLogon::CreateMsgHeaderTextLine (LPSPropValue pProps,
- LPTSTR pszBuffer,
- FILETIME & time)
- {
- // In case we don't find the properties in the array, we need
- // to supply default values for the strings. This method
- // should never fail.
- LPTSTR pszSubject = TEXT("<Subject Not Found>");
- LPTSTR pszMsgClass = TEXT("IPM.Note");
- TCHAR szDisplayTo[256] = { 0 };
-
- // In case we don't have the expected properties, assign default values.
- long lMsgFlags = 0;
- if (PR_MESSAGE_FLAGS == pProps[MSG_FLAGS].ulPropTag)
- {
- // Filter out the flags to only allow the ones listed
- lMsgFlags = pProps[MSG_FLAGS].Value.l & (MSGFLAG_UNMODIFIED |
- MSGFLAG_HASATTACH |
- MSGFLAG_FROMME |
- MSGFLAG_RESEND);
- }
- if (pProps[MSG_SIZE].ulPropTag != PR_MESSAGE_SIZE)
- {
- pProps[MSG_SIZE].Value.l = 1024; // Default to 1Kb
- }
- if (pProps[MSG_PRIORITY].ulPropTag != PR_PRIORITY)
- {
- pProps[MSG_PRIORITY].Value.l = PRIO_NORMAL;
- }
- if (pProps[MSG_IMPORTANCE].ulPropTag != PR_IMPORTANCE)
- {
- pProps[MSG_IMPORTANCE].Value.l = IMPORTANCE_NORMAL;
- }
- if (pProps[MSG_SENSITIVITY].ulPropTag != PR_SENSITIVITY)
- {
- pProps[MSG_SENSITIVITY].Value.l = SENSITIVITY_NONE;
- }
-
- // Get the string of TO recipients. If the string is too long, set the elipsis at the end of the buffer
- if (pProps[MSG_DISP_TO].ulPropTag == PR_DISPLAY_TO)
- {
- LPTSTR pszDisplayTo = pProps[MSG_DISP_TO].Value.LPSZ;
- if (lstrlen (pszDisplayTo) > 256)
- {
- pszDisplayTo[252] = '.'; // Copy the elipsis for a long string
- pszDisplayTo[253] = '.';
- pszDisplayTo[254] = '.';
- pszDisplayTo[255] = 0;
- }
- LPTSTR pszOneName = strtok (pszDisplayTo, ";");
- if (pszOneName)
- {
- pszOneName[lstrlen(pszOneName) - 1] = 0;
- lstrcpy (szDisplayTo, &pszOneName[1]);
- }
- while (pszOneName)
- {
- pszOneName = strtok (NULL, ";");
- if (pszOneName)
- {
- pszOneName[0] = TEXT(';');
- pszOneName[1] = TEXT(' ');
- pszOneName[lstrlen(pszOneName) - 1] = 0;
- lstrcat (szDisplayTo, pszOneName);
- }
- }
- }
- if (0 == szDisplayTo[0])
- {
- lstrcpy (szDisplayTo, TEXT("<Display To Names Not Found>"));
- }
- // Get the message class string.
- if (pProps[MSG_CLASS].ulPropTag == PR_MESSAGE_CLASS)
- {
- pszMsgClass = pProps[MSG_CLASS].Value.LPSZ;
- }
- // Get the subject. If the string is too long, set the elipsis at the end of the buffer
- if (pProps[MSG_SUBJECT].ulPropTag == PR_SUBJECT)
- {
- pszSubject = pProps[MSG_SUBJECT].Value.LPSZ;
- if (lstrlen (pszSubject) > 256)
- {
- pszSubject[252] = '.'; // Copy the elipsis for a long string
- pszSubject[253] = '.';
- pszSubject[254] = '.';
- pszSubject[255] = 0;
- }
- }
- // Write the properties into the buffer. This buffer is the header
- // information we send to the server The buffer passed in must hold
- // at least 1024 characters
- wsprintf (pszBuffer,
- // The string must end with a ',' (for the parsing logic
- // in the downloading of the headers)
- TEXT("%d,%s,%d,%s,%d,%s,%s,%d,%d,%d,%d,%d,%d,%d,"),
- lstrlen(m_UserInfo.szFullName),
- m_UserInfo.szFullName,
- lstrlen(szDisplayTo),
- szDisplayTo,
- lstrlen(pszSubject),
- pszSubject,
- pszMsgClass,
- lMsgFlags,
- pProps[MSG_SIZE].Value.l,
- pProps[MSG_PRIORITY].Value.l,
- pProps[MSG_IMPORTANCE].Value.l,
- pProps[MSG_SENSITIVITY].Value.l,
- time.dwLowDateTime,
- time.dwHighDateTime);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::IsValidAddress()
- //
- // Parameters
- // pszAddress The address of the recipient. This string gets
- // decomposed locally, so it can't be re-used by
- // the caller.
- // ppszServer Pointer to a location where the function returns
- // the remote server name
- // ppszMailbox Pointer to a location where the function returns
- // the remote user mailbox name
- //
- // Purpose
- // This functions takes the address of a recipient and makes sure it is
- // valid (as far as syntax) and decomposes the address into two
- // components: Remote server name and Remote user mailbox name. The
- // two component strings are returned to the caller.
- //
- // Return Value
- // TRUE if the address of the recipient is valid. FALSE otherwise.
- //
- BOOL WINAPI CXPLogon::IsValidAddress (LPTSTR pszAddress,
- LPTSTR * ppszServer,
- LPTSTR * ppszMailbox)
- {
- // Make sure that we can read the string
- if (!pszAddress || IsBadStringPtr (pszAddress, 32))
- {
- TraceMessage ("CXPLogon::IsValidAddress: Invalid string pointer");
- return FALSE;
- }
- DecomposeAddress (pszAddress, ppszServer, ppszMailbox);
- // Validate the names of the server and the mailbox
- if (!IsValidServerName (*ppszServer) || !*ppszMailbox)
- {
- TraceMessage ("CXPLogon::IsValidAddress: Invalid address for remote server host");
- return FALSE;
- }
- return TRUE;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::GrowAddressList()
- //
- // Parameters
- // ppAdrList Pointer to an address where the old address list
- // is and where the new resized address list will
- // be returned
- // ulResizeBy Number of new address entries to add to the list
- // pulOldAndNewCount Number of entries in the old address list. In
- // this parameter, upon sucessful return, will have
- // the number of in the new address list
- //
- // Purpose
- // In this function, given an address list with pulOldAndNewCount of
- // entries, we resize the address list to hold the old number of
- // entries plus the ulResizeBy entries. The old address list contents
- // are copied to the new list and the count reset. The memory for the
- // old address list is released here.
- //
- // Return Value
- // An HRESULT
- //
- STDMETHODIMP CXPLogon::GrowAddressList (LPADRLIST * ppAdrList,
- ULONG ulResizeBy,
- ULONG * pulOldAndNewCount)
- {
- LPADRLIST pNewAdrList;
- // Calculate how big the new buffer for the expanded address list should be
- ULONG cbSize = CbNewADRLIST ((*pulOldAndNewCount) + ulResizeBy);
- // Allocate the memory for it
- HRESULT hResult = gpfnAllocateBuffer (cbSize, (LPVOID *)&pNewAdrList);
- if (hResult)
- {
- // We can't continue
- TraceResult ("CXPLogon::GrowAddressList: Failed to allocate memory for resized address list", hResult);
- return hResult;
- }
-
- // Zero-out all memory for neatness
- ZeroMemory (pNewAdrList, cbSize);
-
- // If we had entries in the old address list, copy the memory from
- // the old addres list into the new expanded list
- if ((*pulOldAndNewCount))
- {
- CopyMemory (pNewAdrList, *ppAdrList, CbNewADRLIST ((*pulOldAndNewCount)));
- }
-
- // Set the number of entries in the new address list to the OLD size
- pNewAdrList->cEntries = (*pulOldAndNewCount);
-
- // We must return the number of available entries in the new expanded address list
- (*pulOldAndNewCount) += ulResizeBy;
-
- // Free the old memory and put the new pointer in place
- gpfnFreeBuffer (*ppAdrList);
- *ppAdrList = pNewAdrList;
- return hResult;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::CheckSpoolerYield()
- //
- // Parameters
- // fReset Resets the pseudo-timer
- //
- // Purpose
- // Enforce the 0.2 second rule for transport that need to yield to the
- // MAPI spooler. Called periodically while processing a message to
- // determine if we have used more than 0.2 seconds. If so, then call
- // SpoolerYield(), else just continue.
- // This is called with fReset set to TRUE when we first enter one
- // of the Transport Logon methods (usually one that is known to
- // take a long time like StartMessage() or SubmitMessage(). )
- //
- // Return Value
- // None.
- //
- void WINAPI CXPLogon::CheckSpoolerYield (BOOL fReset)
- {
- DWORD dwStop;
- static DWORD dwStart;
- if (fReset)
- {
- dwStart = GetTickCount();
- }
- else
- {
- dwStop = GetTickCount();
- if ((dwStop - dwStart) > 200) // 200 milliseconds
- {
- m_pSupObj->SpoolerYield (0);
- dwStart = GetTickCount();
- }
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::InitializeStatusRow()
- //
- // Parameters
- // ulFlags 0 if the properties are being created the first time.
- // MODIFY_FLAGS if a change is being made to the properties
- //
- // Purpose
- // To initialize or modify the status properties of a CXPLogon
- // object. This function allocates an array with NUM_STATUS_ROW_PROPS
- // properties and initializes them.
- //
- // Return Value
- // An HRESULT
- //
- STDMETHODIMP CXPLogon::InitializeStatusRow (ULONG ulFlags)
- {
- #define NUM_STATUS_ROW_PROPS 10
- SPropValue spvStatusRow[NUM_STATUS_ROW_PROPS] = { 0 };
- ULONG i = 0;
-
- ///////////////////////////////////////////////////////////////////////////
- // Set the PR_PROVIDER_DISPLAY property: The transport readable name
- spvStatusRow[i].ulPropTag = PR_PROVIDER_DISPLAY;
- spvStatusRow[i++].Value.LPSZ = TRANSPORT_DISPLAY_NAME_STRING;
-
- ///////////////////////////////////////////////////////////////////////////
- // Set the PR_RESOURCE_METHODS property. These are the methods implemented
- // in the our IMAPIStatus implementation (CMAPIStatus class.)
- spvStatusRow[i].ulPropTag = PR_RESOURCE_METHODS;
- // we support ALL the methods in our implementation of IMAPIStatus interface (except the WRITABLE ones)
- spvStatusRow[i++].Value.l = STATUS_SETTINGS_DIALOG |
- STATUS_FLUSH_QUEUES |
- STATUS_VALIDATE_STATE |
- STATUS_CHANGE_PASSWORD;
-
- ///////////////////////////////////////////////////////////////////////////
- // Set the PR_STATUS_CODE property.
- spvStatusRow[i].ulPropTag = PR_STATUS_CODE;
- spvStatusRow[i++].Value.l = GetTransportStatusCode();
-
- ///////////////////////////////////////////////////////////////////////////
- // Set the PR_STATUS_STRING property
- TCHAR szStatus[64];
- LoadStatusString (szStatus, sizeof(szStatus));
- spvStatusRow[i].ulPropTag = PR_STATUS_STRING;
- spvStatusRow[i++].Value.LPSZ = szStatus;
-
- ///////////////////////////////////////////////////////////////////////////
- // Set the PR_DISPLAY_NAME property
- TCHAR szDisplayName[64];
- wsprintf (szDisplayName, TEXT("%s (%s)"), TRANSPORT_DISPLAY_NAME_STRING, m_szServer);
- spvStatusRow[i].ulPropTag = PR_DISPLAY_NAME;
- spvStatusRow[i++].Value.LPSZ = szDisplayName;
-
- ///////////////////////////////////////////////////////////////////////////
- // Set the PR_IDENTITY_ENTRYID property
- spvStatusRow[i].ulPropTag = PR_IDENTITY_ENTRYID;
- spvStatusRow[i++].Value = m_pIdentityProps[XPID_EID].Value;
-
- ///////////////////////////////////////////////////////////////////////////
- // Set the PR_IDENTITY_DISPLAY property
- spvStatusRow[i].ulPropTag = PR_IDENTITY_DISPLAY;
- spvStatusRow[i++].Value.LPSZ = m_pIdentityProps[XPID_NAME].Value.LPSZ;
-
- ///////////////////////////////////////////////////////////////////////////
- // Set the PR_IDENTITY_SEARCH_KEY property
- spvStatusRow[i].ulPropTag = PR_IDENTITY_SEARCH_KEY;
- spvStatusRow[i++].Value = m_pIdentityProps[XPID_SEARCH_KEY].Value;
-
- ///////////////////////////////////////////////////////////////////////////
- // Set the PR_REMOTE_PROGRESS property
- spvStatusRow[i].ulPropTag = PR_REMOTE_PROGRESS;
- spvStatusRow[i++].Value.l = -1; // Not initialized
-
- ///////////////////////////////////////////////////////////////////////////
- // Set the PR_REMOTE_VALIDATE_OK property
- spvStatusRow[i].ulPropTag = PR_REMOTE_VALIDATE_OK;
- spvStatusRow[i++].Value.b = TRUE;
- ASSERT (NUM_STATUS_ROW_PROPS == i);
-
- // Write the entries on the provider's session status row
- HRESULT hResult = m_pSupObj->ModifyStatusRow (i, spvStatusRow, ulFlags);
- TraceResult ("CXPLogon::InitializeStatusRow: Failed to modify the status row", hResult);
- return hResult;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::CheckForUnfinishedDownloads()
- //
- // Parameters
- // None.
- //
- // Purpose
- // This function checks to see if we have files where downloaded messages
- // were lefted from a previous session or from a previous failed download
- // sequence. The message files, if any, should be in the data directory of
- // this service. If any files are found, the message queue is loaded and
- // the during out inbound logic initialization in
- // IXPLogon::TransportNotify(), we check the queue. If the queue is not
- // empty, we tell the transport to flush our inbound flush.
- //
- // Return Value
- // None.
- //
- void WINAPI CXPLogon::CheckForUnfinishedDownloads()
- {
- WIN32_FIND_DATA wfdFile = { 0 };
- TCHAR szTmpDir[_MAX_PATH], szDownloadDir[_MAX_PATH], szSearchMask[512];
- GetTempPath (_MAX_PATH, szTmpDir);
- lstrcat (szTmpDir, WINDS_DATA_DIRECTORY);
- wsprintf (szDownloadDir, WINDS_DOWNLOAD_DIR_NAME_FORMAT, szTmpDir, m_UserInfo.szMailboxName);
- wsprintf (szSearchMask, TEXT("%s\\%s*.%s"), szDownloadDir, XP_MSG_FILE_PREFIX, XP_MSG_FILE_SUFFIX);
- HANDLE hSearch = FindFirstFile (szSearchMask, &wfdFile);
- if (hSearch == INVALID_HANDLE_VALUE)
- {
- return;
- }
- BOOL fFound = TRUE;
- while (fFound)
- {
- wsprintf (szTmpDir, TEXT("%s\\%s"), szDownloadDir, wfdFile.cFileName);
- // If the file size of 0, then is probably some garbage file. Get rid of it.
- // A zero-sized file does not contains a message.
- if (0 == wfdFile.nFileSizeHigh && 0 == wfdFile.nFileSizeLow)
- {
- DeleteFile (szTmpDir);
- }
- else
- {
- m_List.QueuePendingMsgFile (szTmpDir);
- }
- fFound = FindNextFile (hSearch, &wfdFile);
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::DownloadMessageHeaders()
- //
- // Parameters
- // None
- //
- // Purpose
- // This function downloads the message headers for the user's mailbox and
- // is a remote folder is available, re-load the contents table of the
- // folder with the new message headers information.
- //
- // Return Value
- // An HRESULT
- //
- STDMETHODIMP CXPLogon::DownloadMessageHeaders()
- {
- // Guard against re-entrancy from the timer call back which happens on a separate thread
- UpdateProgress (0, REMOTE_ACTION_HEADER_REFRESH); // Start the progress bar
- HRESULT hResult = GetHeadersFromServer (m_szServer,
- m_UserInfo.szMailboxName,
- m_szHeaders);
- UpdateProgress (50, REMOTE_ACTION_HEADER_REFRESH); // Half way through
- if (!hResult && m_pStatusObj && m_pStatusObj->m_pHeaderFolder)
- {
- hResult = m_pStatusObj->m_pHeaderFolder->FillContentsTable (m_szHeaders);
- }
- UpdateProgress (100, REMOTE_ACTION_HEADER_REFRESH); // Finish
- TraceResult ("CXPLogon::DownloadMessageHeaders", hResult);
- return hResult;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::EmptyInboundQueue()
- //
- // Parameters
- // None
- //
- // Purpose
- // Deletes all the node in the queue of downloaded messages, deleting
- // the used memory and closing the handle to the local temporary
- // message file.
- //
- // Return Value
- // None
- //
- void WINAPI CXPLogon::EmptyInboundQueue()
- {
- // If we have nodes at this point, is because the transport could not
- // process them at this time. They will be retrieved in the next time this
- // transport comes on line on the same profile or on a profile that has
- // the same user identity.
- PLIST_NODE pNode = m_List.GetDownloadNode();
- while (pNode)
- {
- CloseHandle (pNode->hFile);
- delete pNode;
- // If the list is empty, pNode will be NULL.
- // CList::GetDownloadNode() returns NULL for an empty list.
- pNode = m_List.GetDownloadNode();
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // TimerWndProc()
- //
- // Parameters
- // { Refer to Win32 documentation }
- //
- // Purpose
- // Stub window procedure for the hidden timer window class.
- //
- // Return Value
- // Default value return by the default window procedure
- //
- LRESULT CALLBACK TimerWndProc (HWND hWnd,
- UINT message,
- WPARAM wParam,
- LPARAM lParam)
- {
- return DefWindowProc(hWnd, message, wParam, lParam);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::InitializeTimer()
- //
- // Parameters
- // None.
- //
- // Purpose
- // Initialize the hidden window for the upload timer.
- //
- // Return Value
- // None.
- //
- void WINAPI CXPLogon::InitializeTimer()
- {
- WNDCLASS wc = { 0 };
- // Register the class for this application
- wc.lpfnWndProc = TimerWndProc;
- wc.hInstance = m_hInstance;
- wc.lpszClassName = TIMER_WND_CLASS;
- if (!RegisterClass (&wc))
- {
- TraceResult ("InitializeTimer: Failed to register the timer window class", GetLastError());
- return;
- }
- m_hTimerWnd = CreateWindow (TIMER_WND_CLASS,
- NULL,
- WS_OVERLAPPEDWINDOW,
- 0, 0, 0, 0,
- NULL,
- NULL,
- m_hInstance,
- NULL);
- if (NULL == m_hTimerWnd)
- {
- TraceResult ("InitializeTimer: Failed to create timer window", GetLastError());
- return;
- }
- SetWindowLong (m_hTimerWnd, GWL_USERDATA, (LONG)this);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::StartUploadTimer()
- //
- // Parameters
- // None.
- //
- // Purpose
- // This function sets a timer with the operating system. When
- // the specified period elapses, we will get called in the procedure
- // specified and we will then flush the incoming and outgoing queues.
- // Note that we round the delivery time to the HOUR
- //
- // Return Value
- // None.
- //
- void WINAPI CXPLogon::StartUploadTimer()
- {
- SYSTEMTIME stNow = { 0 };
- GetLocalTime (&stNow);
- WORD wUploadHour = m_stDelivTime.wHour;
- // If the time is 0:00, this is 12:00 AM midnight
- if (!wUploadHour)
- {
- wUploadHour = 24;
- }
- UINT uDelay = 0;
- // How many hours before the next upload?
- int nHours = wUploadHour - stNow.wHour;
- if (nHours <= 0)
- {
- // If the hours is 0 and the time hasn't arrived with in this hour,
- // set the upload timer for THIS hour.
- if (0 == nHours && stNow.wMinute < m_stDelivTime.wMinute)
- {
- nHours = -24;
- uDelay += (UINT)(m_stDelivTime.wMinute - stNow.wMinute) * 60 * 1000;
- }
- nHours += 24;
- }
- uDelay += (UINT)nHours * 60 * 60 * 1000; // Number of milliseconds in the hours
- m_uTimerID = SetTimer (m_hTimerWnd, 0, uDelay, UploadTimerProc);
- if (0 == m_uTimerID)
- {
- TraceResult ("CXPLogon::StartUploadTimer: Failed to set the timer", GetLastError());
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // CXPLogon::StopUploadTimer()
- //
- // Parameters
- // None.
- //
- // Purpose
- // Terminates the timer used for the upload time.
- //
- // Return Value
- // None
- //
- void WINAPI CXPLogon::StopUploadTimer()
- {
- // If we have a timer around, terminate it and all its associated resources
- if (m_uTimerID)
- {
- KillTimer (m_hTimerWnd, m_uTimerID);
- DestroyWindow (m_hTimerWnd);
- UnregisterClass (TIMER_WND_CLASS, m_hInstance);
- m_hTimerWnd = NULL;
- m_uTimerID = 0;
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // UploadTimerProc()
- //
- // Parameters
- // { Refer to the Win32 TIMERPROC callback parameters }
- //
- // Purpose
- // This function executes when the timer delay has expired.
- // Now we ask the spooler to send us the deferred messages, and we set
- // the transport state ready to receive updated headers.
- //
- // Return Value
- // None
- //
- void CALLBACK UploadTimerProc (HWND hTimerWnd,
- UINT Message,
- UINT idEvent,
- DWORD dwTime)
- {
- KillTimer (hTimerWnd, idEvent);
- // We asked to get the CXPLogon object who set the timer. We now
- // check and see if the object is valid before we attempt to use it.
- CXPLogon * pLogon = (CXPLogon *)GetWindowLong (hTimerWnd, GWL_USERDATA);
- if (!pLogon ||
- IsBadWritePtr (pLogon, sizeof(CXPLogon)) ||
- IsBadReadPtr (pLogon, sizeof(CXPLogon)))
- {
- TraceMessage ("UploadTimerProc: We got a bogus logon object");
- return;
- }
- pLogon->m_uTimerID = 0;
-
- // If the transport's outgoing logic has been activated in this session,
- // send all the deferred messages, by flushing the transport.
- if (pLogon->GetTransportStatusCode() & STATUS_OUTBOUND_ENABLED)
- {
- pLogon->AddStatusBits (UPLOADING_MESSAGES);
- }
- // If the transport's incoming logic has been activated in this session,
- // get any pending messages that need to be placed in the default inbox,
- // and set the transport state, ready to get the headers from the server..
- if (pLogon->GetTransportStatusCode() & STATUS_INBOUND_ENABLED)
- {
- pLogon->AddStatusBits (DOWNLOADING_MESSAGES);
- pLogon->SetTransportState (PROCESSING_TIMER_EVENT);
- }
- // Modify the status row now
- pLogon->UpdateStatus();
- // Reset the time for the next upload. Uploading time is a recurring event.
- pLogon->StartUploadTimer();
- }
-
- // End of file for XPLOGON.CPP
-