367 lines
9.7 KiB
C++
367 lines
9.7 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
|
|
#include "nsIBlockingNotification.h"
|
|
#include "nsIURL.h"
|
|
#include "nsIWebShell.h"
|
|
#include "nsNetSupportDialog.h"
|
|
|
|
#include "nsIEventQueueService.h"
|
|
#include "nsIServiceManager.h"
|
|
#include "nsXPComFactory.h"
|
|
|
|
// Class IDs...
|
|
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
|
static NS_DEFINE_CID(kNetSupportDialogCID, NS_NETSUPPORTDIALOG_CID);
|
|
|
|
// Interface IDs...
|
|
static NS_DEFINE_IID(kIEventQueueServiceIID, NS_IEVENTQUEUESERVICE_IID);
|
|
static NS_DEFINE_IID(kIBlockingNotificationObserverIID,
|
|
NS_IBLOCKINGNOTIFICATION_OBSERVER_IID);
|
|
static NS_DEFINE_IID(kIBlockingNotificationIID, NS_IBLOCKINGNOTIFICATION_IID);
|
|
|
|
|
|
// Forward declarations...
|
|
class nsDefaultProtocolHelper;
|
|
|
|
/*-------------------- Notification Event Class ----------------------------*/
|
|
|
|
struct NotificationEvent : public PLEvent
|
|
{
|
|
NotificationEvent(nsDefaultProtocolHelper *aSelf,
|
|
nsIBlockingNotification *aCaller,
|
|
nsIURI *aUrl,
|
|
PRInt32 aCode,
|
|
nsISupports *aExtraInfo);
|
|
~NotificationEvent();
|
|
PRStatus Fire(nsIEventQueue* aEventQ);
|
|
|
|
static void PR_CALLBACK HandlePLEvent(PLEvent* aEvent);
|
|
static void PR_CALLBACK DestroyPLEvent(PLEvent* aEvent);
|
|
|
|
nsDefaultProtocolHelper *mSelf;
|
|
nsIBlockingNotification *mCaller;
|
|
nsIURI *mUrl;
|
|
PRInt32 mCode;
|
|
nsISupports *mExtraInfo;
|
|
};
|
|
|
|
|
|
|
|
/*----------------------------- nsDefaultProtocolHelper ---------------------*/
|
|
|
|
|
|
class nsDefaultProtocolHelper : public nsIBlockingNotificationObserver
|
|
{
|
|
public:
|
|
nsDefaultProtocolHelper();
|
|
|
|
/* nsISupports interface... */
|
|
NS_DECL_ISUPPORTS
|
|
|
|
/* nsIBlockingNotificationObserver interface... */
|
|
NS_IMETHOD Notify(nsIBlockingNotification *aCaller,
|
|
nsIURI *aUrl,
|
|
PRThread *aThread,
|
|
PRInt32 aCode,
|
|
void *aExtraInfo);
|
|
|
|
NS_IMETHOD CancelNotify(nsIURI *aUrl);
|
|
|
|
/* class methods... */
|
|
nsresult HandleNotification(nsIBlockingNotification *aCaller,
|
|
nsIURI *aUrl,
|
|
PRInt32 aCode,
|
|
void *aExtraInfo);
|
|
|
|
protected:
|
|
virtual ~nsDefaultProtocolHelper();
|
|
|
|
private:
|
|
nsIEventQueueService *mEventQService;
|
|
};
|
|
|
|
|
|
nsDefaultProtocolHelper::nsDefaultProtocolHelper()
|
|
{
|
|
NS_INIT_REFCNT();
|
|
|
|
/*
|
|
* Cache the EventQueue service...
|
|
*
|
|
* Ignore failure since there is nothing that can be done...
|
|
* Instead, all of the code that uses mEventQService *must*
|
|
* check that it was initialized...
|
|
*/
|
|
(void) nsServiceManager::GetService(kEventQueueServiceCID,
|
|
kIEventQueueServiceIID,
|
|
(nsISupports **)&mEventQService);
|
|
}
|
|
|
|
nsDefaultProtocolHelper::~nsDefaultProtocolHelper()
|
|
{
|
|
if (mEventQService) {
|
|
nsServiceManager::ReleaseService(kEventQueueServiceCID, mEventQService);
|
|
mEventQService = nsnull;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Implementations of nsISupports interface methods...
|
|
*/
|
|
NS_IMPL_ADDREF(nsDefaultProtocolHelper);
|
|
NS_IMPL_RELEASE(nsDefaultProtocolHelper);
|
|
NS_IMPL_QUERY_INTERFACE(nsDefaultProtocolHelper, kIBlockingNotificationObserverIID);
|
|
|
|
|
|
|
|
/*
|
|
* Implementations of nsIBlockingNotificationObserver interface methods...
|
|
*/
|
|
NS_IMETHODIMP
|
|
nsDefaultProtocolHelper::Notify(nsIBlockingNotification *aCaller,
|
|
nsIURI *aUrl,
|
|
PRThread *aThread,
|
|
PRInt32 aCode,
|
|
void *aExtraInfo)
|
|
{
|
|
nsresult rv;
|
|
NotificationEvent *ev;
|
|
|
|
/*
|
|
* Initialize the return code to indicate that the notification was not
|
|
* processed synchronously...
|
|
*/
|
|
rv = NS_NOTIFY_BLOCKED;
|
|
|
|
/*
|
|
* If no thread switch is necessary, then handle the notification
|
|
* immediately...
|
|
*/
|
|
#if 0 // The mac netlib is on the same thread as the UI thread but you crash if you block right here
|
|
PRThread* currentThread = PR_GetCurrentThread();
|
|
if ( currentThread == aThread) {
|
|
rv = HandleNotification(aCaller, aUrl, aCode, (void *)aExtraInfo);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
|
|
/*
|
|
* Post a message to the appropriate thread event queue to
|
|
* handle the notification...
|
|
*/
|
|
nsIEventQueue *evQ = nsnull;
|
|
|
|
/* locate the event queue for the thread... */
|
|
if (mEventQService) {
|
|
mEventQService->GetThreadEventQueue(aThread, &evQ);
|
|
}
|
|
|
|
/* Create and dispatch the notification event... */
|
|
if (evQ) {
|
|
ev = new NotificationEvent(this, aCaller, aUrl, aCode, (nsISupports *) aExtraInfo);
|
|
if (ev) {
|
|
PRStatus status;
|
|
|
|
/* dispatch the event into the appropriate event queue... */
|
|
status = ev->Fire(evQ);
|
|
|
|
if (PR_SUCCESS != status) {
|
|
/* If the event was not dispatched, then clean up... */
|
|
NotificationEvent::DestroyPLEvent(ev);
|
|
rv = NS_ERROR_FAILURE;
|
|
}
|
|
}
|
|
else {
|
|
/* allocation of the Notification event failed... */
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
NS_IF_RELEASE(evQ);
|
|
} else {
|
|
/* No event queue was found! */
|
|
NS_ASSERTION(0, "No Event Queue is available!");
|
|
rv = NS_ERROR_FAILURE;
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsDefaultProtocolHelper::CancelNotify(nsIURI *aUrl)
|
|
{
|
|
/* XXX: does not support interrupting a notification yet... */
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
|
|
nsresult nsDefaultProtocolHelper::HandleNotification(nsIBlockingNotification *aCaller,
|
|
nsIURI *aUrl,
|
|
PRInt32 aCode,
|
|
void *aExtraInfo)
|
|
{
|
|
/* XXX this definition must match the one in network/protocol/http/mkhttp.c
|
|
this will go away as netlib cleanup continues */
|
|
|
|
typedef struct _NET_AuthClosure {
|
|
char * msg;
|
|
char * user;
|
|
char * pass;
|
|
void * _private;
|
|
} NET_AuthClosure;
|
|
|
|
NET_AuthClosure * auth_closure = (NET_AuthClosure *) aExtraInfo;
|
|
|
|
nsAutoString aText(auth_closure->msg);
|
|
nsAutoString aUser;
|
|
nsAutoString aPass(auth_closure->pass);
|
|
|
|
// create a dialog
|
|
PRBool bResult = PR_FALSE;
|
|
nsString password, user;
|
|
PRInt32 result;
|
|
nsresult rv;
|
|
|
|
#ifdef NECKO
|
|
NS_WITH_SERVICE(nsIPrompt, dialog, kNetSupportDialogCID, &rv);
|
|
#else
|
|
NS_WITH_SERVICE(nsINetSupportDialogService, dialog, kNetSupportDialogCID, &rv);
|
|
#endif
|
|
|
|
if (NS_FAILED(rv))
|
|
return NS_ERROR_FAILURE;
|
|
if ( dialog ) {
|
|
#ifdef NECKO
|
|
PRUnichar* usr;
|
|
PRUnichar* pwd;
|
|
rv = dialog->PromptUsernameAndPassword(aText.GetUnicode(), &usr, &pwd, &result);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
aUser = usr;
|
|
delete[] usr;
|
|
aPass = pwd;
|
|
delete[] pwd;
|
|
}
|
|
#else
|
|
dialog->PromptUserAndPassword( aText, aUser, aPass, &result );
|
|
#endif
|
|
}
|
|
if ( result == 1 )
|
|
bResult = NS_NOTIFY_SUCCEEDED;
|
|
else
|
|
bResult = NS_ERROR_FAILURE;
|
|
|
|
auth_closure->user = aUser.ToNewCString();
|
|
auth_closure->pass = aPass.ToNewCString();
|
|
|
|
aCaller->Resume(aUrl, (void *) auth_closure);
|
|
|
|
return bResult;
|
|
// delete aUser;
|
|
// delete aPass;
|
|
// delete aText;
|
|
// dialog->Release();
|
|
|
|
return NS_NOTIFY_BLOCKED;
|
|
}
|
|
|
|
|
|
|
|
/*-------------------- Notification Event Class ----------------------------*/
|
|
|
|
|
|
|
|
NotificationEvent::NotificationEvent(nsDefaultProtocolHelper *aSelf,
|
|
nsIBlockingNotification *aCaller,
|
|
nsIURI *aUrl,
|
|
PRInt32 aCode,
|
|
nsISupports *aExtraInfo)
|
|
{
|
|
mSelf = aSelf;
|
|
mCaller = aCaller;
|
|
mUrl = aUrl;
|
|
mCode = aCode;
|
|
mExtraInfo = aExtraInfo;
|
|
|
|
NS_IF_ADDREF(mSelf);
|
|
NS_IF_ADDREF(mCaller);
|
|
NS_IF_ADDREF(mUrl);
|
|
// NS_IF_ADDREF(mExtraInfo);
|
|
}
|
|
|
|
|
|
NotificationEvent::~NotificationEvent()
|
|
{
|
|
NS_IF_RELEASE(mSelf);
|
|
NS_IF_RELEASE(mCaller);
|
|
NS_IF_RELEASE(mUrl);
|
|
// NS_IF_RELEASE(mExtraInfo);
|
|
}
|
|
|
|
void PR_CALLBACK NotificationEvent::HandlePLEvent(PLEvent* aEvent)
|
|
{
|
|
NotificationEvent *ev = (NotificationEvent*)aEvent;
|
|
|
|
(void)ev->mSelf->HandleNotification(ev->mCaller, ev->mUrl, ev->mCode,
|
|
(void *)ev->mExtraInfo);
|
|
}
|
|
|
|
void PR_CALLBACK NotificationEvent::DestroyPLEvent(PLEvent* aEvent)
|
|
{
|
|
NotificationEvent *ev = (NotificationEvent*)aEvent;
|
|
|
|
delete ev;
|
|
}
|
|
|
|
PRStatus NotificationEvent::Fire(nsIEventQueue* aEventQ)
|
|
{
|
|
PL_InitEvent(this, nsnull,
|
|
(PLHandleEventProc) NotificationEvent::HandlePLEvent,
|
|
(PLDestroyEventProc) NotificationEvent::DestroyPLEvent);
|
|
|
|
PRStatus status = aEventQ->PostEvent(this);
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Entry point to create nsAppShellService factory instances...
|
|
NS_DEF_FACTORY(DefaultProtocolHelper,nsDefaultProtocolHelper)
|
|
|
|
nsresult NS_NewDefaultProtocolHelperFactory(nsIFactory** aResult)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
nsIFactory* inst;
|
|
|
|
inst = new nsDefaultProtocolHelperFactory;
|
|
if (nsnull == inst) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
else {
|
|
NS_ADDREF(inst);
|
|
}
|
|
*aResult = inst;
|
|
return rv;
|
|
}
|
|
|
|
|