diff --git a/mailnews/absync/public/nsIAbSync.idl b/mailnews/absync/public/nsIAbSync.idl index eed56b6e004..58dab9ca063 100644 --- a/mailnews/absync/public/nsIAbSync.idl +++ b/mailnews/absync/public/nsIAbSync.idl @@ -47,4 +47,5 @@ interface nsIAbSync : nsISupports { * will be sent along with all sync listener operations */ void PerformAbSync(out PRInt32 aTransactionID); + void CancelAbSync(); }; diff --git a/mailnews/absync/public/nsIAbSyncDriver.idl b/mailnews/absync/public/nsIAbSyncDriver.idl index cde0107fa57..85ffe135713 100644 --- a/mailnews/absync/public/nsIAbSyncDriver.idl +++ b/mailnews/absync/public/nsIAbSyncDriver.idl @@ -28,5 +28,6 @@ interface nsIAbSyncDriver : nsIAbSyncListener { void KickIt(in nsIMsgStatusFeedback aStatus); + void CancelIt(); }; diff --git a/mailnews/absync/public/nsIAbSyncMojo.idl b/mailnews/absync/public/nsIAbSyncMojo.idl index 9ee4936b024..847056fc4e0 100644 --- a/mailnews/absync/public/nsIAbSyncMojo.idl +++ b/mailnews/absync/public/nsIAbSyncMojo.idl @@ -36,6 +36,7 @@ interface nsIAbSyncMojo : nsISupports { /* * This is the primary interface for performing AB Sync mojo operations */ + string BuildMojoString(); void StartAbSyncMojo(in nsIStreamListener aListener); - void GetAbSyncMojoResults(out string aMojoString); + void GetAbSyncMojoResults(out string aMojoUser, out string aMojoString); }; diff --git a/mailnews/absync/public/nsIAbSyncPostEngine.idl b/mailnews/absync/public/nsIAbSyncPostEngine.idl index 8fdd14709fd..4bb13e62ae9 100644 --- a/mailnews/absync/public/nsIAbSyncPostEngine.idl +++ b/mailnews/absync/public/nsIAbSyncPostEngine.idl @@ -42,11 +42,18 @@ interface nsIAbSyncPostEngine : nsISupports { void RemovePostListener(in nsIAbSyncPostListener aListener); /* Get the nsIAbSyncPostEngineState of the sync operation */ + string BuildMojoString(); PRInt32 GetCurrentState(); + void GetMojoUserAndSnack(out string aMojoUser, out string aMojoSnack); /* * Send the protocol request and get a transaction ID in return that * will be sent along with all sync listener operations */ void SendAbRequest(in string aSpec, in PRInt32 aPort, in string aProtocolRequest, in PRInt32 aTransactionID); + + /* + * Cancel it! + */ + void CancelAbSync(); }; diff --git a/mailnews/absync/src/nsABSyncDriver.cpp b/mailnews/absync/src/nsABSyncDriver.cpp index 8902ed18e6b..f8ca8aa8c79 100644 --- a/mailnews/absync/src/nsABSyncDriver.cpp +++ b/mailnews/absync/src/nsABSyncDriver.cpp @@ -235,3 +235,22 @@ nsAbSyncDriver::GetString(const PRUnichar *aStringName) return nsCRT::strdup(aStringName); } +// +// What if we want to stop the operation? Call this! +// +NS_IMETHODIMP nsAbSyncDriver::CancelIt() +{ + nsresult rv = NS_OK; + PRInt32 stateVar; + + NS_WITH_SERVICE(nsIAbSync, sync, kAbSync, &rv); + if (NS_FAILED(rv) || !sync) + return rv; + + sync->GetCurrentState(&stateVar); + if (stateVar == nsIAbSyncState::nsIAbSyncIdle) + return NS_ERROR_FAILURE; + + // Cancel this mess... + return sync->CancelAbSync(); +} diff --git a/mailnews/absync/src/nsAbSync.cpp b/mailnews/absync/src/nsAbSync.cpp index f56971982ee..895215fd864 100644 --- a/mailnews/absync/src/nsAbSync.cpp +++ b/mailnews/absync/src/nsAbSync.cpp @@ -501,6 +501,15 @@ NS_IMETHODIMP nsAbSync::GetCurrentState(PRInt32 *_retval) return NS_OK; } +/* void PerformAbSync (out PRInt32 aTransactionID); */ +NS_IMETHODIMP nsAbSync::CancelAbSync() +{ + if (!mPostEngine) + return NS_ERROR_FAILURE; + + return mPostEngine->CancelAbSync(); +} + /* void PerformAbSync (out PRInt32 aTransactionID); */ NS_IMETHODIMP nsAbSync::PerformAbSync(PRInt32 *aTransactionID) { @@ -508,6 +517,7 @@ NS_IMETHODIMP nsAbSync::PerformAbSync(PRInt32 *aTransactionID) char *postSpec = nsnull; char *protocolRequest = nsnull; char *prefixStr = nsnull; + char *clientIDStr = nsnull; // If we are already running...don't let anything new start... if (mCurrentState != nsIAbSyncState::nsIAbSyncIdle) @@ -594,13 +604,19 @@ NS_IMETHODIMP nsAbSync::PerformAbSync(PRInt32 *aTransactionID) mPostEngine->AddPostListener((nsIAbSyncPostListener *)this); } - // Ok, add the header to this protocol string information... + rv = mPostEngine->BuildMojoString(&clientIDStr); + if (NS_FAILED(rv) || (!clientIDStr)) + goto EarlyExit; + if (mPostString.IsEmpty()) - prefixStr = PR_smprintf("last=%u&protocol=%d&client=2&ver=%s", - mLastChangeNum, ABSYNC_PROTOCOL, ABSYNC_VERSION); + prefixStr = PR_smprintf("last=%u&protocol=%d&client=%s&ver=%s", + mLastChangeNum, ABSYNC_PROTOCOL, + clientIDStr, ABSYNC_VERSION); else - prefixStr = PR_smprintf("last=%u&protocol=%d&client=2&ver=%s&", - mLastChangeNum, ABSYNC_PROTOCOL, ABSYNC_VERSION); + prefixStr = PR_smprintf("last=%u&protocol=%d&client=%s&ver=%s&", + mLastChangeNum, ABSYNC_PROTOCOL, + clientIDStr, ABSYNC_VERSION); + if (!prefixStr) { rv = NS_ERROR_OUT_OF_MEMORY; @@ -630,6 +646,7 @@ NS_IMETHODIMP nsAbSync::PerformAbSync(PRInt32 *aTransactionID) EarlyExit: PR_FREEIF(protocolRequest); PR_FREEIF(postSpec); + PR_FREEIF(clientIDStr); if (NS_FAILED(rv)) InternalCleanup(); diff --git a/mailnews/absync/src/nsAbSyncPostEngine.cpp b/mailnews/absync/src/nsAbSyncPostEngine.cpp index f7242ad6bc2..ec7750f4a97 100644 --- a/mailnews/absync/src/nsAbSyncPostEngine.cpp +++ b/mailnews/absync/src/nsAbSyncPostEngine.cpp @@ -100,8 +100,11 @@ nsAbSyncPostEngine::nsAbSyncPostEngine() mMessageSize = 0; mAuthenticationRunning = PR_TRUE; mCookie = nsnull; + mUser = nsnull; mSyncSpec = nsnull; mSyncProtocolRequest = nsnull; + mSyncProtocolRequestPrefix = nsnull; + mChannel = nsnull; } nsAbSyncPostEngine::~nsAbSyncPostEngine() @@ -111,11 +114,178 @@ nsAbSyncPostEngine::~nsAbSyncPostEngine() PR_FREEIF(mCharset); PR_FREEIF(mSyncProtocolRequest); + PR_FREEIF(mSyncProtocolRequestPrefix); PR_FREEIF(mCookie); + PR_FREEIF(mUser); PR_FREEIF(mSyncSpec); DeleteListeners(); } +PRInt32 Base64Decode_int(const char *in_str, unsigned char *out_str, + PRUint32& decoded_len); +/* ================================================================== + * Base64Encode + * + * Returns number of bytes that were encoded. + * + * >0 -> OK + * -1 -> BAD (output buffer not big enough). + * + * ================================================================== + */ +PRInt32 Base64Encode(const unsigned char *in_str, PRInt32 in_len, char *out_str, + PRInt32 out_len) +{ + static unsigned char base64[] = + { + /* 0 1 2 3 4 5 6 7 */ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', /* 0 */ + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 1 */ + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', /* 2 */ + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', /* 3 */ + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 4 */ + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', /* 5 */ + 'w', 'x', 'y', 'z', '0', '1', '2', '3', /* 6 */ + '4', '5', '6', '7', '8', '9', '+', '/' /* 7 */ + }; + PRInt32 curr_out_len = 0; + + PRInt32 i = 0; + unsigned char a, b, c; + + out_str[0] = '\0'; + + if (in_len > 0) + { + + while (i < in_len) + { + a = in_str[i]; + b = (i + 1 >= in_len) ? 0 : in_str[i + 1]; + c = (i + 2 >= in_len) ? 0 : in_str[i + 2]; + + if (i + 2 < in_len) + { + out_str[curr_out_len++] = (base64[(a >> 2) & 0x3F]); + out_str[curr_out_len++] = (base64[((a << 4) & 0x30) + + ((b >> 4) & 0xf)]); + out_str[curr_out_len++] = (base64[((b << 2) & 0x3c) + + ((c >> 6) & 0x3)]); + out_str[curr_out_len++] = (base64[c & 0x3F]); + } + else if (i + 1 < in_len) + { + out_str[curr_out_len++] = (base64[(a >> 2) & 0x3F]); + out_str[curr_out_len++] = (base64[((a << 4) & 0x30) + + ((b >> 4) & 0xf)]); + out_str[curr_out_len++] = (base64[((b << 2) & 0x3c) + + ((c >> 6) & 0x3)]); + out_str[curr_out_len++] = '='; + } + else + { + out_str[curr_out_len++] = (base64[(a >> 2) & 0x3F]); + out_str[curr_out_len++] = (base64[((a << 4) & 0x30) + + ((b >> 4) & 0xf)]); + out_str[curr_out_len++] = '='; + out_str[curr_out_len++] = '='; + } + + i += 3; + + if((curr_out_len + 4) > out_len) + { + return(-1); + } + + } + out_str[curr_out_len] = '\0'; + } + + return curr_out_len; +} + +/* + * This routine decodes base64 string to a buffer. + * Populates 'out_str' with b64 decoded data. + * + * Returns number of bytes that were decoded. + * >0 -> OK + * -1 -> BAD (output buffer not big enough). + */ +PRInt32 Base64Decode(const char *in_str, unsigned char *out_str, + PRUint32* decoded_len) +{ + return Base64Decode_int(in_str, out_str, *decoded_len); +} + +PRInt32 Base64Decode_int(const char *in_str, unsigned char *out_str, + PRUint32& decoded_len) +{ + PRInt32 in_len = strlen (/*(char *)*/ in_str); + PRInt32 ii = 0; + PRInt32 a = 0; + char ch; + PRInt32 b1 = 0; + long b4 = 0; + PRInt32 nn = 0; + + /* Decode remainder of base 64 string */ + + while (ii < in_len) + { + ch = in_str[ii++]; + if (ch >= 'A' && ch <= 'Z') b1 = (ch - 'A'); + else if (ch >= 'a' && ch <= 'z') b1 = 26 + (ch - 'a'); + else if (ch >= '0' && ch <= '9') b1 = 52 + (ch - '0'); + else if (ch == '+') b1 = 62; + else if (ch == '/') b1 = 63; + else if (ch == '\r' || ch == '\n') continue; + else + { + if (ch == '=') + { + if (nn == 3) + { + if ((a + 2) > (PRInt32) decoded_len) + return (-1); /* Bail. Buffer overflow */ + b4 = (b4 << 6); + out_str[a++] = (char) (0xff & (b4 >> 16)); + out_str[a++] = (char) (0xff & (b4 >> 8)); + } + else if (nn == 2) + { + if ((a + 1) > (PRInt32) decoded_len) + { + return (-1); /* Bail. Buffer overflow */ + } + b4 = (b4 << 12); + out_str[a++] = (char) (0xff & (b4 >> 16)); + } + } + break; + } + b4 = (b4 << 6) | (long) b1; + nn++; + if (nn == 4) + { + if ((a + 3) > (PRInt32) decoded_len) + { + return (-1); /* Bail. Buffer overflow */ + } + out_str[a++] = (char) (0xff & (b4 >> 16)); + out_str[a++] = (char) (0xff & (b4 >> 8)); + out_str[a++] = (char) (0xff & (b4)); + nn = 0; + } + } + + out_str[a] = '\0'; + decoded_len = a; + + return (a); +} + NS_IMETHODIMP nsAbSyncPostEngine::GetInterface(const nsIID & aIID, void * *aInstancePtr) { NS_ENSURE_ARG_POINTER(aInstancePtr); @@ -296,12 +466,47 @@ nsAbSyncPostEngine::OnStopRequest(nsIChannel *aChannel, nsISupports * /* ctxt */ if (mAuthenticationRunning) { + nsresult rv; if (mSyncMojo) - mSyncMojo->GetAbSyncMojoResults(&mCookie); + rv = mSyncMojo->GetAbSyncMojoResults(&mUser, &mCookie); + + if (NS_SUCCEEDED(rv)) + { + // Base64 encode then url encode it... + // + char tUser[256] = ""; + + if (Base64Encode((unsigned char *)mUser, nsCRT::strlen(mUser), tUser, sizeof(tUser)) < 0) + { + rv = NS_ERROR_FAILURE; + NotifyListenersOnStopAuthOperation(rv, aMsg, tProtResponse); + NotifyListenersOnStopSending(mTransactionID, rv, nsnull, nsnull); + } + else + { + char *tUser2 = nsEscape(tUser, url_Path); + if (!tUser2) + { + rv = NS_ERROR_FAILURE; + NotifyListenersOnStopAuthOperation(rv, aMsg, tProtResponse); + NotifyListenersOnStopSending(mTransactionID, rv, nsnull, nsnull); + } + else + { + mSyncProtocolRequestPrefix = PR_smprintf("cn=%s&cc=%s&", tUser2, mCookie); + PR_FREEIF(tUser2); + NotifyListenersOnStopAuthOperation(aStatus, aMsg, tProtResponse); + KickTheSyncOperation(); + } + } + } + else + { + NotifyListenersOnStopAuthOperation(rv, aMsg, tProtResponse); + NotifyListenersOnStopSending(mTransactionID, rv, nsnull, nsnull); + } mSyncMojo = nsnull; - NotifyListenersOnStopAuthOperation(aStatus, aMsg, tProtResponse); - KickTheSyncOperation(); } else { @@ -469,14 +674,13 @@ nsAbSyncPostEngine::FireURLRequest(nsIURI *aURL, const char *postData) if (!postData) return NS_ERROR_INVALID_ARG; - nsCOMPtr channel; - NS_ENSURE_SUCCESS(NS_OpenURI(getter_AddRefs(channel), aURL, nsnull), NS_ERROR_FAILURE); + NS_ENSURE_SUCCESS(NS_OpenURI(getter_AddRefs(mChannel), aURL, nsnull), NS_ERROR_FAILURE); // Tag the post stream onto the channel...but never seemed to work...so putting it // directly on the URL spec // nsCOMPtr method = NS_NewAtom ("POST"); - nsCOMPtr httpChannel = do_QueryInterface(channel); + nsCOMPtr httpChannel = do_QueryInterface(mChannel); if (!httpChannel) return NS_ERROR_FAILURE; @@ -501,18 +705,42 @@ NS_IMETHODIMP nsAbSyncPostEngine::GetCurrentState(PRInt32 *_retval) // This is the implementation of the actual post driver. // //////////////////////////////////////////////////////////////////////////////////////// -NS_IMETHODIMP nsAbSyncPostEngine::SendAbRequest(const char *aSpec, PRInt32 aPort, const char *aProtocolRequest, PRInt32 aTransactionID) +NS_IMETHODIMP nsAbSyncPostEngine::BuildMojoString(char **aID) { nsresult rv; + if (!aID) + return NS_ERROR_FAILURE; + + // Now, get the COMPtr to the Mojo! + if (!mSyncMojo) + { + rv = nsComponentManager::CreateInstance(kCAbSyncMojoCID, NULL, NS_GET_IID(nsIAbSyncMojo), getter_AddRefs(mSyncMojo)); + if ( NS_FAILED(rv) || (!mSyncMojo) ) + return NS_ERROR_FAILURE; + } + + rv = mSyncMojo->BuildMojoString(aID); + return rv; +} + +NS_IMETHODIMP nsAbSyncPostEngine::SendAbRequest(const char *aSpec, PRInt32 aPort, const char *aProtocolRequest, PRInt32 aTransactionID) +{ + nsresult rv; + char *mojoUser = nsnull; + char *mojoSnack = nsnull; + // Only try if we are not currently busy! if (mPostEngineState != nsIAbSyncPostEngineState::nsIAbSyncPostIdle) return NS_ERROR_FAILURE; // Now, get the COMPtr to the Mojo! - rv = nsComponentManager::CreateInstance(kCAbSyncMojoCID, NULL, NS_GET_IID(nsIAbSyncMojo), getter_AddRefs(mSyncMojo)); - if ( NS_FAILED(rv) || (!mSyncMojo) ) - return NS_ERROR_FAILURE; + if (!mSyncMojo) + { + rv = nsComponentManager::CreateInstance(kCAbSyncMojoCID, NULL, NS_GET_IID(nsIAbSyncMojo), getter_AddRefs(mSyncMojo)); + if ( NS_FAILED(rv) || (!mSyncMojo) ) + return NS_ERROR_FAILURE; + } if (NS_FAILED(mSyncMojo->StartAbSyncMojo(this))) return NS_ERROR_FAILURE; @@ -528,7 +756,7 @@ NS_IMETHODIMP nsAbSyncPostEngine::SendAbRequest(const char *aSpec, PRInt32 aPort mSyncProtocolRequest = nsCRT::strdup(aProtocolRequest); mProtocolResponse = NS_ConvertASCIItoUCS2(""); mTotalWritten = 0; - + // The first thing we need to do is authentication so do it! mAuthenticationRunning = PR_TRUE; mPostEngineState = nsIAbSyncPostEngineState::nsIAbSyncAuthenticationRunning; @@ -540,6 +768,7 @@ nsAbSyncPostEngine::KickTheSyncOperation(void) { nsresult rv; nsIURI *workURI = nsnull; + char *protString = nsnull; // The first thing we need to do is authentication so do it! mAuthenticationRunning = PR_FALSE; @@ -547,12 +776,14 @@ nsAbSyncPostEngine::KickTheSyncOperation(void) mPostEngineState = nsIAbSyncPostEngineState::nsIAbSyncPostRunning; char *postHeader = "Content-Type: application/x-www-form-urlencoded\r\nContent-Length: %d\r\nCookie: %s\r\n\r\n%s"; - if (mSyncProtocolRequest) - mMessageSize = nsCRT::strlen(mSyncProtocolRequest); + protString = PR_smprintf("%s%s", mSyncProtocolRequestPrefix, mSyncProtocolRequest); + if (protString) + mMessageSize = nsCRT::strlen(protString); else mMessageSize = 0; - char *tCommand = PR_smprintf(postHeader, mMessageSize, mCookie, mSyncProtocolRequest); + char *tCommand = PR_smprintf(postHeader, mMessageSize, mCookie, protString); + PR_FREEIF(protString); #ifdef DEBUG_rhp printf("COMMAND = %s\n", tCommand); @@ -586,3 +817,29 @@ GetOuttaHere: return rv; } +NS_IMETHODIMP +nsAbSyncPostEngine::CancelAbSync() +{ + nsresult rv = NS_ERROR_FAILURE; + + nsCOMPtr httpChannel = do_QueryInterface(mChannel); + if (httpChannel) + rv = httpChannel->Cancel(NS_BINDING_ABORTED); + + return rv; +} + +NS_IMETHODIMP +nsAbSyncPostEngine::GetMojoUserAndSnack(char **aMojoUser, char **aMojoSnack) +{ + if ( (!mUser) || (!mCookie) ) + return NS_ERROR_FAILURE; + + *aMojoUser = nsCRT::strdup(mUser); + *aMojoSnack = nsCRT::strdup(mCookie); + + if ( (!*aMojoUser) || (!*aMojoSnack) ) + return NS_ERROR_FAILURE; + else + return NS_OK; +} diff --git a/mailnews/absync/src/nsAbSyncPostEngine.h b/mailnews/absync/src/nsAbSyncPostEngine.h index be4abab19b4..4fa6d64da6b 100644 --- a/mailnews/absync/src/nsAbSyncPostEngine.h +++ b/mailnews/absync/src/nsAbSyncPostEngine.h @@ -32,6 +32,7 @@ #include "nsIURIContentListener.h" #include "nsIURI.h" #include "nsIAbSyncMojo.h" +#include "nsIChannel.h" // // Callback declarations for URL completion @@ -96,6 +97,7 @@ private: nsCOMPtr mLoadCookie; // load cookie used by the uri loader when we post the url char *mCookie; + char *mUser; char *mAuthSpec; PRInt32 mMessageSize; // Size of POST request... @@ -108,8 +110,10 @@ private: nsCOMPtr mSyncMojo; char *mSyncSpec; PRInt32 mSyncPort; + nsCOMPtr mChannel; char *mSyncProtocolRequest; + char *mSyncProtocolRequestPrefix; }; #endif /* nsAbSyncPostEngine_h_ */ diff --git a/mailnews/imap/public/nsIMsgLogonRedirector.idl b/mailnews/imap/public/nsIMsgLogonRedirector.idl index c44874a479f..cc73e7be639 100644 --- a/mailnews/imap/public/nsIMsgLogonRedirector.idl +++ b/mailnews/imap/public/nsIMsgLogonRedirector.idl @@ -19,6 +19,7 @@ interface nsMsgLogonRedirectionServiceIDs { const long Imap = 0; const long Smtp = 1; + const long AbSync = 2; }; [scriptable, uuid(3c882b66-df4f-11d3-b9f9-00108335942a)]