/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "MPL"); you may not use this file * except in compliance with the MPL. You may obtain a copy of * the MPL at http://www.mozilla.org/MPL/ * * Software distributed under the MPL is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the MPL for the specific language governing * rights and limitations under the MPL. * * The Original Code is XMLterm. * * The Initial Developer of the Original Code is Ramalingam Saravanan. * Portions created by Ramalingam Saravanan are * Copyright (C) 1999 Ramalingam Saravanan. All Rights Reserved. * * Contributor(s): * Pierre Phaneuf */ // mozXMLTerminal.cpp: implementation of mozIXMLTerminal interface // to manage all XMLTerm operations. // Creates a new mozXMLTermSession object to manage session input/output. // Creates a mozLineTermAux object to access LineTerm operations. // Creates key/text/mouse/drag listener objects to handle user events. #include "nscore.h" #include "nspr.h" #include "nsCOMPtr.h" #include "nsString.h" #include "nsIDocument.h" #include "nsIDOMHTMLDocument.h" #include "nsIDocumentViewer.h" #include "nsIDocumentLoaderObserver.h" #include "nsIObserver.h" #include "nsIPresContext.h" #include "nsIDOMEventReceiver.h" #include "nsIDOMEventListener.h" #include "nsIServiceManager.h" #include "nsISupportsPrimitives.h" #include "nsWidgetsCID.h" #include "nsIClipboard.h" #include "nsITransferable.h" #include "mozXMLT.h" #include "mozXMLTermUtils.h" #include "mozXMLTerminal.h" //////////////////////////////////////////////////////////////////////// static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); static NS_DEFINE_IID(kIXMLTerminalIID, MOZIXMLTERMINAL_IID); static NS_DEFINE_IID(kXMLTerminalCID, MOZXMLTERMINAL_CID); static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); static NS_DEFINE_CID(kCTransferableCID, NS_TRANSFERABLE_CID); ///////////////////////////////////////////////////////////////////////// // mozXMLTerminal factory ///////////////////////////////////////////////////////////////////////// nsresult NS_NewXMLTerminal(mozIXMLTerminal** aXMLTerminal) { NS_PRECONDITION(aXMLTerminal != nsnull, "null ptr"); if (!aXMLTerminal) return NS_ERROR_NULL_POINTER; *aXMLTerminal = new mozXMLTerminal(); if (! *aXMLTerminal) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(*aXMLTerminal); return NS_OK; } ///////////////////////////////////////////////////////////////////////// // mozXMLTerminal implementation ///////////////////////////////////////////////////////////////////////// mozXMLTerminal::mozXMLTerminal() : mInitialized(PR_FALSE), mCookie(""), mCommand(""), mPromptExpr(""), mFirstInput(""), mXMLTermShell(nsnull), mWebShell(nsnull), mPresShell(nsnull), mDOMDocument(nsnull), mXMLTermSession(nsnull), mLineTermAux(nsnull), mKeyListener(nsnull), mTextListener(nsnull), mMouseListener(nsnull), mDragListener(nsnull) { NS_INIT_REFCNT(); mFirstInputLock = PR_NewLock(); } mozXMLTerminal::~mozXMLTerminal() { if (mInitialized) { Finalize(); } PR_DestroyLock(mFirstInputLock); } // Implement AddRef and Release NS_IMPL_ADDREF(mozXMLTerminal) NS_IMPL_RELEASE(mozXMLTerminal) NS_INTERFACE_MAP_BEGIN(mozXMLTerminal) /* I maintained the order from the original, however, the original called |XMLT_LOG| and in the interface-map form it no longer does. Is this an issue? */ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozIXMLTerminal) NS_INTERFACE_MAP_ENTRY(mozIXMLTerminal) NS_INTERFACE_MAP_ENTRY(nsIDocumentLoaderObserver) NS_INTERFACE_MAP_ENTRY(nsIObserver) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_END NS_IMETHODIMP mozXMLTerminal::GetCurrentEntryNumber(PRInt32 *aNumber) { if (mXMLTermSession) { return mXMLTermSession->GetCurrentEntryNumber(aNumber); } else { return NS_ERROR_FAILURE; } } NS_IMETHODIMP mozXMLTerminal::GetHistory(PRInt32 *aHistory) { if (mXMLTermSession) { return mXMLTermSession->GetHistory(aHistory); } else { return NS_ERROR_FAILURE; } } NS_IMETHODIMP mozXMLTerminal::SetHistory(PRInt32 aHistory) { if (mXMLTermSession) { return mXMLTermSession->SetHistory(aHistory); } else { return NS_ERROR_FAILURE; } } NS_IMETHODIMP mozXMLTerminal::GetPrompt(PRUnichar **aPrompt) { if (mXMLTermSession) { return mXMLTermSession->GetPrompt(aPrompt); } else { return NS_ERROR_FAILURE; } } NS_IMETHODIMP mozXMLTerminal::SetPrompt(const PRUnichar* aPrompt) { if (mXMLTermSession) { return mXMLTermSession->SetPrompt(aPrompt); } else { return NS_ERROR_FAILURE; } } // Initialize by starting load of Init page for XMLTerm NS_IMETHODIMP mozXMLTerminal::Init(nsIWebShell* aWebShell, mozIXMLTermShell* aXMLTermShell, const PRUnichar* aURL, const PRUnichar* args) { XMLT_LOG(mozXMLTerminal::Init,20,("\n")); if (!aWebShell) return NS_ERROR_NULL_POINTER; if (mWebShell) return NS_ERROR_ALREADY_INITIALIZED; mWebShell = aWebShell; // containing webshell; no addref mXMLTermShell = aXMLTermShell; // containing xmlterm shell; no addref nsresult result = NS_OK; printf("mozXMLTerminal::Init, check1\n"); nsCOMPtr contViewer; result = mWebShell->GetContentViewer(getter_AddRefs(contViewer)); printf("mozXMLTerminal::Init, check2, result=%x, contViewer=%x\n", result, contViewer.get()); // NOTE: Need to parse args string!!! mCommand = ""; mPromptExpr = ""; mFirstInput = args; // Initialization completed mInitialized = PR_TRUE; if ((aURL != nsnull) && (*aURL != 0)) { // Load URL and activate XMLTerm after loading XMLT_LOG(mozXMLTerminal::Init,22,("setting DocLoaderObs\n")); // About to create owning reference to this result = mWebShell->SetDocLoaderObserver((nsIDocumentLoaderObserver*)this); if (NS_FAILED(result)) return NS_ERROR_FAILURE; XMLT_LOG(mozXMLTerminal::Init,22,("done setting DocLoaderObs\n")); // Load initial XMLterm background document nsAutoString urlString(aURL); result = mWebShell->LoadURL(urlString.GetUnicode()); if (NS_FAILED(result)) return NS_ERROR_FAILURE; } else { // Document already loaded; activate XMLTerm result = Activate(); if (NS_FAILED(result)) return NS_ERROR_FAILURE; } XMLT_LOG(mozXMLTerminal::Init,21,("exiting\n")); return result; } // De-initialize XMLTerminal NS_IMETHODIMP mozXMLTerminal::Finalize(void) { if (mXMLTermSession) { // Finalize XMLTermSession object and delete it (it is not ref. counted) mXMLTermSession->Finalize(); delete mXMLTermSession; mXMLTermSession = nsnull; } if (mDOMDocument) { // Release any event listeners for the document nsCOMPtr eventReceiver; nsresult result = mDOMDocument->QueryInterface(NS_GET_IID(nsIDOMEventReceiver), getter_AddRefs(eventReceiver)); if (NS_SUCCEEDED(result) && eventReceiver) { if (mKeyListener) { eventReceiver->RemoveEventListenerByIID(mKeyListener, NS_GET_IID(nsIDOMKeyListener)); mKeyListener = nsnull; } if (mTextListener) { eventReceiver->RemoveEventListenerByIID(mTextListener, NS_GET_IID(nsIDOMTextListener)); mTextListener = nsnull; } if (mMouseListener) { eventReceiver->RemoveEventListenerByIID(mMouseListener, NS_GET_IID(nsIDOMMouseListener)); mMouseListener = nsnull; } if (mDragListener) { eventReceiver->RemoveEventListenerByIID(mDragListener, NS_GET_IID(nsIDOMDragListener)); mDragListener = nsnull; } } mDOMDocument = nsnull; } if (mLineTermAux) { // Finalize and release reference to LineTerm object owned by us mLineTermAux->CloseAux(); mLineTermAux = nsnull; } if (mWebShell) { // Stop observing document loading mWebShell->SetDocLoaderObserver((nsIDocumentLoaderObserver *)nsnull); mWebShell = nsnull; } mPresShell = nsnull; mXMLTermShell = nsnull; mInitialized = PR_FALSE; return NS_OK; } /** Activates XMLterm and instantiates LineTerm; * called at the the end of Init page loading. */ NS_IMETHODIMP mozXMLTerminal::Activate(void) { nsresult result = NS_OK; #if 0 // TEMPORARY: Testing mozIXMLTermStream nsAutoString streamData = "Stream Title" "" "Stream Body " "Clik
" "
 
" "
ABCD
EFGH
JKLM
" ""; nsCOMPtr stream; result = NS_NewXMLTermStream(getter_AddRefs(stream)); if (NS_FAILED(result)) { fprintf(stderr, "mozXMLTerminal::Activate: Failed to create stream\n"); return result; } nsCOMPtr outerDOMWindow; result = mozXMLTermUtils::ConvertWebShellToDOMWindow(mWebShell, getter_AddRefs(outerDOMWindow)); if (NS_FAILED(result) || !outerDOMWindow) { fprintf(stderr, "mozXMLTerminal::Activate: Failed to convert webshell\n"); return NS_ERROR_FAILURE; } result = stream->Open(outerDOMWindow, "iframet", "chrome://dummy", "text/html", 800); if (NS_FAILED(result)) { fprintf(stderr, "mozXMLTerminal::Activate: Failed to open stream\n"); return result; } result = stream->Write(streamData.GetUnicode()); if (NS_FAILED(result)) { fprintf(stderr, "mozXMLTerminal::Activate: Failed to write to stream\n"); return result; } result = stream->Close(); if (NS_FAILED(result)) { fprintf(stderr, "mozXMLTerminal::Activate: Failed to close stream\n"); return result; } #endif XMLT_LOG(mozXMLTerminal::Activate,20,("\n")); if (!mInitialized) return NS_ERROR_NOT_INITIALIZED; PR_ASSERT(mWebShell != nsnull); if ((mDOMDocument != nsnull) || (mPresShell != nsnull)) return NS_ERROR_FAILURE; // Get reference to DOMDocument nsCOMPtr domDocument; result = mozXMLTermUtils::GetWebShellDOMDocument(mWebShell, getter_AddRefs(domDocument)); if (NS_FAILED(result) || !domDocument) return NS_ERROR_FAILURE; // Get reference to presentation shell if (mPresShell != nsnull) return NS_ERROR_FAILURE; nsCOMPtr presContext; result = mozXMLTermUtils::GetWebShellPresContext(mWebShell, getter_AddRefs(presContext)); if (NS_FAILED(result) || !presContext) return NS_ERROR_FAILURE; nsCOMPtr presShell; result = presContext->GetShell(getter_AddRefs(presShell)); if (NS_FAILED(result) || !presShell) return NS_ERROR_FAILURE; // Save references to DOMDocument and presentation shell // (SVN: Should these be addref'ed and released in the destructor?) mDOMDocument = domDocument; // no addref mPresShell = presShell; // no addref // Instantiate and initialize XMLTermSession object mXMLTermSession = new mozXMLTermSession(); if (!mXMLTermSession) { return NS_ERROR_OUT_OF_MEMORY; } result = mXMLTermSession->Init(this, mPresShell, mDOMDocument); if (NS_FAILED(result)) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to initialize XMLTermSession\n"); return NS_ERROR_FAILURE; } // Instantiate LineTerm XMLT_LOG(mozXMLTerminal::Activate,22,("instantiating lineterm\n")); result = NS_NewLineTermAux(getter_AddRefs(mLineTermAux)); if (NS_FAILED(result)) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to instantiate LineTermAux\n"); return result; } // Open LineTerm to execute command // Non-owning reference to this; delete LineTerm before deleting self PRInt32 options = 0; XMLT_LOG(mozXMLTerminal::Activate,22,("Opening LineTerm\n")); nsCOMPtr anObserver = this; #ifdef NO_CALLBACK anObserver = nsnull; #endif nsAutoString cookie; result = mLineTermAux->OpenAux(mCommand.GetUnicode(), mPromptExpr.GetUnicode(), options, LTERM_DETERMINE_PROCESS, mDOMDocument, anObserver, cookie); if (NS_FAILED(result)) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to open LineTermAux\n"); return result; } XMLT_LOG(mozXMLTerminal::Activate,22,("Opened LineTerm\n")); // Save cookie mCookie = cookie; // Get the DOM event receiver for document nsCOMPtr eventReceiver; result = mDOMDocument->QueryInterface(NS_GET_IID(nsIDOMEventReceiver), getter_AddRefs(eventReceiver)); if (NS_FAILED(result)) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to get DOM receiver\n"); return result; } // Create a key listener result = NS_NewXMLTermKeyListener(getter_AddRefs(mKeyListener), this); if (NS_OK != result) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to get key listener\n"); return result; } // Register the key listener with the DOM event receiver result = eventReceiver->AddEventListenerByIID(mKeyListener, NS_GET_IID(nsIDOMKeyListener)); if (NS_FAILED(result)) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to register key listener\n"); return result; } // Create a text listener result = NS_NewXMLTermTextListener(getter_AddRefs(mTextListener), this); if (NS_OK != result) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to get text listener\n"); return result; } // Register the text listener with the DOM event receiver result = eventReceiver->AddEventListenerByIID(mTextListener, NS_GET_IID(nsIDOMTextListener)); if (NS_FAILED(result)) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to register text listener\n"); return result; } // Create a mouse listener result = NS_NewXMLTermMouseListener(getter_AddRefs(mMouseListener), this); if (NS_OK != result) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to get mouse listener\n"); return result; } // Register the mouse listener with the DOM event receiver result = eventReceiver->AddEventListenerByIID(mMouseListener, NS_GET_IID(nsIDOMMouseListener)); if (NS_FAILED(result)) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to register mouse listener\n"); return result; } // Create a drag listener result = NS_NewXMLTermDragListener(getter_AddRefs(mDragListener), this); if (NS_OK != result) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to get drag listener\n"); return result; } // Register the drag listener with the DOM event receiver result = eventReceiver->AddEventListenerByIID(mDragListener, NS_GET_IID(nsIDOMDragListener)); if (NS_FAILED(result)) { XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to register drag listener\n"); return result; } return NS_OK; } // Transmit string to LineTerm (use saved cookie) NS_IMETHODIMP mozXMLTerminal::SendTextAux(const nsString& aString) { return SendText(aString, mCookie.GetUnicode()); } // Transmit string to LineTerm NS_IMETHODIMP mozXMLTerminal::SendText(const nsString& aString, const PRUnichar* aCookie) { nsresult result; if (!mLineTermAux) return NS_ERROR_FAILURE; nsAutoString sendStr = aString; // Preprocess string and check if it is to be consumed PRBool consumed = false; result = mXMLTermSession->Preprocess(sendStr, consumed); if (!consumed) { PR_Lock(mFirstInputLock); if (mFirstInput.Length() > 0) { result = mLineTermAux->Write(mFirstInput.GetUnicode(), aCookie); if (NS_FAILED(result)) return result; mFirstInput = ""; } PR_Unlock(mFirstInputLock); result = mLineTermAux->Write(sendStr.GetUnicode(), aCookie); if (NS_FAILED(result)) { // Close LineTerm mLineTermAux->Close(aCookie); return NS_ERROR_FAILURE; } } return NS_OK; } // Paste data from clipboard to terminal NS_IMETHODIMP mozXMLTerminal::Paste() { nsresult result; nsAutoString pasteString; XMLT_LOG(mozXMLTerminal::Paste,20,("\n")); // Get Clipboard service NS_WITH_SERVICE (nsIClipboard, clipboard, kCClipboardCID, &result); if ( NS_FAILED(result) ) return result; // Generic transferable for getting clipboard data nsCOMPtr trans; result = nsComponentManager::CreateInstance(kCTransferableCID, nsnull, NS_GET_IID(nsITransferable), (void**) getter_AddRefs(trans)); if (NS_FAILED(result) || !trans) return NS_ERROR_FAILURE; // DataFlavors to get out of transferable trans->AddDataFlavor(kHTMLMime); trans->AddDataFlavor(kUnicodeMime); // Get data from clipboard result = clipboard->GetData(trans); if (NS_FAILED(result)) return result; char* bestFlavor = nsnull; nsCOMPtr genericDataObj; PRUint32 objLen = 0; result = trans->GetAnyTransferData(&bestFlavor, getter_AddRefs(genericDataObj), &objLen); if (NS_FAILED(result)) return result; nsAutoString flavor ( bestFlavor ); char* temCStr = flavor.ToNewCString(); XMLT_LOG(mozXMLTerminal::Paste,20,("flavour=%s\n", temCStr)); nsAllocator::Free(temCStr); if (flavor.Equals(kHTMLMime) || flavor.Equals(kUnicodeMime)) { nsCOMPtr textDataObj ( do_QueryInterface(genericDataObj) ); if (textDataObj && objLen > 0) { PRUnichar* text = nsnull; textDataObj->ToString ( &text ); pasteString.SetString ( text, objLen / 2 ); result = SendTextAux(pasteString); } } nsAllocator::Free(bestFlavor); return NS_OK; } // Poll for readable data from LineTerm NS_IMETHODIMP mozXMLTerminal::Poll(void) { if (!mLineTermAux) return NS_ERROR_NOT_INITIALIZED; XMLT_LOG(mozXMLTerminal::Poll,20,("\n")); nsresult result; PRBool processedData; result = mXMLTermSession->ReadAll(mLineTermAux, processedData); if (NS_FAILED(result)) return result; if (processedData && (mFirstInput.Length() > 0)) { // Send first input command line(s) PR_Lock(mFirstInputLock); result = mLineTermAux->Write(mFirstInput.GetUnicode(), mCookie.GetUnicode()); mFirstInput = ""; PR_Unlock(mFirstInputLock); if (NS_FAILED(result)) return result; } return NS_OK; } // Handle callback from LineTerm when new input/output needs to be displayed NS_IMETHODIMP mozXMLTerminal::Observe(nsISupports *aSubject, const PRUnichar *aTopic, const PRUnichar *someData) { nsCOMPtr lineTermAux = do_QueryInterface(aSubject); PR_ASSERT(lineTermAux != nsnull); PR_ASSERT(lineTermAux.get() == mLineTermAux.get()); return Poll(); } // Returns document associated with XMLTerminal NS_IMETHODIMP mozXMLTerminal::GetDocument(nsIDOMDocument** aDoc) { if (!aDoc) return NS_ERROR_NULL_POINTER; *aDoc = nsnull; NS_PRECONDITION(mDOMDocument, "bad state, null mDOMDocument"); if (!mDOMDocument) return NS_ERROR_NOT_INITIALIZED; return mDOMDocument->QueryInterface(NS_GET_IID(nsIDOMDocument), (void **)aDoc); } // Returns web shell associated with XMLTerm NS_IMETHODIMP mozXMLTerminal::GetWebShell(nsIWebShell** aWebShell) { if (!aWebShell) return NS_ERROR_NULL_POINTER; *aWebShell = nsnull; NS_PRECONDITION(mWebShell, "bad state, null mWebShell"); if (!mWebShell) return NS_ERROR_NOT_INITIALIZED; return mWebShell->QueryInterface(NS_GET_IID(nsIWebShell), (void **)aWebShell); } // Returns presentation shell associated with XMLTerm NS_IMETHODIMP mozXMLTerminal::GetPresShell(nsIPresShell** aPresShell) { if (!aPresShell) return NS_ERROR_NULL_POINTER; *aPresShell = nsnull; NS_PRECONDITION(mPresShell, "bad state, null mPresShell"); if (!mPresShell) return NS_ERROR_NOT_INITIALIZED; return mPresShell->QueryInterface(NS_GET_IID(nsIPresShell), (void **)aPresShell); } // nsIDocumentLoaderObserver methods NS_IMETHODIMP mozXMLTerminal::OnStartDocumentLoad(nsIDocumentLoader* loader, nsIURI* aURL, const char* aCommand) { return NS_OK; } NS_IMETHODIMP mozXMLTerminal::OnEndDocumentLoad(nsIDocumentLoader* loader, nsIChannel* channel, nsresult aStatus) { return NS_OK; } NS_IMETHODIMP mozXMLTerminal::OnStartURLLoad(nsIDocumentLoader* loader, nsIChannel* channel) { return NS_OK; } NS_IMETHODIMP mozXMLTerminal::OnProgressURLLoad(nsIDocumentLoader* loader, nsIChannel* channel, PRUint32 aProgress, PRUint32 aProgressMax) { return NS_OK; } NS_IMETHODIMP mozXMLTerminal::OnStatusURLLoad(nsIDocumentLoader* loader, nsIChannel* channel, nsString& aMsg) { return NS_OK; } NS_IMETHODIMP mozXMLTerminal::OnEndURLLoad(nsIDocumentLoader* loader, nsIChannel* channel, nsresult aStatus) { XMLT_LOG(mozXMLTerminal::OnEndURLLoad,20,("\n")); // Activate XMLTerm Activate(); return NS_OK; } NS_IMETHODIMP mozXMLTerminal::HandleUnknownContentType(nsIDocumentLoader* loader, nsIChannel* channel, const char *aContentType, const char *aCommand ) { return NS_OK; }