Back to index

lightning-sunbird  0.9+nobinonly
mozXMLTermSession.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is XMLterm.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Ramalingam Saravanan.
00018  * Portions created by the Initial Developer are Copyright (C) 1999
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 // mozXMLTermSession.cpp: implementation of mozXMLTermSession class
00038 
00039 #include "nscore.h"
00040 #include "prlog.h"
00041 
00042 #include "nscore.h"
00043 #include "nsCOMPtr.h"
00044 #include "nsString.h"
00045 #include "nsCRT.h"
00046 #include "nsIComponentManager.h"
00047 
00048 #include "nsMemory.h"
00049 
00050 #include "nsIDocumentViewer.h"
00051 
00052 #include "nsILocalFile.h"
00053 #include "nsNetUtil.h"
00054 
00055 #include "nsITextContent.h"
00056 
00057 #include "nsIDOMElement.h"
00058 #include "nsISelection.h"
00059 #include "nsIDOMText.h"
00060 #include "nsIDOMAttr.h"
00061 #include "nsIDOMNamedNodeMap.h"
00062 #include "nsIDOMNodeList.h"
00063 #include "nsIDOMRange.h"
00064 #include "nsIDOMCharacterData.h"
00065 
00066 #include "nsIDOMHTMLDocument.h"
00067 #include "nsIDOMDocumentFragment.h"
00068 #include "nsIDOMNSRange.h"
00069 
00070 #include "nsIViewManager.h"
00071 #include "nsIScrollableView.h"
00072 
00073 #include "mozXMLT.h"
00074 #include "mozIXMLTerminal.h"
00075 #include "mozIXMLTermStream.h"
00076 #include "mozXMLTermUtils.h"
00077 #include "mozXMLTermSession.h"
00078 #include "nsISelectionController.h"
00079 #include "nsReadableUtils.h"
00080 #include "nsIDocument.h"
00081 
00083 // mozXMLTermSession definition
00085 static const char* kWhitespace=" \b\t\r\n";
00086 static const PRUnichar kNBSP = 160;
00087 
00088 const char* const mozXMLTermSession::sessionElementNames[] = {
00089   "session",
00090   "entry",
00091   "input",
00092   "output",
00093   "prompt",
00094   "command",
00095   "stdin",
00096   "stdout",
00097   "stderr",
00098   "mixed",
00099   "warning"
00100 };
00101 
00102 // Should HTML event names should always be in lower case for DOM to work?
00103 const char* const mozXMLTermSession::sessionEventNames[] = {
00104   "click"
00105 };
00106 
00107 const char* const mozXMLTermSession::metaCommandNames[] = {
00108   "",
00109   "default",
00110   "http",
00111   "js",
00112   "tree",
00113   "ls"
00114 };
00115 
00116 const char* const mozXMLTermSession::fileTypeNames[] = {
00117   "plainfile",
00118   "directory",
00119   "executable"
00120 };
00121 
00122 const char* const mozXMLTermSession::treeActionNames[] = {
00123   "^",
00124   "v",
00125   "<",
00126   ">",
00127   "A",
00128   "H"
00129 };
00130 
00131 mozXMLTermSession::mozXMLTermSession() :
00132   mInitialized(PR_FALSE),
00133   mXMLTerminal(nsnull),
00134 
00135   mBodyNode(nsnull),
00136   mMenusNode(nsnull),
00137   mSessionNode(nsnull),
00138   mCurrentDebugNode(nsnull),
00139 
00140   mStartEntryNode(nsnull),
00141   mCurrentEntryNode(nsnull),
00142 
00143   mMaxHistory(20),
00144   mStartEntryNumber(0),
00145   mCurrentEntryNumber(0),
00146 
00147   mEntryHasOutput(PR_FALSE),
00148 
00149   mPromptTextNode(nsnull),
00150   mCommandSpanNode(nsnull),
00151   mInputTextNode(nsnull),
00152 
00153   mOutputBlockNode(nsnull),
00154   mOutputDisplayNode(nsnull),
00155   mOutputTextNode(nsnull),
00156 
00157   mXMLTermStream(nsnull),
00158 
00159   mOutputType(LINE_OUTPUT),
00160   mOutputDisplayType(NO_NODE),
00161   mOutputMarkupType(PLAIN_TEXT),
00162 
00163   mMetaCommandType(NO_META_COMMAND),
00164   mAutoDetect(FIRST_LINE),
00165 
00166   mFirstOutputLine(PR_FALSE),
00167 
00168   mEntryOutputLines(0),
00169   mPreTextBufferLines(0),
00170   mPreTextIncomplete(),
00171   mPreTextBuffered(),
00172   mPreTextDisplayed(),
00173 
00174   mScreenNode(nsnull),
00175   mScreenRows(0),
00176   mScreenCols(0),
00177   mTopScrollRow(0),
00178   mBotScrollRow(0),
00179 
00180   mRestoreInputEcho(PR_FALSE),
00181 
00182   mCountExportHTML(0),
00183   mLastExportHTML(),
00184 
00185   mShellPrompt(),
00186   mPromptHTML(),
00187   mFragmentBuffer()
00188 
00189 {
00190 }
00191 
00192 
00193 mozXMLTermSession::~mozXMLTermSession()
00194 {
00195   Finalize();
00196 }
00197 
00198 
00199 // Initialize XMLTermSession
00200 NS_IMETHODIMP mozXMLTermSession::Init(mozIXMLTerminal* aXMLTerminal,
00201                                       nsIPresShell* aPresShell,
00202                                       nsIDOMDocument* aDOMDocument,
00203                                       PRInt32 nRows, PRInt32 nCols)
00204 {
00205   nsresult result = NS_OK;
00206 
00207   XMLT_LOG(mozXMLTermSession::Init,30,("\n"));
00208 
00209   if (mInitialized)
00210     return NS_ERROR_ALREADY_INITIALIZED;
00211 
00212   if (!aXMLTerminal || !aPresShell || !aDOMDocument)
00213       return NS_ERROR_NULL_POINTER;
00214 
00215   mXMLTerminal = aXMLTerminal;    // containing XMLTerminal; no addref
00216 
00217   mInitialized = PR_TRUE;
00218 
00219   mScreenRows = nRows;
00220   mScreenCols = nCols;
00221   mTopScrollRow = mScreenRows - 1;
00222   mBotScrollRow = 0;
00223 
00224   nsCOMPtr<nsIDOMDocument> domDoc;
00225   result = mXMLTerminal->GetDOMDocument(getter_AddRefs(domDoc));
00226   if (NS_FAILED(result) || !domDoc)
00227     return NS_ERROR_FAILURE;
00228 
00229   nsCOMPtr<nsIDOMHTMLDocument> vDOMHTMLDocument
00230                                              (do_QueryInterface(domDoc));
00231   if (!vDOMHTMLDocument)
00232     return NS_ERROR_FAILURE;
00233 
00234   // Locate document body node
00235   nsCOMPtr<nsIDOMNodeList> nodeList;
00236   nsAutoString bodyTag;
00237   bodyTag.AssignLiteral("body");
00238   result = vDOMHTMLDocument->GetElementsByTagName(bodyTag,
00239                                                   getter_AddRefs(nodeList));
00240   if (NS_FAILED(result) || !nodeList)
00241     return NS_ERROR_FAILURE;
00242 
00243   PRUint32 count;
00244   nodeList->GetLength(&count);
00245   PR_ASSERT(count==1);
00246 
00247   result = nodeList->Item(0, getter_AddRefs(mBodyNode));
00248   if (NS_FAILED(result) || !mBodyNode)
00249     return NS_ERROR_FAILURE;
00250 
00251   nsCOMPtr<nsIDOMElement> menusElement;
00252   nsAutoString menusID( NS_LITERAL_STRING("menus") );
00253   result = vDOMHTMLDocument->GetElementById(menusID,
00254                                             getter_AddRefs(menusElement));
00255 
00256   if (NS_SUCCEEDED(result) && menusElement) {
00257     mMenusNode = do_QueryInterface(menusElement);
00258   }
00259 
00260   // Use body node as session node by default
00261   mSessionNode = mBodyNode;
00262 
00263   nsCOMPtr<nsIDOMElement> sessionElement;
00264   nsAutoString sessionID;
00265   sessionID.AssignASCII(sessionElementNames[SESSION_ELEMENT]);
00266   result = vDOMHTMLDocument->GetElementById(sessionID,
00267                                             getter_AddRefs(sessionElement));
00268 
00269   if (NS_SUCCEEDED(result) && sessionElement) {
00270     // Specific session node
00271     mSessionNode = do_QueryInterface(sessionElement);
00272   }
00273 
00274   mCurrentDebugNode = mSessionNode;
00275 
00276   // Create preface element to display initial output
00277   result = NewPreface();
00278   if (NS_FAILED(result))
00279     return NS_ERROR_FAILURE;
00280 
00281 #if 0
00282   nsAutoString prefaceText ("Preface");
00283   result = AppendOutput(prefaceText, EmptyString(), PR_TRUE);
00284 #endif
00285 
00286   XMLT_LOG(mozXMLTermSession::Init,31,("exiting\n"));
00287   return result;
00288 }
00289 
00290 
00291 // De-initialize XMLTermSession
00292 NS_IMETHODIMP mozXMLTermSession::Finalize(void)
00293 {
00294 
00295   if (!mInitialized)
00296     return NS_OK;
00297 
00298   XMLT_LOG(mozXMLTermSession::Finalize,30,("\n"));
00299 
00300   mInitialized = PR_FALSE;
00301 
00302   mScreenNode = nsnull;
00303 
00304   mOutputBlockNode = nsnull;
00305   mOutputDisplayNode = nsnull;
00306   mOutputTextNode = nsnull;
00307 
00308   mXMLTermStream = nsnull;
00309 
00310   mPromptTextNode = nsnull;
00311   mCommandSpanNode = nsnull;
00312   mInputTextNode = nsnull;
00313 
00314   mStartEntryNode = nsnull;
00315   mCurrentEntryNode = nsnull;
00316 
00317   mBodyNode = nsnull;
00318   mMenusNode = nsnull;
00319   mSessionNode = nsnull;
00320   mCurrentDebugNode = nsnull;
00321 
00322   mXMLTerminal = nsnull;
00323 
00324   XMLT_LOG(mozXMLTermSession::Finalize,32,("END\n"));
00325 
00326   return NS_OK;
00327 }
00328 
00329 
00333 NS_IMETHODIMP mozXMLTermSession::Resize(mozILineTermAux* lineTermAux)
00334 {
00335   nsresult result;
00336 
00337   XMLT_LOG(mozXMLTermSession::Resize,70,("\n"));
00338 
00339   // Determine current screen dimensions
00340   PRInt32 nRows, nCols, xPixels, yPixels;
00341   result = mXMLTerminal->ScreenSize(&nRows, &nCols, &xPixels, &yPixels);
00342   if (NS_FAILED(result))
00343     return result;
00344 
00345   // If dimensions haven't changed, do nothing
00346   if ((nRows == mScreenRows) && (nCols == mScreenCols))
00347     return NS_OK;
00348 
00349   mScreenRows = nRows;
00350   mScreenCols = nCols;
00351 
00352   mTopScrollRow = mScreenRows - 1;
00353   mBotScrollRow = 0;
00354 
00355   XMLT_LOG(mozXMLTermSession::Resize,72,
00356        ("Resizing XMLterm, nRows=%d, nCols=%d\n", mScreenRows, mScreenCols));
00357 
00358   if (lineTermAux) {
00359     // Resize associated LineTerm
00360     result = lineTermAux->ResizeAux(mScreenRows, mScreenCols);
00361     if (NS_FAILED(result))
00362       return result;
00363   }
00364 
00365   return NS_OK;
00366 }
00367 
00368 
00374 NS_IMETHODIMP mozXMLTermSession::Preprocess(const nsString& aString,
00375                                             PRBool& consumed,
00376                                             PRBool& checkSize)
00377 {
00378 
00379   XMLT_LOG(mozXMLTermSession::Preprocess,70,("\n"));
00380 
00381   consumed = PR_FALSE;
00382   checkSize = PR_FALSE;
00383 
00384   if (mMetaCommandType == TREE_META_COMMAND) {
00385     if (aString.Length() == 1) {
00386       // Navigate the DOM tree from keyboard
00387       PRUnichar uch = aString.CharAt(0);
00388 
00389       XMLT_LOG(mozXMLTermSession::Preprocess,60,("char=0x%x\n", uch));
00390 
00391       consumed = PR_TRUE;
00392       switch (uch) {
00393       case U_CTL_B:
00394         TraverseDOMTree(stderr, mBodyNode, mCurrentDebugNode,
00395                         TREE_MOVE_LEFT);
00396         break;
00397 
00398       case U_CTL_F:
00399         TraverseDOMTree(stderr, mBodyNode, mCurrentDebugNode,
00400                         TREE_MOVE_RIGHT);
00401         break;
00402 
00403       case U_CTL_N:
00404         TraverseDOMTree(stderr, mBodyNode, mCurrentDebugNode,
00405                         TREE_MOVE_DOWN);
00406         break;
00407 
00408       case U_CTL_P:
00409         TraverseDOMTree(stderr, mBodyNode, mCurrentDebugNode,
00410                         TREE_MOVE_UP);
00411         break;
00412 
00413       case U_A_CHAR:
00414       case U_a_CHAR:
00415         TraverseDOMTree(stderr, mBodyNode, mCurrentDebugNode,
00416                         TREE_PRINT_ATTS);
00417         break;
00418 
00419       case U_H_CHAR:
00420       case U_h_CHAR:
00421         TraverseDOMTree(stderr, mBodyNode, mCurrentDebugNode,
00422                         TREE_PRINT_HTML);
00423         break;
00424 
00425       case U_Q_CHAR:
00426       case U_q_CHAR:
00427       case U_CTL_C:
00428         // End of keyboard command sequence; reset debug node to session node
00429         mCurrentDebugNode = mSessionNode;
00430         mMetaCommandType = NO_META_COMMAND;
00431         break;
00432 
00433       default:
00434         break;
00435       }
00436     }
00437   } else {
00438 
00439     if ((mScreenNode == nsnull) &&
00440         (aString.FindCharInSet("\r\n\017") >= 0)) {
00441       // C-Return or Newline or Control-O found in string; not screen mode;
00442       // resize terminal, if need be
00443       checkSize = PR_TRUE;
00444       XMLT_LOG(mozXMLTermSession::Preprocess,72,("checkSize\n"));
00445     }
00446   }
00447 
00448   return NS_OK;
00449 }
00450 
00451 
00457 NS_IMETHODIMP mozXMLTermSession::ReadAll(mozILineTermAux* lineTermAux,
00458                                          PRBool& processedData)
00459 {
00460   PRInt32 opcodes, opvals, buf_row, buf_col;
00461   PRUnichar *buf_str, *buf_style;
00462   PRBool newline, errorFlag, streamData, screenData;
00463   nsAutoString bufString, bufStyle;
00464   nsAutoString abortCode;
00465   abortCode.SetLength(0);
00466 
00467   XMLT_LOG(mozXMLTermSession::ReadAll,60,("\n"));
00468 
00469   processedData = PR_FALSE;
00470 
00471   if (lineTermAux == nsnull)
00472     return NS_ERROR_FAILURE;
00473 
00474   nsresult result = NS_OK;
00475   PRBool flushOutput = PR_FALSE;
00476 
00477   PRBool metaNextCommand = PR_FALSE;
00478 
00479   // NOTE: Do not execute return statements within this loop ;
00480   //       always break out of the loop after setting result to an error value,
00481   //       allowing cleanup processing on error
00482   for (;;) {
00483     // NOTE: Remember to de-allocate buf_str and buf_style
00484     //       using nsMemory::Free, if opcodes != 0
00485     result = lineTermAux->ReadAux(&opcodes, &opvals, &buf_row, &buf_col,
00486                                   &buf_str, &buf_style);
00487     if (NS_FAILED(result)) {
00488       abortCode.AssignLiteral("lineTermReadAux");
00489       break;
00490     }
00491 
00492     XMLT_LOG(mozXMLTermSession::ReadAll,62,
00493            ("opcodes=0x%x,mOutputType=%d,mEntryHasOutput=%d\n",
00494             opcodes, mOutputType, mEntryHasOutput));
00495 
00496     if (opcodes == 0) break;
00497 
00498     processedData = PR_TRUE;
00499 
00500     screenData = (opcodes & LTERM_SCREENDATA_CODE);
00501     streamData = (opcodes & LTERM_STREAMDATA_CODE);
00502     newline =    (opcodes & LTERM_NEWLINE_CODE);
00503     errorFlag =  (opcodes & LTERM_ERROR_CODE);
00504 
00505     // Copy character/style strings
00506     bufString = buf_str;
00507     bufStyle = buf_style;
00508 
00509     // De-allocate buf_str, buf_style using nsMemory::Free
00510     nsMemory::Free(buf_str);
00511     nsMemory::Free(buf_style);
00512 
00513     char* temCString = ToNewCString(bufString);
00514     XMLT_LOG(mozXMLTermSession::ReadAll,68,("bufString=%s\n", temCString));
00515     nsCRT::free(temCString);
00516 
00517     if (screenData && (mOutputType != SCREEN_OUTPUT)) {
00518       // Initiate screen mode
00519       XMLT_LOG(mozXMLTermSession::ReadAll,62,("Initiate SCREEN mode\n"));
00520 
00521       // Break output display
00522       result = BreakOutput(PR_FALSE);
00523       if (NS_FAILED(result))
00524         break;
00525 
00526       // Create screen element
00527       result = NewScreen();
00528       if (NS_FAILED(result))
00529         break;
00530 
00531       mOutputType = SCREEN_OUTPUT;
00532 
00533       // Disable input echo
00534       lineTermAux->SetEchoFlag(PR_FALSE);
00535       mRestoreInputEcho = PR_TRUE;
00536     }
00537 
00538     if (!screenData && (mOutputType == SCREEN_OUTPUT)) {
00539       // Terminate screen mode
00540       mOutputType = LINE_OUTPUT;
00541 
00542       XMLT_LOG(mozXMLTermSession::ReadAll,62,
00543                ("Terminating screen mode\n"));
00544 
00545       // Uncollapse non-screen stuff
00546       nsAutoString attName(NS_LITERAL_STRING("xmlt-block-collapsed"));
00547 
00548       nsCOMPtr<nsIDOMElement> menusElement = do_QueryInterface(mMenusNode);
00549 
00550       if (NS_SUCCEEDED(result) && menusElement) {
00551         menusElement->RemoveAttribute(attName);
00552       }
00553 
00554       nsCOMPtr<nsIDOMElement> sessionElement = do_QueryInterface(mSessionNode);
00555 
00556       if (sessionElement) {
00557         sessionElement->RemoveAttribute(attName);
00558       }
00559 
00560       // Delete screen element
00561       nsCOMPtr<nsIDOMNode> resultNode;
00562       mBodyNode->RemoveChild(mScreenNode, getter_AddRefs(resultNode));
00563       if (NS_FAILED(result))
00564         break;
00565       mScreenNode = nsnull;
00566 
00567       if (mRestoreInputEcho) {
00568         lineTermAux->SetEchoFlag(PR_TRUE);
00569         mRestoreInputEcho = PR_FALSE;
00570       }
00571 
00572       // Show the caret
00573       // WORKAROUND for some unknown bug in the full screen implementation.
00574       // Without this, if you delete a line using "vi" and save the file,
00575       // the cursor suddenly disappears
00576       mXMLTerminal->ShowCaret();
00577     }
00578 
00579     if (streamData) {
00580       // Process stream data
00581       if (mOutputType != STREAM_OUTPUT) {
00582         mOutputType = STREAM_OUTPUT;
00583 
00584         // Disable input echo
00585         lineTermAux->SetEchoFlag(PR_FALSE);
00586         mRestoreInputEcho = PR_TRUE;
00587 
00588         // Determine effective stream URL and default markup type
00589         nsAutoString streamURL;
00590         OutputMarkupType streamMarkupType;
00591         PRBool streamIsSecure = (opcodes & LTERM_COOKIESTR_CODE);
00592 
00593         if (streamIsSecure) {
00594           // Secure stream, i.e., prefixed with cookie; fragments allowed
00595           streamURL.AssignLiteral("chrome://xmlterm/content/xmltblank.html");
00596 
00597           if (opcodes & LTERM_JSSTREAM_CODE) {
00598             // Javascript stream 
00599             streamMarkupType = JS_FRAGMENT;
00600 
00601           } else {
00602             // HTML/XML stream
00603             streamMarkupType = HTML_FRAGMENT;
00604           }
00605 
00606         } else {
00607           // Insecure stream; do not display
00608           streamURL.AssignLiteral("http://in.sec.ure");
00609           streamMarkupType = INSECURE_FRAGMENT;
00610         }
00611 
00612         if (!(opcodes & LTERM_JSSTREAM_CODE) &&
00613             (opcodes & LTERM_DOCSTREAM_CODE)) {
00614           // Stream contains complete document (not Javascript)
00615 
00616           if (opcodes & LTERM_XMLSTREAM_CODE) {
00617             streamMarkupType = XML_DOCUMENT;
00618           } else {
00619             streamMarkupType = HTML_DOCUMENT;
00620           }
00621         }
00622 
00623         // Initialize stream output
00624         result = InitStream(streamURL, streamMarkupType, streamIsSecure);
00625         if (NS_FAILED(result))
00626           break;
00627       }
00628 
00629       // Process stream output
00630       bufStyle.SetLength(0);
00631       result = ProcessOutput(bufString, bufStyle, PR_FALSE, PR_TRUE);
00632       if (NS_FAILED(result))
00633         break;
00634 
00635       if (newline) {
00636         if (!mEntryHasOutput) {
00637           // Start of command output
00638           mEntryHasOutput = PR_TRUE;
00639         }
00640 
00641         if (errorFlag) {
00642           mOutputMarkupType = INCOMPLETE_FRAGMENT;
00643         }
00644 
00645         // Break stream output display
00646         result = BreakOutput(PR_TRUE);
00647         if (NS_FAILED(result))
00648           break;
00649 
00650         mOutputType = LINE_OUTPUT;
00651         flushOutput = PR_TRUE;
00652       }
00653 
00654     } else if (screenData) {
00655       // Process screen data
00656 
00657       if (opcodes & LTERM_CLEAR_CODE) {
00658         // Clear screen
00659         XMLT_LOG(mozXMLTermSession::ReadAll,62,
00660                  ("Clear screen, opvals=%d, buf_row=%d\n",
00661                   opvals, buf_row));
00662 
00663         nsCOMPtr<nsIDOMNode> resultNode;
00664         result = mBodyNode->RemoveChild(mScreenNode,
00665                                            getter_AddRefs(resultNode));
00666         if (NS_FAILED(result))
00667           break;
00668 
00669         mScreenNode = nsnull;
00670 
00671         // Create new screen element
00672         result = NewScreen();
00673         if (NS_FAILED(result))
00674           break;
00675 
00676       } else if (opcodes & LTERM_INSERT_CODE) {
00677         // Insert rows
00678         PRInt32 row;
00679         nsCOMPtr<nsIDOMNode> rowNode, resultNode;
00680 
00681         XMLT_LOG(mozXMLTermSession::ReadAll,62,
00682                  ("Insert rows, opvals=%d, buf_row=%d\n",
00683                   opvals, buf_row));
00684 
00685         if (opvals > 0) {
00686           // Delete row elements below
00687           for (row=0; row < opvals; row++) {
00688             result = GetRow(mBotScrollRow+opvals-1, getter_AddRefs(rowNode));
00689             if (NS_FAILED(result) || !rowNode)
00690               break;
00691 
00692             result = mScreenNode->RemoveChild(rowNode,
00693                                               getter_AddRefs(resultNode));
00694             if (NS_FAILED(result))
00695               break;
00696           }
00697           if (NS_FAILED(result))
00698             break;
00699 
00700           // Insert individual row elements above
00701           if (buf_row < opvals) {
00702             rowNode = nsnull;
00703           } else {
00704             result = GetRow(buf_row, getter_AddRefs(rowNode));
00705             if (NS_FAILED(result))
00706               break;
00707           }
00708 
00709           for (row=0; row < opvals; row++)
00710             NewRow(rowNode, getter_AddRefs(resultNode));
00711         }
00712 
00713       } else if (opcodes & LTERM_DELETE_CODE) {
00714         // Delete rows
00715         PRInt32 row;
00716         nsCOMPtr<nsIDOMNode> rowNode, resultNode;
00717 
00718         XMLT_LOG(mozXMLTermSession::ReadAll,62,
00719                  ("Delete rows, opvals=%d, buf_row=%d\n",
00720                   opvals, buf_row));
00721 
00722         if (opvals > 0) {
00723           // Delete row elements below
00724           for (row=0; row < opvals; row++) {
00725             result = GetRow(buf_row, getter_AddRefs(rowNode));
00726             if (NS_FAILED(result) || !rowNode)
00727               break;
00728 
00729             result = mScreenNode->RemoveChild(rowNode,
00730                                               getter_AddRefs(resultNode));
00731             if (NS_FAILED(result))
00732               break;
00733           }
00734           if (NS_FAILED(result))
00735             break;
00736 
00737           // Insert individual row elements above
00738           if (mBotScrollRow == 0) {
00739             rowNode = nsnull;
00740           } else {
00741             result = GetRow(mBotScrollRow+opvals-1, getter_AddRefs(rowNode));
00742             if (NS_FAILED(result))
00743               break;
00744           }
00745 
00746           for (row=0; row < opvals; row++)
00747             NewRow(rowNode, getter_AddRefs(resultNode));
00748         }
00749 
00750       } else if (opcodes & LTERM_SCROLL_CODE) {
00751         // Set scrolling region
00752         XMLT_LOG(mozXMLTermSession::ReadAll,62,
00753                  ("Set scrolling region, opvals=%d, buf_row=%d\n",
00754                   opvals, buf_row));
00755 
00756         mTopScrollRow = opvals;
00757         mBotScrollRow = buf_row;
00758 
00759       } else if (opcodes & LTERM_OUTPUT_CODE) {
00760         // Display row
00761         XMLT_LOG(mozXMLTermSession::ReadAll,62,
00762                  ("Display buf_row=%d\n",
00763                   buf_row));
00764 
00765         result = DisplayRow(bufString, bufStyle, buf_row);
00766         if (NS_FAILED(result))
00767           break;
00768       }
00769 
00770       // Determine cursor position and position cursor
00771       PRInt32 cursorRow = 0;
00772       PRInt32 cursorCol = 0;
00773       result = lineTermAux->GetCursorRow(&cursorRow);
00774       result = lineTermAux->GetCursorColumn(&cursorCol);
00775 
00776       XMLT_LOG(mozXMLTermSession::ReadAll,62, ("cursorRow=%d, cursorCol=%d\n",
00777                                                cursorRow, cursorCol));
00778 
00779       result = PositionScreenCursor(cursorRow, cursorCol);
00780 
00781       flushOutput = PR_FALSE;
00782 
00783     } else {
00784       // Process line data
00785       PRBool promptLine, inputLine, metaCommand, completionRequested;
00786 
00787       flushOutput = PR_TRUE;
00788 
00789       inputLine =   (opcodes & LTERM_INPUT_CODE);
00790       promptLine =  (opcodes & LTERM_PROMPT_CODE);
00791       metaCommand = (opcodes & LTERM_META_CODE);
00792       completionRequested = (opcodes & LTERM_COMPLETION_CODE);
00793 
00794       nsAutoString promptStr;
00795       PRInt32 promptLength = 0;
00796       promptStr.SetLength(0);
00797 
00798       if (promptLine) {
00799         // Count prompt characters
00800         const PRUnichar *styleVals = bufStyle.get();
00801         const PRInt32 bufLength = bufStyle.Length();
00802 
00803         for (promptLength=0; promptLength<bufLength; promptLength++) {
00804           if (styleVals[promptLength] != LTERM_PROMPT_STYLE)
00805             break;
00806         }
00807 
00808         XMLT_LOG(mozXMLTermSession::ReadAll,62,
00809                  ("bufLength=%d, promptLength=%d, styleVals[0]=0x%x\n",
00810                   bufLength, promptLength, styleVals[0]));
00811 
00812         PR_ASSERT(promptLength > 0);
00813 
00814         // Extract prompt string
00815         bufString.Left(promptStr, promptLength);
00816 
00817         if ( (promptLength < bufLength) &&
00818              !inputLine &&
00819              !promptStr.Equals(mShellPrompt) ) {
00820           // Ignore the mismatched prompt in the output line
00821           int j;
00822           promptLine = 0;
00823 
00824           for (j=0; j<promptLength; j++)
00825             bufStyle.SetCharAt((UNICHAR) LTERM_STDOUT_STYLE, j);
00826 
00827         } else {
00828           // Remove prompt chars/style from buffer strings
00829           bufString.Cut(0, promptLength);
00830           bufStyle.Cut(0, promptLength);
00831 
00832           // Save prompt string
00833           mShellPrompt = promptStr;
00834         }
00835       }
00836 
00837       if (!metaCommand && inputLine) {
00838         if (metaNextCommand) {
00839           // Echo of transmitted meta command
00840           metaNextCommand = PR_FALSE;
00841 
00842         } else {
00843           // No meta command; enable input echo
00844           mMetaCommandType = NO_META_COMMAND;
00845 
00846           if (mRestoreInputEcho) {
00847             lineTermAux->SetEchoFlag(PR_TRUE);
00848             mRestoreInputEcho = PR_FALSE;
00849           }
00850         }
00851       }
00852 
00853       if (metaCommand && !completionRequested) {
00854         // Identify meta command type
00855 
00856         // Eliminate leading spaces/TABs
00857         nsAutoString metaLine = bufString;
00858         metaLine.Trim(kWhitespace, PR_TRUE, PR_FALSE);
00859 
00860         int delimOffset = metaLine.FindChar((PRUnichar) ':');
00861         PR_ASSERT(delimOffset >= 0);
00862 
00863         XMLT_LOG(mozXMLTermSession::ReadAll,62,
00864                  ("delimOffset=%d\n", delimOffset));
00865 
00866         if (delimOffset == 0) {
00867           // Default protocol
00868           mMetaCommandType = DEFAULT_META_COMMAND;
00869 
00870         } else {
00871           // Identify meta command type
00872           mMetaCommandType = NO_META_COMMAND;
00873 
00874           nsAutoString temString;
00875           metaLine.Left(temString, delimOffset);
00876 
00877           PRInt32 j;
00878           for (j=NO_META_COMMAND+1; j<META_COMMAND_TYPES; j++) {
00879             if (temString.EqualsASCII(metaCommandNames[j])) {
00880               mMetaCommandType = (MetaCommandType) j;
00881               break;
00882             }
00883           }
00884         }
00885 
00886         XMLT_LOG(mozXMLTermSession::ReadAll,62,("mMetaCommandType=%d\n",
00887                                                mMetaCommandType));
00888 
00889         // Extract command arguments
00890         int argChars = metaLine.Length() - delimOffset - 1;
00891         nsAutoString commandArgs;
00892         metaLine.Right(commandArgs, argChars);
00893 
00894         // Eliminate leading spaces/TABs
00895         commandArgs.Trim(kWhitespace, PR_TRUE, PR_FALSE);
00896 
00897         // Display meta command
00898         if (mEntryHasOutput) {
00899           // Break previous output display
00900           result = BreakOutput(PR_FALSE);
00901 
00902           // Create new entry block
00903           result = NewEntry(promptStr);
00904           if (NS_FAILED(result))
00905             break;
00906         }
00907 
00908         // Display input and position cursor
00909         PRInt32 cursorCol = 0;
00910         result = lineTermAux->GetCursorColumn(&cursorCol);
00911 
00912         // Remove prompt offset
00913         cursorCol -= promptLength;
00914         if (cursorCol < 0) cursorCol = 0;
00915 
00916         XMLT_LOG(mozXMLTermSession::ReadAll,62,("cursorCol=%d\n", cursorCol));
00917 
00918         result = DisplayInput(bufString, bufStyle, cursorCol);
00919         if (NS_FAILED(result))
00920           break;
00921 
00922         if (newline && mXMLTerminal) {
00923           // Complete meta command; XMLterm instantiated
00924           nsAutoString metaCommandOutput;
00925          metaCommandOutput.SetLength(0);
00926 
00927           nsCOMPtr<nsIDOMDocument> domDoc;
00928           result = mXMLTerminal->GetDOMDocument(getter_AddRefs(domDoc));
00929           if (NS_FAILED(result) || !domDoc)
00930             break;
00931 
00932           switch (mMetaCommandType) {
00933 
00934           case DEFAULT_META_COMMAND:
00935             {
00936               // Construct Javascript command to handle default meta command
00937               nsAutoString JSCommand;
00938              JSCommand.AssignLiteral("MetaDefault(\"");
00939               JSCommand.Append(commandArgs);
00940               JSCommand.Append(NS_LITERAL_STRING("\");"));
00941 
00942               // Execute JavaScript command
00943               result = mozXMLTermUtils::ExecuteScript(domDoc,
00944                                                       JSCommand,
00945                                                       metaCommandOutput);
00946               nsCAutoString cstrout;
00947               if (NS_SUCCEEDED(result))
00948                 CopyUCS2toASCII(metaCommandOutput, cstrout);
00949               else
00950                 cstrout = "Error in displaying URL\n";
00951               XMLT_LOG(mozXMLTermSession::ReadAll,63,
00952                        ("DEFAULT_META output=%s\n", cstrout.get()));
00953 
00954             }
00955             break;
00956 
00957           case HTTP_META_COMMAND:
00958             {
00959               // Display URL using IFRAME
00960               nsAutoString url;
00961              url.AssignLiteral("http:");
00962               url.Append(commandArgs);
00963               nsAutoString width;
00964              width.AssignLiteral("100%");
00965               nsAutoString height;
00966              height.AssignLiteral("100");
00967               result = NewIFrame(mOutputBlockNode, mCurrentEntryNumber,
00968                                  2, url, width, height);
00969               if (NS_FAILED(result))
00970                 metaCommandOutput.AssignLiteral("Error in displaying URL\n");
00971 
00972             }
00973             break;
00974 
00975           case JS_META_COMMAND:
00976             {
00977               // Execute JavaScript command
00978               result = mozXMLTermUtils::ExecuteScript(domDoc,
00979                                                       commandArgs,
00980                                                       metaCommandOutput);
00981               nsCAutoString cstrout;
00982               if (NS_SUCCEEDED(result))
00983                 CopyUCS2toASCII(metaCommandOutput, cstrout);
00984               else
00985                 cstrout = "Error in executing JavaScript command\n";
00986               XMLT_LOG(mozXMLTermSession::ReadAll,63,
00987                        ("JS output=%s\n", cstrout.get()));
00988 
00989             }
00990             break;
00991 
00992           case TREE_META_COMMAND:
00993             XMLT_WARNING("\nTraverseDOMTree: use arrow keys; A for attributes; H for HTML; Q to quit\n");
00994             break;
00995 
00996           case LS_META_COMMAND:
00997             {
00998               // Disable input echo and transmit command
00999               lineTermAux->SetEchoFlag(PR_FALSE);
01000               nsAutoString lsCommand;
01001               lsCommand.SetLength(0);
01002 
01003               if (!commandArgs.IsEmpty()) {
01004                 lsCommand.AppendLiteral("cd ");
01005                 lsCommand.Append(commandArgs);
01006                 lsCommand.AppendLiteral(";");
01007               }
01008 
01009               lsCommand.AppendLiteral("ls -dF `pwd`/*\n");
01010 
01011               //mXMLTerminal->SendText(lsCommand);
01012 
01013               /* Set flag to recognize transmitted command */
01014               metaNextCommand = PR_TRUE;
01015               mRestoreInputEcho = PR_TRUE;
01016             }
01017             break;
01018 
01019           default:
01020             break;
01021           }
01022 
01023           if ((mMetaCommandType == DEFAULT_META_COMMAND) ||
01024               (mMetaCommandType == JS_META_COMMAND)) {
01025             // Display metacommand output
01026             mEntryHasOutput = PR_TRUE;
01027 
01028             XMLT_LOG(mozXMLTermSession::ReadAll,62,("metaCommandOutput\n"));
01029 
01030             // Ignore the string "false", if that's the only output
01031             if (metaCommandOutput.EqualsLiteral("false"))
01032               metaCommandOutput.SetLength(0);
01033 
01034             // Check metacommand output for markup (secure)
01035             result = AutoDetectMarkup(metaCommandOutput, PR_TRUE, PR_TRUE);
01036             if (NS_FAILED(result))
01037               break;
01038 
01039             nsAutoString nullStyle;
01040             nullStyle.SetLength(0);
01041             result = ProcessOutput(metaCommandOutput, nullStyle, PR_TRUE,
01042                                    mOutputMarkupType != PLAIN_TEXT);
01043             if (NS_FAILED(result))
01044               break;
01045 
01046             // Break metacommand output display
01047             result = BreakOutput(PR_FALSE);
01048           }
01049 
01050           // Reset newline flag
01051           newline = PR_FALSE;
01052         }
01053 
01054         // Clear the meta command from the string nuffer
01055         bufString.SetLength(0);
01056         bufStyle.SetLength(0);
01057       }
01058 
01059       if (promptLine) {
01060         // Prompt line
01061         if (mEntryHasOutput) {
01062           // Break previous output display
01063           result = BreakOutput(PR_FALSE);
01064 
01065           // Create new entry block
01066           result = NewEntry(promptStr);
01067           if (NS_FAILED(result))
01068             break;
01069 
01070           if (mCurrentEntryNumber == mStartEntryNumber) {
01071             // First entry; resize terminal
01072             result = Resize(lineTermAux);
01073             if (NS_FAILED(result))
01074               break;
01075           }
01076         }
01077 
01078         // Display input and position cursor
01079         PRInt32 cursorCol = 0;
01080         result = lineTermAux->GetCursorColumn(&cursorCol);
01081 
01082         // Remove prompt offset
01083         cursorCol -= promptLength;
01084         if (cursorCol < 0) cursorCol = 0;
01085 
01086         XMLT_LOG(mozXMLTermSession::ReadAll,62,("cursorCol=%d\n", cursorCol));
01087 
01088         result = DisplayInput(bufString, bufStyle, cursorCol);
01089         if (NS_FAILED(result))
01090           break;
01091 
01092         if (newline) {
01093           // Start of command output
01094           // (this is needed to properly handle commands with no output!)
01095           mEntryHasOutput = PR_TRUE;
01096           mFirstOutputLine = PR_TRUE;
01097 
01098         }
01099 
01100       } else {
01101         // Not prompt line
01102         if (!mEntryHasOutput) {
01103           // Start of command output
01104           mEntryHasOutput = PR_TRUE;
01105           mFirstOutputLine = PR_TRUE;
01106         }
01107 
01108         if (newline) {
01109           // Complete line; check for markup (insecure)
01110           result = AutoDetectMarkup(bufString, mFirstOutputLine, PR_FALSE);
01111           if (NS_FAILED(result))
01112             break;
01113 
01114           // Not first output line anymore
01115           mFirstOutputLine = PR_FALSE;
01116         }
01117 
01118         if (mOutputMarkupType == PLAIN_TEXT) {
01119           // Display plain text output
01120           result = ProcessOutput(bufString, bufStyle, newline, PR_FALSE);
01121           if (NS_FAILED(result))
01122             break;
01123 
01124         } else if (newline) {
01125           // Process autodetected stream output (complete lines only)
01126           bufStyle.SetLength(0);
01127           result = ProcessOutput(bufString, bufStyle, PR_TRUE, PR_TRUE);
01128           if (NS_FAILED(result))
01129             break;
01130         }
01131       }
01132     }
01133   }
01134 
01135   if (NS_FAILED(result)) {
01136     // Error processing; close LineTerm
01137     XMLT_LOG(mozXMLTermSession::ReadAll,62,
01138              ("Aborting on error, result=0x%x\n", result));
01139 
01140     Abort(lineTermAux, abortCode);
01141     return result;
01142   }
01143 
01144   if (flushOutput) {
01145     // Flush output, splitting off incomplete line
01146     FlushOutput(SPLIT_INCOMPLETE_FLUSH);
01147 
01148     if (mEntryHasOutput)
01149       PositionOutputCursor(lineTermAux);
01150 
01151     nsCOMPtr<nsISelectionController> selCon;
01152     result = mXMLTerminal->GetSelectionController(getter_AddRefs(selCon));
01153     if (NS_FAILED(result) || !selCon)
01154       return NS_ERROR_FAILURE;
01155 
01156     selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
01157                                     nsISelectionController::SELECTION_FOCUS_REGION,
01158                                     PR_TRUE);
01159 
01160   }
01161 
01162   // Show caret
01163   mXMLTerminal->ShowCaret();
01164 
01165   // Scroll frame (ignore result)
01166   ScrollToBottomLeft();
01167 
01168   return NS_OK;
01169 }
01170 
01171 
01177 NS_IMETHODIMP mozXMLTermSession::ExportHTML(const PRUnichar* aFilename,
01178                                             PRInt32 permissions,
01179                                             const PRUnichar* style,
01180                                             PRUint32 refreshSeconds,
01181                                             PRBool forceExport,
01182                                             PRBool* exported)
01183 {
01184   nsresult result;
01185 
01186   if (!aFilename || !exported)
01187     return NS_ERROR_NULL_POINTER;
01188 
01189   *exported = PR_FALSE;
01190 
01191   if (forceExport)
01192     mLastExportHTML.SetLength(0);
01193 
01194   nsAutoString indentString; indentString.SetLength(0);
01195   nsAutoString htmlString;
01196   result = ToHTMLString(mBodyNode, indentString, htmlString,
01197                         PR_TRUE, PR_FALSE );
01198   if (NS_FAILED(result))
01199     return NS_ERROR_FAILURE;
01200 
01201   if (htmlString.Equals(mLastExportHTML))
01202     return NS_OK;
01203 
01204   mLastExportHTML.Assign( htmlString );
01205   mCountExportHTML++;
01206 
01207   nsAutoString filename( aFilename );
01208 
01209   if (filename.IsEmpty()) {
01210     // Write to STDERR
01211     char* htmlCString = ToNewCString(htmlString);
01212     fprintf(stderr, "mozXMLTermSession::ExportHTML:\n%s\n\n", htmlCString);
01213     nsCRT::free(htmlCString);
01214 
01215     *exported = PR_TRUE;
01216     return NS_OK;
01217   }
01218 
01219   // Copy HTML to local file
01220   nsCOMPtr<nsILocalFile> localFile = do_CreateInstance( NS_LOCAL_FILE_CONTRACTID, &result);
01221   if (NS_FAILED(result))
01222     return NS_ERROR_FAILURE;
01223 
01224   XMLT_LOG(mozXMLTermSession::ExportHTML,0,
01225            ("Exporting %d\n", mCountExportHTML));
01226 
01227   result = localFile->InitWithPath(filename);
01228   if (NS_FAILED(result))
01229     return NS_ERROR_FAILURE;
01230 
01231   PRInt32 ioFlags = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE;
01232 
01233   nsCOMPtr<nsIOutputStream> outStream;
01234   result = NS_NewLocalFileOutputStream(getter_AddRefs(outStream),
01235                                        localFile, ioFlags, permissions);
01236   if (NS_FAILED(result))
01237     return NS_ERROR_FAILURE;
01238 
01239   PRUint32 writeCount;
01240 
01241   nsCAutoString cString( "<html>\n<head>\n" );
01242 
01243   if (refreshSeconds > 0) {
01244      cString.Append("<META HTTP-EQUIV='refresh' content='");
01245      cString.AppendInt(refreshSeconds);
01246      cString.Append("'>");
01247   }
01248 
01249   cString.Append("<title>xmlterm page</title>\n");
01250   cString.Append("<link title='defaultstyle' rel='stylesheet' type='text/css' href='xmlt.css'>\n");
01251 
01252   if (style) {
01253     cString.Append("<style type='text/css'>\n");
01254     AppendUTF16toUTF8(style, cString);
01255     cString.Append("</style>\n");
01256   }
01257 
01258   cString.Append("<script language='JavaScript'>var exportCount=");
01259   cString.AppendInt(mCountExportHTML);
01260   cString.Append(";</script>\n");
01261   cString.Append("<script language='JavaScript' src='xmlt.js'></script>\n</head>");
01262 
01263   AppendUTF16toUTF8(htmlString, cString);
01264 
01265   cString.Append("</html>\n");
01266 
01267   result = outStream->Write(cString.get(), cString.Length(),
01268                             &writeCount);
01269   if (NS_FAILED(result))
01270     return NS_ERROR_FAILURE;
01271 
01272   result = outStream->Flush();
01273 
01274   result = outStream->Close();
01275 
01276   *exported = PR_TRUE;
01277   return NS_OK;
01278 }
01279 
01280 
01285 NS_IMETHODIMP mozXMLTermSession::Abort(mozILineTermAux* lineTermAux,
01286                                        nsString& abortCode)
01287 {
01288   nsresult result;
01289 
01290   XMLT_LOG(mozXMLTermSession::Abort,70,
01291            ("Aborting session; closing LineTerm\n"));
01292 
01293   // Close LineTerm
01294   lineTermAux->CloseAux();
01295 
01296   // Display error message using DIV node
01297   nsCOMPtr<nsIDOMNode> divNode, textNode;
01298   nsAutoString tagName(NS_LITERAL_STRING("div"));
01299   nsAutoString elementName(NS_LITERAL_STRING("errmsg"));
01300   result = NewElementWithText(tagName, elementName, -1,
01301                               mSessionNode, divNode, textNode);
01302 
01303   if (NS_SUCCEEDED(result) && divNode && textNode) {
01304     nsAutoString errMsg(NS_LITERAL_STRING("Error in XMLterm (code "));
01305     errMsg.Append(abortCode);
01306     errMsg.Append(NS_LITERAL_STRING("); session closed."));
01307     SetDOMText(textNode, errMsg);
01308 
01309     // Collapse selection and position cursor
01310     nsCOMPtr<nsISelectionController> selCon;
01311     result = mXMLTerminal->GetSelectionController(getter_AddRefs(selCon));
01312     if (NS_FAILED(result) || !selCon)
01313       return NS_ERROR_FAILURE;
01314 
01315     nsCOMPtr<nsISelection> selection;
01316     result = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
01317                                       getter_AddRefs(selection));
01318     if (NS_SUCCEEDED(result) && selection) {
01319       selection->Collapse(textNode, errMsg.Length());
01320       if (NS_SUCCEEDED(result)) {
01321         selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
01322                                         nsISelectionController::SELECTION_FOCUS_REGION,
01323                                         PR_TRUE);
01324       }
01325     }
01326   }
01327 
01328   return NS_OK;
01329 }
01330 
01331 
01337 NS_IMETHODIMP mozXMLTermSession::DisplayInput(const nsString& aString,
01338                                               const nsString& aStyle,
01339                                               PRInt32 cursorCol)
01340 {
01341   nsresult result;
01342 
01343   XMLT_LOG(mozXMLTermSession::DisplayInput,70,("cursorCol=%d\n", cursorCol));
01344 
01345   // If string terminates in whitespace, append NBSP for cursor positioning
01346   nsAutoString tempString( aString );
01347   if (!aString.IsEmpty() && aString.Last() == PRUnichar(' '))
01348     tempString += kNBSP;
01349 
01350   // Display string
01351   result = SetDOMText(mInputTextNode, tempString);
01352 
01353   if (NS_FAILED(result))
01354     return NS_ERROR_FAILURE;
01355 
01356   char* temCString = ToNewCString(aString);
01357   XMLT_LOG(mozXMLTermSession::DisplayInput,72,
01358            ("aString=%s\n", temCString));
01359   nsCRT::free(temCString);
01360 
01361   // Collapse selection and position cursor
01362   nsCOMPtr<nsISelectionController> selCon;
01363   result = mXMLTerminal->GetSelectionController(getter_AddRefs(selCon));
01364   if (NS_FAILED(result) || !selCon)
01365       return NS_ERROR_FAILURE;
01366 
01367   nsCOMPtr<nsISelection> selection;
01368 
01369   result = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
01370                                     getter_AddRefs(selection));
01371   if (NS_FAILED(result) || !selection)
01372     return NS_ERROR_FAILURE;
01373 
01374 #ifdef NO_WORKAROUND
01375   // Collapse selection to new cursor location
01376   result = selection->Collapse(mInputTextNode, cursorCol);
01377 #else
01378   // WORKAROUND for cursor positioning at end of prompt
01379   // Without this workaround, the cursor is positioned too close to the prompt
01380   // (i.e., too far to the left, ignoring the prompt whitespace)
01381 
01382   if ((cursorCol > 0) || !mPromptHTML.IsEmpty()) {
01383     // Collapse selection to new cursor location
01384     result = selection->Collapse(mInputTextNode, cursorCol);
01385 
01386   } else {
01387     // Get the last bit of text in the prompt
01388     nsCOMPtr<nsIDOMText> domText (do_QueryInterface(mPromptTextNode));
01389 
01390     if (domText) {
01391       PRUint32 textLength;
01392       result = domText->GetLength(&textLength);
01393       if (NS_SUCCEEDED(result)) {
01394         XMLT_LOG(mozXMLTermSession::DisplayInput,72,
01395                  ("textLength=%d\n", textLength));
01396         result = selection->Collapse(mPromptTextNode, textLength);
01397       }
01398     }
01399   }
01400 #endif // !NO_WORKAROUND
01401 
01402   NS_ASSERTION((NS_SUCCEEDED(result)),
01403                  "selection could not be collapsed after insert.");
01404 
01405   return NS_OK;
01406 }
01407 
01408 
01415 NS_IMETHODIMP mozXMLTermSession::AutoDetectMarkup(const nsString& aString,
01416                                                   PRBool firstOutputLine,
01417                                                   PRBool secure)
01418 {
01419   nsresult result;
01420 
01421   XMLT_LOG(mozXMLTermSession::AutoDetectMarkup,70,("firstOutputLine=0x%x\n",
01422                                                    firstOutputLine));
01423 
01424   // If autodetect disabled or not plain text, do nothing
01425   if ((mAutoDetect == NO_MARKUP) ||
01426       ((mAutoDetect == FIRST_LINE) && !firstOutputLine) ||
01427       (mOutputMarkupType != PLAIN_TEXT))
01428     return NS_OK;
01429 
01430   OutputMarkupType newMarkupType = PLAIN_TEXT;
01431 
01432   // Copy string and trim leading spaces/backspaces/tabs
01433   nsAutoString str(aString);
01434   
01435   str.Trim(kWhitespace, PR_TRUE, PR_FALSE);
01436 
01437   if (str.First() == U_LESSTHAN) {
01438     // Markup tag detected
01439     str.CompressWhitespace();
01440     str.AppendLiteral(" ");
01441 
01442     if ( (str.Find("<!DOCTYPE HTML",PR_TRUE) == 0) ||
01443          (str.Find("<BASE ",PR_TRUE) == 0) ||
01444          (str.Find("<HTML>",PR_TRUE) == 0) ) {
01445       // HTML document
01446       newMarkupType = HTML_DOCUMENT;
01447 
01448     } else if (str.Find("<?xml ",PR_FALSE) == 0) {
01449       // XML document
01450       newMarkupType = XML_DOCUMENT;
01451 
01452     } else {
01453       // HTML fragment
01454       if (secure) {
01455         // Secure HTML fragment
01456         newMarkupType = HTML_FRAGMENT;
01457       } else {
01458         // Insecure; treat as text fragment for security reasons
01459         newMarkupType = TEXT_FRAGMENT;
01460       }
01461     }
01462 
01463 
01464   } else if (firstOutputLine && str.Find("Content-Type",PR_TRUE) == 0) {
01465     // Possible MIME content type header
01466     str.StripWhitespace();
01467     if (str.Find("Content-Type:text/html",PR_TRUE) == 0) {
01468       // MIME content type header for HTML document
01469       newMarkupType = HTML_DOCUMENT;
01470     }
01471   }
01472 
01473   if (newMarkupType != PLAIN_TEXT) {
01474     // Markup found; initialize (insecure) stream
01475     nsAutoString streamURL(NS_LITERAL_STRING("http://in.sec.ure"));
01476     result = InitStream(streamURL, newMarkupType, PR_FALSE);
01477     if (NS_FAILED(result))
01478       return result;
01479 
01480   } else {
01481     // No markup found; assume rest of output is plain text
01482     mOutputMarkupType = PLAIN_TEXT;
01483   }
01484 
01485   XMLT_LOG(mozXMLTermSession::AutoDetectMarkup,71,("mOutputMarkupType=%d\n",
01486                                                    mOutputMarkupType));
01487 
01488   return NS_OK;
01489 }
01490 
01491 
01497 NS_IMETHODIMP mozXMLTermSession::InitStream(const nsString& streamURL,
01498                                             OutputMarkupType streamMarkupType,
01499                                             PRBool streamIsSecure)
01500 {
01501   nsresult result;
01502 
01503   XMLT_LOG(mozXMLTermSession::InitStream,70,("streamMarkupType=%d\n",
01504                                              streamMarkupType));
01505 
01506   // Break previous output display
01507   result = BreakOutput(PR_FALSE);
01508   if (NS_FAILED(result))
01509     return result;
01510 
01511   if ((streamMarkupType == TEXT_FRAGMENT)     ||
01512       (streamMarkupType == JS_FRAGMENT)       ||
01513       (streamMarkupType == HTML_FRAGMENT)     ||
01514       (streamMarkupType == INSECURE_FRAGMENT) ||
01515       (streamMarkupType == OVERFLOW_FRAGMENT) ||
01516       (streamMarkupType == INCOMPLETE_FRAGMENT)) {
01517     // Initialize fragment buffer
01518     mFragmentBuffer.SetLength(0);
01519 
01520   } else {
01521     // Create IFRAME to display stream document
01522     nsAutoString src(NS_LITERAL_STRING("about:blank"));
01523     nsAutoString width(NS_LITERAL_STRING("100%"));
01524     nsAutoString height(NS_LITERAL_STRING("10"));
01525     PRInt32 frameBorder = 0;
01526 
01527     if (!streamIsSecure)
01528       frameBorder = 2;
01529 
01530     result = NewIFrame(mOutputBlockNode, mCurrentEntryNumber,
01531                        frameBorder, src, width, height);
01532 
01533     if (NS_FAILED(result))
01534       return result;
01535 
01536     mXMLTermStream = do_CreateInstance( MOZXMLTERMSTREAM_CONTRACTID,
01537                                         &result);
01538     if (NS_FAILED(result))
01539       return result;
01540 
01541 
01542     nsCOMPtr<nsIDocShell> docShell;
01543     result = mXMLTerminal->GetDocShell(getter_AddRefs(docShell));
01544     if (NS_FAILED(result) || !docShell)
01545       return NS_ERROR_FAILURE;
01546 
01547     nsCOMPtr<nsIDOMWindowInternal> outerDOMWindow;
01548     result = mozXMLTermUtils::ConvertDocShellToDOMWindow(docShell,
01549                                               getter_AddRefs(outerDOMWindow));
01550 
01551     if (NS_FAILED(result) || !outerDOMWindow) {
01552       XMLT_ERROR("mozXMLTermSession::InitStream: Failed to convert webshell\n");
01553       return NS_ERROR_FAILURE;
01554     }
01555 
01556     // Initialize markup handling
01557     nsCAutoString iframeName("iframe");
01558 #if 0
01559     iframeName.Append("t");
01560 #else
01561     iframeName.AppendInt(mCurrentEntryNumber,10);
01562 #endif
01563 
01564     nsCAutoString contentType;
01565     switch (streamMarkupType) {
01566 
01567     case HTML_DOCUMENT:
01568       contentType = "text/html";
01569       break;
01570 
01571     case XML_DOCUMENT:
01572       contentType = "application/xml";
01573       break;
01574 
01575     default:
01576       PR_ASSERT(0);
01577       break;
01578     }
01579 
01580     NS_ConvertUTF16toUTF8 url(streamURL);
01581     result = mXMLTermStream->Open(outerDOMWindow, iframeName.get(),
01582                                   url.get(),
01583                                   contentType.get(), 800);
01584     if (NS_FAILED(result)) {
01585       XMLT_ERROR("mozXMLTermSession::InitStream: Failed to open stream\n");
01586       return result;
01587     }
01588 
01589   }
01590 
01591   mOutputMarkupType = streamMarkupType;
01592 
01593   return NS_OK;
01594 }
01595 
01596 
01598 NS_IMETHODIMP mozXMLTermSession::BreakOutput(PRBool positionCursorBelow)
01599 {
01600   nsresult result;
01601 
01602   XMLT_LOG(mozXMLTermSession::BreakOutput,70,
01603            ("positionCursorBelow=%x, mOutputMarkupType=%d\n",
01604              positionCursorBelow, mOutputMarkupType));
01605 
01606   if (!mEntryHasOutput)
01607     return NS_OK;
01608 
01609   nsCOMPtr<nsIDOMDocument> domDoc;
01610   result = mXMLTerminal->GetDOMDocument(getter_AddRefs(domDoc));
01611   if (NS_FAILED(result) || !domDoc)
01612     return NS_ERROR_FAILURE;
01613 
01614   switch (mOutputMarkupType) {
01615 
01616   case INSECURE_FRAGMENT:
01617   case OVERFLOW_FRAGMENT:
01618   case INCOMPLETE_FRAGMENT:
01619   case TEXT_FRAGMENT:
01620     {
01621       // Display text fragment using new SPAN node
01622       nsCOMPtr<nsIDOMNode> spanNode, textNode;
01623       nsAutoString tagName(NS_LITERAL_STRING("span"));
01624       nsAutoString elementName(NS_LITERAL_STRING("stream"));
01625       result = NewElementWithText(tagName, elementName, -1,
01626                                   mOutputBlockNode, spanNode, textNode);
01627 
01628       if (NS_FAILED(result) || !spanNode || !textNode)
01629         return NS_ERROR_FAILURE;
01630 
01631       // Append node
01632       nsCOMPtr<nsIDOMNode> resultNode;
01633       result = mOutputBlockNode->AppendChild(spanNode,
01634                                              getter_AddRefs(resultNode));
01635 
01636       // Handle stream output error messages
01637       switch (mOutputMarkupType) {
01638       case INSECURE_FRAGMENT:
01639         mFragmentBuffer.AssignLiteral("XMLTerm: *Error* Insecure stream data; is LTERM_COOKIE set?");
01640         break;
01641 
01642       case INCOMPLETE_FRAGMENT:
01643         mFragmentBuffer.AssignLiteral("XMLTerm: *Error* Incomplete stream data");
01644         break;
01645 
01646       default:
01647         break;
01648       }
01649 
01650       // Display text
01651       result = SetDOMText(textNode, mFragmentBuffer);
01652       if (NS_FAILED(result))
01653         return result;
01654 
01655       mFragmentBuffer.SetLength(0);
01656       break;
01657     }
01658 
01659   case JS_FRAGMENT:
01660     {
01661       // Execute JS fragment
01662       nsAutoString jsOutput;
01663       jsOutput.SetLength(0);
01664       result = mozXMLTermUtils::ExecuteScript(domDoc,
01665                                               mFragmentBuffer,
01666                                               jsOutput);
01667       if (NS_FAILED(result))
01668         jsOutput.AssignLiteral("Error in JavaScript execution\n");
01669 
01670       mFragmentBuffer.SetLength(0);
01671 
01672       if (!jsOutput.IsEmpty()) {
01673         // Display JS output as HTML fragment
01674         result = InsertFragment(jsOutput, mOutputBlockNode,
01675                                 mCurrentEntryNumber);
01676         if (NS_FAILED(result))
01677           return result;
01678       }
01679     }
01680 
01681     break;
01682 
01683   case HTML_FRAGMENT:
01684     // Display HTML fragment
01685     result = InsertFragment(mFragmentBuffer, mOutputBlockNode,
01686                             mCurrentEntryNumber);
01687     if (NS_FAILED(result))
01688       return result;
01689 
01690     mFragmentBuffer.SetLength(0);
01691     break;
01692 
01693   case HTML_DOCUMENT:
01694   case XML_DOCUMENT:
01695     // Close HTML/XML document
01696     result = mXMLTermStream->Close();
01697     if (NS_FAILED(result)) {
01698       XMLT_ERROR("mozXMLTermSession::BreakOutput: Failed to close stream\n");
01699       return result;
01700     }
01701     mXMLTermStream = nsnull;
01702     break;
01703 
01704   default:
01705     // Flush plain text output, clearing any incomplete input line
01706     result = FlushOutput(CLEAR_INCOMPLETE_FLUSH);
01707     if (NS_FAILED(result))
01708       return result;
01709 
01710     mPreTextBufferLines = 0;
01711     mPreTextBuffered.SetLength(0);
01712     mPreTextDisplayed.SetLength(0);
01713     mOutputDisplayNode = nsnull;
01714     mOutputDisplayType = NO_NODE;
01715     mOutputTextNode = nsnull;
01716     break;
01717   }
01718 
01719   // Revert to plain text type
01720   mOutputMarkupType = PLAIN_TEXT;
01721 
01722   if (positionCursorBelow) {
01723     PositionOutputCursor(nsnull);
01724   }
01725 
01726   return NS_OK;
01727 }
01728 
01729 
01737 NS_IMETHODIMP mozXMLTermSession::ProcessOutput(const nsString& aString,
01738                                                const nsString& aStyle,
01739                                                PRBool newline,
01740                                                PRBool streamOutput)
01741 {
01742   nsresult result;
01743 
01744   XMLT_LOG(mozXMLTermSession::ProcessOutput,70,
01745            ("newline=%d, streamOutput=%d\n", newline, streamOutput));
01746 
01747   if ((mMetaCommandType == LS_META_COMMAND) && newline) {
01748     // Display hypertext directory listing
01749     result = AppendLineLS(aString, aStyle);
01750     if (NS_FAILED(result))
01751       return NS_ERROR_FAILURE;
01752 
01753     return NS_OK;
01754 
01755   } else {
01756     // Not LS meta command
01757 
01758     switch (mOutputMarkupType) {
01759 
01760     case INSECURE_FRAGMENT:
01761     case OVERFLOW_FRAGMENT:
01762     case INCOMPLETE_FRAGMENT:
01763       // Do nothing
01764       break;
01765 
01766     case TEXT_FRAGMENT:
01767     case JS_FRAGMENT:
01768     case HTML_FRAGMENT:
01769       // Append complete lines to fragment buffer
01770       if (newline || streamOutput) {
01771         PRInt32 strLen = mFragmentBuffer.Length()+aString.Length();
01772 
01773         if (strLen < 100000) {
01774           mFragmentBuffer += aString;
01775           if (newline)
01776             mFragmentBuffer += PRUnichar('\n');
01777 
01778         } else {
01779           mOutputMarkupType = OVERFLOW_FRAGMENT;
01780           mFragmentBuffer.AssignLiteral("XMLTerm: *Error* Stream data overflow (");
01781           mFragmentBuffer.AppendInt(strLen,10);
01782           mFragmentBuffer.Append(NS_LITERAL_STRING(" chars)"));
01783         break;
01784 
01785         }
01786       }
01787 
01788       break;
01789 
01790     case HTML_DOCUMENT:
01791     case XML_DOCUMENT:
01792       // Write complete lines to document stream
01793 
01794       if (newline || streamOutput) {
01795         nsAutoString str(aString);
01796         if (newline)
01797           str.AppendLiteral("\n");
01798 
01799         result = mXMLTermStream->Write(str.get());
01800         if (NS_FAILED(result)) {
01801           XMLT_ERROR("mozXMLTermSession::ProcessOutput: Failed to write to stream\n");
01802           return result;
01803         }
01804       }
01805       break;
01806 
01807     default:
01808       // Display plain text output, complete or incomplete lines
01809       PR_ASSERT(!streamOutput);
01810       result = AppendOutput(aString, aStyle, newline);
01811       if (NS_FAILED(result))
01812         return NS_ERROR_FAILURE;
01813       break;
01814     }
01815 
01816     return NS_OK;
01817   }
01818 }
01819 
01820 
01826 NS_IMETHODIMP mozXMLTermSession::LimitOutputLines(PRBool deleteAllOld)
01827 {
01828   nsresult result;
01829   nsAutoString attValue;
01830 
01831   XMLT_LOG(mozXMLTermSession::LimitOutputLines,70,
01832            ("deleteAllOld=%d, mEntryOutputLines=%d\n",
01833             deleteAllOld, mEntryOutputLines));
01834 
01835   nsCOMPtr<nsIDOMNode> firstChild;
01836   result = mOutputBlockNode->GetFirstChild(getter_AddRefs(firstChild));
01837   if (NS_FAILED(result) || !firstChild)
01838     return NS_ERROR_FAILURE;
01839 
01840   attValue.SetLength(0);
01841   result = mozXMLTermUtils::GetNodeAttribute(firstChild, "class", attValue);
01842   if (NS_FAILED(result))
01843     return result;
01844 
01845   if (!attValue.EqualsASCII(sessionElementNames[WARNING_ELEMENT])) {
01846     // Create warning message element
01847     nsCOMPtr<nsIDOMNode> divNode, textNode;
01848     nsAutoString tagName(NS_LITERAL_STRING("div"));
01849     nsAutoString elementName; elementName.AssignASCII(sessionElementNames[WARNING_ELEMENT]);
01850     result = NewElementWithText(tagName, elementName, -1,
01851                                 mOutputBlockNode, divNode, textNode,
01852                                 firstChild);
01853     if (NS_FAILED(result) || !divNode || !textNode)
01854       return NS_ERROR_FAILURE;
01855 
01856     firstChild = divNode;
01857 
01858     nsAutoString warningMsg;
01859     warningMsg.AssignLiteral("XMLTerm: *WARNING* Command output truncated to ");
01860     warningMsg.AppendInt(300,10);
01861     warningMsg.AppendLiteral(" lines");
01862     result = SetDOMText(textNode, warningMsg);
01863   }
01864 
01865   PR_ASSERT(mOutputDisplayNode != firstChild);
01866 
01867   nsCOMPtr<nsIDOMNode> nextChild;
01868 
01869   PRInt32 decrementedLineCount = 0;
01870 
01871   for (;;) {
01872     result = firstChild->GetNextSibling(getter_AddRefs(nextChild));
01873     PR_ASSERT(NS_SUCCEEDED(result) && nextChild);
01874 
01875     // Do not modify current display node
01876     if (nextChild.get() == mOutputDisplayNode.get())
01877       break;
01878 
01879     PRInt32 deleteNode = 0;
01880 
01881     if (deleteAllOld) {
01882       deleteNode = 1;
01883 
01884     } else {
01885       attValue.SetLength(0);
01886       result = mozXMLTermUtils::GetNodeAttribute(nextChild, "class", attValue);
01887 
01888       if (NS_FAILED(result) || attValue.IsEmpty()) {
01889         deleteNode = 1;
01890 
01891       } else {
01892 
01893         if (attValue.EqualsASCII(sessionElementNames[MIXED_ELEMENT])) {
01894           // Delete single line containing mixed style output
01895           deleteNode = 1;
01896           decrementedLineCount = 1;
01897 
01898           XMLT_LOG(mozXMLTermSession::LimitOutputLines,79,
01899                    ("deleted mixed line\n"));
01900 
01901         } else if ( (attValue.EqualsASCII(sessionElementNames[STDIN_ELEMENT]))  ||
01902                     (attValue.EqualsASCII(sessionElementNames[STDOUT_ELEMENT])) ||
01903                     (attValue.EqualsASCII(sessionElementNames[STDERR_ELEMENT]))) {
01904           // Delete first line from STDIN/STDOUT/STDERR PRE output
01905 
01906           nsCOMPtr<nsIDOMNode> textNode;
01907           result = nextChild->GetFirstChild(getter_AddRefs(textNode));
01908           PR_ASSERT( NS_SUCCEEDED(result) && textNode);
01909 
01910           nsCOMPtr<nsIDOMText> domText (do_QueryInterface(textNode));
01911           PR_ASSERT(domText);
01912 
01913           // Delete first line from text
01914           nsAutoString text;
01915           domText->GetData(text);
01916 
01917           PRInt32 offset = text.FindChar((PRUnichar) U_LINEFEED);
01918 
01919           if (offset < 0) {
01920             deleteNode = 1;
01921           } else {
01922             text.Cut(0,offset+1);
01923             domText->SetData(text);
01924           }
01925           decrementedLineCount = 1;
01926 
01927           XMLT_LOG(mozXMLTermSession::LimitOutputLines,79,
01928                    ("deleted PRE line\n"));
01929 
01930         } else {
01931           // Unknown type of DOM element, delete
01932           deleteNode = 1;
01933         }
01934       }
01935     }
01936 
01937     if (deleteNode) {
01938       // Delete next child node
01939       nsCOMPtr<nsIDOMNode> resultNode;
01940       result = mOutputBlockNode->RemoveChild(nextChild,
01941                                              getter_AddRefs(resultNode));
01942       if (NS_FAILED(result))
01943         return result;
01944     }
01945 
01946     if (decrementedLineCount || !deleteNode)
01947       break;
01948   }
01949 
01950   if (deleteAllOld) {
01951     mEntryOutputLines = 0;
01952     return NS_OK;
01953 
01954   } else if (decrementedLineCount) {
01955     mEntryOutputLines--;
01956     return NS_OK;
01957 
01958   } else {
01959     return NS_ERROR_FAILURE;
01960   }
01961 }
01962 
01963 
01972 NS_IMETHODIMP mozXMLTermSession::AppendOutput(const nsString& aString,
01973                                               const nsString& aStyle,
01974                                               PRBool newline)
01975 {
01976   nsresult result;
01977 
01978   const PRInt32   strLength   = aString.Length();
01979   const PRInt32   styleLength = aStyle.Length();
01980   const PRUnichar *strStyle   = aStyle.get();
01981 
01982   XMLT_LOG(mozXMLTermSession::AppendOutput,70,("strLength=%d\n", strLength));
01983 
01984   // Check if line has uniform style
01985   PRUnichar uniformStyle = LTERM_STDOUT_STYLE;
01986   PRInt32 styleChanges = 0;
01987 
01988   if (styleLength > 0) {
01989     PRInt32 j;
01990     uniformStyle = strStyle[0];
01991 
01992     PR_ASSERT((styleLength == 1) || (styleLength == strLength));
01993     for (j=1; j<styleLength; j++) {
01994       if (strStyle[j] != strStyle[j-1]) {
01995         uniformStyle = 0;
01996         styleChanges++;
01997       }
01998     }
01999   }
02000 
02001   XMLT_LOG(mozXMLTermSession::AppendOutput,72,
02002            ("mOutputDisplayType=%d, uniformStyle=0x%x, newline=%d\n",
02003             mOutputDisplayType, uniformStyle, newline));
02004 
02005   char* temCString = ToNewCString(aString);
02006   XMLT_LOG(mozXMLTermSession::AppendOutput,72,
02007            ("aString=%s\n", temCString));
02008   nsCRT::free(temCString);
02009 
02010 #ifdef NO_WORKAROUND
02011   // Do not use PRE text
02012   if (0) {
02013 #else
02014   if (uniformStyle != 0) {
02015 #endif
02016     // Uniform style data; display as preformatted block
02017     OutputDisplayType preDisplayType;
02018     nsAutoString elementName;
02019     elementName.SetLength(0);
02020 
02021     if (uniformStyle == LTERM_STDIN_STYLE) {
02022       preDisplayType = PRE_STDIN_NODE;
02023       elementName.AssignASCII(sessionElementNames[STDIN_ELEMENT]);
02024       XMLT_LOG(mozXMLTermSession::AppendOutput,72, ("PRE_STDIN_NODE\n"));
02025 
02026     } else if (uniformStyle == LTERM_STDERR_STYLE) {
02027       preDisplayType = PRE_STDERR_NODE;
02028       elementName.AssignASCII(sessionElementNames[STDERR_ELEMENT]);
02029       XMLT_LOG(mozXMLTermSession::AppendOutput,72, ("PRE_STDERR_NODE\n"));
02030 
02031     } else {
02032       preDisplayType = PRE_STDOUT_NODE;
02033       elementName.AssignASCII(sessionElementNames[STDOUT_ELEMENT]);
02034       XMLT_LOG(mozXMLTermSession::AppendOutput,72, ("PRE_STDOUT_NODE\n"));
02035     }
02036 
02037     if (mOutputDisplayType != preDisplayType) {
02038       // Flush incomplete line
02039       result = FlushOutput(CLEAR_INCOMPLETE_FLUSH);
02040 
02041       // Create PRE display node
02042       nsCOMPtr<nsIDOMNode> preNode, textNode;
02043       nsAutoString tagName(NS_LITERAL_STRING("pre"));
02044 
02045       result = NewElementWithText(tagName, elementName, -1,
02046                                   mOutputBlockNode, preNode, textNode);
02047 
02048       if (NS_FAILED(result) || !preNode || !textNode)
02049         return NS_ERROR_FAILURE;
02050 
02051       XMLT_LOG(mozXMLTermSession::AppendOutput,72,
02052                ("Creating new PRE node\n"));
02053 
02054       // Append node
02055       nsCOMPtr<nsIDOMNode> resultNode;
02056       result = mOutputBlockNode->AppendChild(preNode,
02057                                              getter_AddRefs(resultNode));
02058 
02059       mOutputDisplayType = preDisplayType;
02060       mOutputDisplayNode = preNode;
02061       mOutputTextNode = textNode;
02062       mOutputTextOffset = 0;
02063 
02064       // If string terminates in whitespace, append NBSP for cursor positioning
02065       nsAutoString tempString( aString );
02066       if (newline || (aString.Last() == PRUnichar(' ')))
02067         tempString += kNBSP;
02068 
02069       // Display incomplete line
02070       result = SetDOMText(mOutputTextNode, tempString);
02071       if (NS_FAILED(result))
02072         return NS_ERROR_FAILURE;
02073 
02074       // Initialize PRE text string buffers
02075       mPreTextDisplayed = aString;
02076       mPreTextBuffered.SetLength(0);
02077       mPreTextBufferLines = 0;
02078     }
02079 
02080     // Save incomplete line
02081     mPreTextIncomplete = aString;
02082 
02083     if (newline) {
02084       // Complete line; append to buffer
02085       if (mPreTextBufferLines > 0) {
02086         mPreTextBuffered += PRUnichar('\n');
02087       }
02088       mPreTextBufferLines++;
02089       mPreTextBuffered += mPreTextIncomplete;
02090       mPreTextIncomplete.SetLength(0);
02091 
02092       if (mPreTextBufferLines > 300) {
02093         // Delete all earlier PRE/mixed blocks and first line of current block
02094 
02095         result = LimitOutputLines(PR_TRUE);
02096         if (NS_FAILED(result))
02097           return result;
02098 
02099         // Delete first line from PRE text buffer
02100         PRInt32 offset = mPreTextBuffered.FindChar((PRUnichar) U_LINEFEED);
02101         if (offset < 0) {
02102           mPreTextBuffered.SetLength(0);
02103         } else {
02104           mPreTextBuffered.Cut(0,offset+1);
02105         }
02106 
02107         mPreTextBufferLines--;
02108 
02109       } else if (mEntryOutputLines+mPreTextBufferLines > 300) {
02110         // Delete oldest PRE/mixed line so as to stay within the limit
02111 
02112         result = LimitOutputLines(PR_FALSE);
02113         if (NS_FAILED(result))
02114           return result;
02115       }
02116     }
02117 
02118     XMLT_LOG(mozXMLTermSession::AppendOutput,72,
02119              ("mPreTextDisplayed.Length()=%d, mPreTextBufferLines()=%d\n",
02120               mPreTextDisplayed.Length(), mPreTextBufferLines));
02121 
02122   } else {
02123     // Create uniform style DIV display node
02124 
02125     XMLT_LOG(mozXMLTermSession::AppendOutput,72,("DIV_MIXED_NODE\n"));
02126 
02127     // Flush buffer, clearing incomplete line
02128     result = FlushOutput(CLEAR_INCOMPLETE_FLUSH);
02129     if (NS_FAILED(result))
02130       return result;
02131 
02132     // Create new DIV node
02133     nsAutoString elementName; elementName.AssignASCII(sessionElementNames[MIXED_ELEMENT]);
02134     nsCOMPtr<nsIDOMNode> divNode;
02135     nsAutoString tagName(NS_LITERAL_STRING("div"));
02136     result = NewElement(tagName, elementName, -1,
02137                         mOutputBlockNode, divNode);
02138 
02139     if (NS_FAILED(result) || !divNode)
02140       return NS_ERROR_FAILURE;
02141 
02142     // Append node
02143     nsCOMPtr<nsIDOMNode> resultNode;
02144     result = mOutputBlockNode->AppendChild(divNode,
02145                                                 getter_AddRefs(resultNode));
02146     if (NS_FAILED(result))
02147       return result;
02148 
02149     nsCOMPtr<nsIDOMNode> spanNode, textNode;
02150     nsAutoString subString;
02151     PRInt32 k;
02152     PRInt32 passwordPrompt = 0;
02153     PRUnichar currentStyle = LTERM_STDOUT_STYLE;
02154     if (styleLength > 0) 
02155       currentStyle = strStyle[0];
02156 
02157     mOutputTextOffset = 0;
02158     tagName.AssignLiteral("pre");
02159 
02160     PR_ASSERT(strLength > 0);
02161 
02162     for (k=1; k<strLength+1; k++) {
02163       if ((k == strLength) || ((k < styleLength) &&
02164                                (strStyle[k] != currentStyle)) ) {
02165         // Change of style or end of string
02166         switch (currentStyle) {
02167         case LTERM_STDIN_STYLE:
02168           elementName.AssignASCII(sessionElementNames[STDIN_ELEMENT]);
02169           break;
02170         case LTERM_STDERR_STYLE:
02171           elementName.AssignASCII(sessionElementNames[STDERR_ELEMENT]);
02172           break;
02173         default:
02174           elementName.AssignASCII(sessionElementNames[STDOUT_ELEMENT]);
02175           break;
02176         }
02177 
02178         result = NewElementWithText(tagName, elementName, -1,
02179                                     divNode, spanNode, textNode);
02180 
02181         if (NS_FAILED(result) || !spanNode || !textNode)
02182           return NS_ERROR_FAILURE;
02183 
02184         aString.Mid(subString, mOutputTextOffset, k-mOutputTextOffset);
02185         result = SetDOMText(textNode, subString);
02186         if (NS_FAILED(result))
02187           return result;
02188 
02189         if (k < styleLength) {
02190           // Change style
02191           PRInt32 strLen = subString.Length();
02192           if ((styleChanges == 1) &&
02193               (currentStyle == LTERM_STDOUT_STYLE)         &&
02194               (strStyle[k] == LTERM_STDIN_STYLE)           &&
02195               ( ((strLen-10) == subString.RFind("password: ",PR_TRUE)) ||
02196                 ((strLen-9) == subString.RFind("password:",PR_TRUE))) ) {
02197             // Password prompt detected; break loop
02198             passwordPrompt = 1;
02199             break;
02200           }
02201 
02202           currentStyle = strStyle[k];
02203           mOutputTextOffset = k;
02204         }
02205       }
02206     }
02207 
02208     mOutputDisplayType = DIV_MIXED_NODE;
02209     mOutputDisplayNode = divNode;
02210     mOutputTextNode = textNode;
02211 
02212     if (newline) {
02213       // Increment total output line count for entry
02214       mEntryOutputLines++;
02215 
02216       if (mEntryOutputLines > 300) {
02217         // Delete oldest PRE/mixed line so as to stay within the limit
02218         result = LimitOutputLines(PR_FALSE);
02219         if (NS_FAILED(result))
02220           return result;
02221       }
02222 
02223       if (passwordPrompt) {
02224         result = mOutputBlockNode->RemoveChild(mOutputDisplayNode,
02225                                                getter_AddRefs(resultNode));
02226       }
02227       mOutputDisplayType = NO_NODE;
02228       mOutputDisplayNode = nsnull;
02229       mOutputTextNode = nsnull;
02230 
02231     }
02232   }
02233 
02234   return NS_OK;
02235 }
02236 
02237 
02243 NS_IMETHODIMP mozXMLTermSession::AppendLineLS(const nsString& aString,
02244                                               const nsString& aStyle)
02245 {
02246   nsresult result;
02247 
02248   const PRInt32   strLength   = aString.Length();
02249   const PRInt32   styleLength = aStyle.Length();
02250   const PRUnichar *strStyle   = aStyle.get();
02251 
02252   // Check if line has uniform style
02253   PRUnichar allStyles = LTERM_STDOUT_STYLE;
02254   PRUnichar uniformStyle = LTERM_STDOUT_STYLE;
02255 
02256   if (styleLength > 0) {
02257     PRInt32 j;
02258     allStyles = strStyle[0];
02259     uniformStyle = strStyle[0];
02260 
02261     for (j=1; j<strLength; j++) {
02262       allStyles |= strStyle[j];
02263       if (strStyle[j] != strStyle[0]) {
02264         uniformStyle = 0;
02265       }
02266     }
02267   }
02268 
02269   XMLT_LOG(mozXMLTermSession::AppendLineLS,60,
02270            ("mOutputDisplayType=%d, uniformStyle=0x%x\n",
02271             mOutputDisplayType, uniformStyle));
02272 
02273   if (uniformStyle != LTERM_STDOUT_STYLE) {
02274     return AppendOutput(aString, aStyle, PR_TRUE);
02275   }
02276 
02277   char* temCString = ToNewCString(aString);
02278   XMLT_LOG(mozXMLTermSession::AppendLineLS,62,("aString=%s\n", temCString));
02279   nsCRT::free(temCString);
02280 
02281   // Add markup to directory listing
02282   nsAutoString markupString;
02283   PRInt32 lineLength = aString.Length();
02284   PRInt32 wordBegin = 0;
02285   markupString.SetLength(0);
02286 
02287   while (wordBegin < lineLength) {
02288     // Consume any leading spaces
02289     while ( (wordBegin < lineLength) &&
02290             ((aString[wordBegin] == U_SPACE) ||
02291              (aString[wordBegin] == U_TAB)) ) {
02292       markupString += aString[wordBegin];
02293       wordBegin++;
02294     }
02295     if (wordBegin >= lineLength) break;
02296 
02297     // Locate end of word (non-space character)
02298     PRInt32 wordEnd = aString.FindCharInSet(kWhitespace, wordBegin);
02299     if (wordEnd < 0) {
02300       wordEnd = lineLength-1;
02301     } else {
02302       wordEnd--;
02303     }
02304 
02305     PR_ASSERT(wordEnd >= wordBegin);
02306 
02307     // Locate pure filename, with possible type suffix
02308     PRInt32 nameBegin;
02309     if (wordEnd > wordBegin) {
02310       nameBegin = aString.RFindChar(U_SLASH, wordEnd-1);
02311       if (nameBegin >= wordBegin) {
02312         nameBegin++;
02313       } else {
02314         nameBegin = wordBegin;
02315       }
02316     } else {
02317       nameBegin = wordBegin;
02318     }
02319 
02320     nsAutoString filename;
02321     aString.Mid(filename, nameBegin, wordEnd-nameBegin+1);
02322 
02323     FileType fileType = PLAIN_FILE;
02324     PRUint32 dropSuffix = 0;
02325 
02326     if (wordEnd > wordBegin) {
02327       // Determine file type from suffix character
02328       switch (aString[wordEnd]) {
02329       case U_SLASH:
02330         fileType = DIRECTORY_FILE;
02331         break;
02332       case U_STAR:
02333         fileType = EXECUTABLE_FILE;
02334         break;
02335       default:
02336         break;
02337       }
02338 
02339       // Discard any type suffix
02340       if (fileType != PLAIN_FILE)
02341         dropSuffix = 1;
02342     }
02343 
02344     // Extract full pathname (minus any type suffix)
02345     nsAutoString pathname;
02346     aString.Mid(pathname, wordBegin, wordEnd-wordBegin+1-dropSuffix);
02347 
02348     // Append to markup string
02349     markupString.AssignLiteral("<span class=\"");
02350     markupString.AssignASCII(fileTypeNames[fileType]);
02351     markupString.AssignLiteral("\"");
02352 
02353     int j;
02354     for (j=0; j<SESSION_EVENT_TYPES; j++) {
02355       markupString.AssignLiteral(" on");
02356       markupString.AssignASCII(sessionEventNames[j]);
02357       markupString.AssignLiteral("=\"return HandleEvent(event, '");
02358       markupString.AssignASCII(sessionEventNames[j]);
02359       markupString.AssignLiteral("','");
02360       markupString.AssignASCII(fileTypeNames[fileType]);
02361       markupString.AssignLiteral("',-#,'");
02362       markupString.Assign(pathname);
02363       markupString.Assign(NS_LITERAL_STRING("');\""));
02364     }
02365 
02366     markupString.AssignLiteral(">");
02367     markupString.Assign(filename);
02368     markupString.AssignLiteral("</span>");
02369 
02370     // Search for new word
02371     wordBegin = wordEnd+1;
02372   }
02373 
02374   if (mOutputDisplayType != PRE_STDOUT_NODE) {
02375     // Create PRE block
02376     nsAutoString nullString; nullString.SetLength(0);
02377     result = AppendOutput(nullString, nullString, PR_FALSE);
02378   }
02379 
02380   PR_ASSERT(mOutputDisplayNode != nsnull);
02381   PR_ASSERT(mOutputTextNode != nsnull);
02382 
02383   result = InsertFragment(markupString, mOutputDisplayNode,
02384                           mCurrentEntryNumber, mOutputTextNode.get());
02385 
02386   nsCOMPtr<nsIDOMDocument> domDoc;
02387   result = mXMLTerminal->GetDOMDocument(getter_AddRefs(domDoc));
02388   if (NS_FAILED(result) || !domDoc)
02389     return NS_ERROR_FAILURE;
02390 
02391   // Insert text node containing newline only
02392   nsCOMPtr<nsIDOMText> newText;
02393   nsAutoString newlineStr(NS_LITERAL_STRING("\n"));
02394 
02395   result = domDoc->CreateTextNode(newlineStr, getter_AddRefs(newText));
02396   if (NS_FAILED(result) || !newText)
02397     return NS_ERROR_FAILURE;
02398 
02399   nsCOMPtr<nsIDOMNode> newTextNode = do_QueryInterface(newText);
02400   nsCOMPtr<nsIDOMNode> resultNode;
02401   result = mOutputDisplayNode->InsertBefore(newTextNode, mOutputTextNode,
02402                                             getter_AddRefs(resultNode));
02403   if (NS_FAILED(result))
02404     return NS_ERROR_FAILURE;
02405 
02406   XMLT_LOG(mozXMLTermSession::AppendLineLS,61,("exiting\n"));
02407 
02408 #if 0
02409   mCurrentDebugNode = mOutputDisplayNode;
02410   mMetaCommandType = TREE_META_COMMAND;
02411   XMLT_LOG(mozXMLTermSession::AppendLineLS,62,("tree:\n"));
02412 #endif  /* 0 */
02413 
02414   return NS_OK;
02415 }
02416 
02417 
02432  NS_IMETHODIMP mozXMLTermSession::InsertFragment(const nsString& aString,
02433                                               nsIDOMNode* parentNode,
02434                                               PRInt32 entryNumber,
02435                                               nsIDOMNode* beforeNode,
02436                                               PRBool replace)
02437 {
02438   nsresult result;
02439 
02440   char* temCString = ToNewCString(aString);
02441   XMLT_LOG(mozXMLTermSession::InsertFragment,70,("aString=%s\n", temCString));
02442   nsCRT::free(temCString);
02443 
02444   // Get selection
02445   nsCOMPtr<nsISelection> selection;
02446 
02447   nsCOMPtr<nsISelectionController> selCon;
02448   result = mXMLTerminal->GetSelectionController(getter_AddRefs(selCon));
02449   if (NS_FAILED(result) || !selCon)
02450     return NS_ERROR_FAILURE;
02451 
02452   result = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
02453                                     getter_AddRefs(selection));
02454   if (NS_FAILED(result) || !selection)
02455     return NS_ERROR_FAILURE;
02456 
02457   PRUint32 insertOffset = 0;
02458 
02459   nsCOMPtr<nsIDOMNodeList> childNodes;
02460   result = parentNode->GetChildNodes(getter_AddRefs(childNodes));
02461 
02462   if (NS_SUCCEEDED(result) && childNodes) {
02463     PRUint32 nChildren = 0;
02464     childNodes->GetLength(&nChildren);
02465 
02466     if(!beforeNode) {
02467       // Append child
02468       insertOffset = nChildren;
02469 
02470     } else {
02471       // Determine offset of before node
02472       int j;
02473       PRInt32 nNodes = nChildren;
02474 
02475       for (j=0; j<nNodes; j++) {
02476         nsCOMPtr<nsIDOMNode> childNode;
02477         result = childNodes->Item(j, getter_AddRefs(childNode));
02478         if ((NS_SUCCEEDED(result)) && childNode) {
02479           if (childNode.get() == beforeNode) {
02480             insertOffset = j;
02481             break;
02482           }
02483         }
02484       }
02485     }
02486   }
02487 
02488   // Collapse selection to insertion point
02489   result = selection->Collapse(parentNode, insertOffset);
02490   if (NS_FAILED(result))
02491     return result;
02492 
02493   // Get the first range in the selection
02494   nsCOMPtr<nsIDOMRange> firstRange;
02495   result = selection->GetRangeAt(0, getter_AddRefs(firstRange));
02496   if (NS_FAILED(result) || !firstRange)
02497     return NS_ERROR_FAILURE;
02498 
02499   nsCOMPtr<nsIDOMNSRange> nsrange (do_QueryInterface(firstRange));
02500   if (!nsrange)
02501     return NS_ERROR_FAILURE;
02502 
02503   XMLT_LOG(mozXMLTermSession::InsertFragment,62,("Creating Fragment\n"));
02504 
02505   nsCOMPtr<nsIDOMDocumentFragment> docfrag;
02506   result = nsrange->CreateContextualFragment(aString, getter_AddRefs(docfrag));
02507   if (NS_FAILED(result) || !docfrag)
02508     return NS_ERROR_FAILURE;
02509 
02510   nsCOMPtr<nsIDOMNode> docfragNode (do_QueryInterface(docfrag));
02511   if (!docfragNode)
02512     return NS_ERROR_FAILURE;
02513 
02514   // Sanitize all nodes in document fragment (deep)
02515   result = DeepSanitizeFragment(docfragNode, nsnull, entryNumber);
02516   if (NS_FAILED(result))
02517     return NS_ERROR_FAILURE;
02518 
02519   // If fragment was deleted during the sanitization process, simply return
02520   if (!docfragNode)
02521     return NS_OK;
02522 
02523   // Insert child nodes of document fragment before PRE text node
02524   nsCOMPtr<nsIDOMNode> childNode;
02525   result = docfragNode->GetFirstChild(getter_AddRefs(childNode));
02526   if (NS_FAILED(result) || !childNode)
02527     return NS_ERROR_FAILURE;
02528 
02529   while (childNode) {
02530     // Get next sibling prior to insertion
02531     nsCOMPtr<nsIDOMNode> nextChild;
02532     result = childNode->GetNextSibling(getter_AddRefs(nextChild));
02533 
02534     XMLT_LOG(mozXMLTermSession::InsertFragment,72,("Inserting child node ...\n"));
02535 
02536     //  nsCOMPtr<nsIContent> childContent (do_QueryInterface(childNode));
02537     //    if (childContent) childContent->List(stderr);
02538 
02539     // Deep clone child node
02540     // Note: Not clear why this needs to be done, but like "deep refresh",
02541     //       seems to be essential for event handlers to work
02542     nsCOMPtr<nsIDOMNode> cloneNode;
02543     result = childNode->CloneNode(PR_TRUE, getter_AddRefs(cloneNode));
02544     if (NS_FAILED(result) || !cloneNode)
02545       return NS_ERROR_FAILURE;
02546 
02547     // Insert clone of child node
02548     nsCOMPtr<nsIDOMNode> resultNode;
02549 
02550     PRBool replaceTem = replace;
02551     if (beforeNode) {
02552       if (replaceTem) {
02553         // Replace before node
02554         result = parentNode->ReplaceChild(cloneNode, beforeNode,
02555                                           getter_AddRefs(resultNode));
02556 
02557         beforeNode = nsnull;
02558 
02559         nsCOMPtr<nsIDOMNode> newBeforeNode;
02560         result = resultNode->GetNextSibling(getter_AddRefs(newBeforeNode));
02561 
02562         if (NS_SUCCEEDED(result) && newBeforeNode) {
02563           beforeNode = newBeforeNode.get();
02564           replaceTem = PR_FALSE;
02565         }
02566 
02567       } else {
02568         // Insert before specified node
02569         result = parentNode->InsertBefore(cloneNode, beforeNode,
02570                                           getter_AddRefs(resultNode));
02571       }
02572     } else {
02573       // Append child
02574       result = parentNode->AppendChild(cloneNode, getter_AddRefs(resultNode));
02575     }
02576     if (NS_FAILED(result))
02577       return result;
02578 
02579     // Refresh attributes of inserted child node (deep)
02580     DeepRefreshEventHandlers(resultNode);
02581 
02582     childNode = nextChild;
02583   }
02584 
02585   return NS_OK;
02586 
02587 }
02588 
02589 
02595 void mozXMLTermSession::SubstituteCommandNumber(nsString& aString,
02596                                                 PRInt32 aNumber)
02597 {
02598 
02599   if (aNumber < 0)
02600     return;
02601 
02602   PRInt32 numberOffset;
02603   nsAutoString numberString;
02604   numberString.SetLength(0);
02605 
02606   numberString.AppendInt(aNumber,10);
02607 
02608   for (;;) {
02609     // Search for '#' character
02610     numberOffset = aString.FindChar((PRUnichar) '#');
02611 
02612     if (numberOffset < 0)
02613       break;
02614 
02615     // Substitute '#' with supplied number
02616     aString.Cut(numberOffset,1);
02617     aString.Insert(numberString, numberOffset);
02618   }
02619 }
02620 
02621 
02626 void mozXMLTermSession::SanitizeAttribute(nsString& aAttrValue,
02627                                           const char* aEventName)
02628 {
02629   // ****************NOTE***************
02630   // At the moment this method simply prevents the word function and the
02631   // the character '{' both occurring in the event handler attribute.
02632   // NEEDS TO BE IMPROVED TO ENFORCE STRICTER REQUIREMENTS
02633   // such as: the event handler attribute should always be of the form
02634   // "return EventHandler(str_arg1, num_arg2, str_arg3, str_arg4);"
02635 
02636   if ((aAttrValue.FindChar((PRUnichar)'{') >= 0) &&
02637       (aAttrValue.Find("function") >= 0)) {
02638     // Character '{' and string "function" both found in attribute value;
02639     // set to null string
02640 
02641     char* temCString = ToNewCString(aAttrValue);
02642     XMLT_WARNING("mozXMLTermSession::SanitizeAttribute: Warning - deleted attribute on%s='%s'\n", aEventName, temCString);
02643     nsCRT::free(temCString);
02644 
02645     aAttrValue.SetLength(0);
02646   }
02647 
02648   return;
02649 }
02650 
02651 
02667 NS_IMETHODIMP mozXMLTermSession::DeepSanitizeFragment(
02668                                   nsCOMPtr<nsIDOMNode>& domNode,
02669                                   nsIDOMNode* parentNode,
02670                                   PRInt32 entryNumber)
02671 {
02672   nsresult result;
02673   PRInt32 j;
02674 
02675   XMLT_LOG(mozXMLTermSession::DeepSanitizeFragment,72,("entryNumber=%d\n",
02676                                                        entryNumber));
02677 
02678   nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(domNode);
02679 
02680   if (domElement) {
02681     // Check if this is a script element (IGNORE CASE)
02682     nsAutoString tagName;
02683     tagName.SetLength(0);
02684     result = domElement->GetTagName(tagName);
02685 
02686     if (NS_SUCCEEDED(result) && tagName.LowerCaseEqualsLiteral("script")) {
02687       // Remove script element and return
02688 
02689       XMLT_WARNING("mozXMLTermSession::DeepSanitizeFragment: Warning - rejected SCRIPT element in inserted HTML fragment\n");
02690 
02691       if (parentNode) {
02692         nsCOMPtr<nsIDOMNode> resultNode;
02693         result = parentNode->RemoveChild(domNode, getter_AddRefs(resultNode));
02694         if (NS_FAILED(result))
02695           return result;
02696 
02697       } else {
02698         domNode = nsnull;
02699       }
02700 
02701       return NS_OK;
02702     }
02703 
02704     nsAutoString eventAttrVals[SESSION_EVENT_TYPES];
02705     for (j=0; j<SESSION_EVENT_TYPES; j++)
02706       eventAttrVals[j].SetLength(0);
02707 
02708     nsAutoString attName, attValue;
02709 
02710     for (j=0; j<SESSION_EVENT_TYPES; j++) {
02711       attName.AssignLiteral("on");
02712       attName.AppendASCII(sessionEventNames[j]);
02713 
02714       attValue.SetLength(0);
02715       result = domElement->GetAttribute(attName, attValue);
02716       if (NS_SUCCEEDED(result) && !attValue.IsEmpty()) {
02717         // Save allowed event attribute value for re-insertion
02718         eventAttrVals[j] = attValue;
02719       }
02720     }
02721 
02722     nsCOMPtr<nsIDOMNamedNodeMap> namedNodeMap(nsnull);
02723     result = domNode->GetAttributes(getter_AddRefs(namedNodeMap));
02724 
02725     if (NS_SUCCEEDED(result) && namedNodeMap) {
02726       // Cycle through all attributes and delete all event attributes ("on*")
02727       PRUint32 nodeCount;
02728       result = namedNodeMap->GetLength(&nodeCount);
02729 
02730       if (NS_SUCCEEDED(result)) {
02731         nsCOMPtr<nsIDOMNode> attrNode;
02732         PRUint32 k;
02733         nsAutoString attrName, attrValue, prefix;
02734         nsAutoString nullStr; nullStr.SetLength(0);
02735 
02736         for (k=0; k<nodeCount; k++) {
02737           result = namedNodeMap->Item(k, getter_AddRefs(attrNode));
02738 
02739           if (NS_SUCCEEDED(result)) {
02740             nsCOMPtr<nsIDOMAttr> attr = do_QueryInterface(attrNode);
02741 
02742             if (attr) {
02743               result = attr->GetName(attrName);
02744 
02745               if (NS_SUCCEEDED(result)) {
02746                 result = attr->GetValue(attrValue);
02747                 if (NS_SUCCEEDED(result) && (attrName.Length() >= 2)) {
02748 
02749                   attrName.Left(prefix,2);
02750 
02751                   if (prefix.LowerCaseEqualsLiteral("on")) {
02752                     // Delete event handler attribute
02753 
02754                     XMLT_LOG(mozXMLTermSession::DeepSanitizeFragment,79,
02755                              ("Deleting event handler in fragment\n"));
02756 
02757                     result = domElement->SetAttribute(attrName, nullStr);
02758                     if (NS_FAILED(result))
02759                     return result;
02760                   }
02761                 }
02762 
02763               }
02764             }
02765 
02766           }
02767         }
02768 
02769       }
02770     }
02771 
02772     if (entryNumber >= 0) {
02773       // Process ID attribute
02774       attName.AssignLiteral("id");
02775 
02776       attValue.SetLength(0);
02777       result = domElement->GetAttribute(attName, attValue);
02778 
02779       if (NS_SUCCEEDED(result) && !attValue.IsEmpty()) {
02780         // Modify attribute value
02781         SubstituteCommandNumber(attValue, entryNumber);
02782         domElement->SetAttribute(attName, attValue);
02783       }
02784     }
02785 
02786     for (j=0; j<SESSION_EVENT_TYPES; j++) {
02787       // Re-introduce sanitized event attribute values
02788       attName.AssignLiteral("on");
02789       attName.AppendASCII(sessionEventNames[j]);
02790       attValue = eventAttrVals[j];
02791 
02792       if (!attValue.IsEmpty()) {
02793         SubstituteCommandNumber(attValue, entryNumber);
02794 
02795         // Sanitize attribute value
02796         SanitizeAttribute(attValue, sessionEventNames[j]);
02797 
02798         // Insert attribute value
02799         domElement->SetAttribute(attName, attValue);
02800       }
02801     }
02802 
02803   }
02804 
02805   // Iterate over all child nodes for deep refresh
02806   nsCOMPtr<nsIDOMNode> child;
02807   result = domNode->GetFirstChild(getter_AddRefs(child));
02808   if (NS_FAILED(result))
02809     return NS_OK;
02810 
02811   while (child) {
02812     DeepSanitizeFragment(child, domNode, entryNumber);
02813 
02814     nsCOMPtr<nsIDOMNode> temp = child;
02815     result = temp->GetNextSibling(getter_AddRefs(child));
02816     if (NS_FAILED(result))
02817       break;
02818   }
02819 
02820   return NS_OK;
02821 }
02822 
02823 
02828 NS_IMETHODIMP mozXMLTermSession::DeepRefreshEventHandlers(
02829                                   nsCOMPtr<nsIDOMNode>& domNode)
02830 {
02831   nsresult result;
02832 
02833   XMLT_LOG(mozXMLTermSession::DeepRefreshEventHandlers,82,("\n"));
02834 
02835   nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(domNode);
02836   if (!domElement)
02837     return NS_OK;
02838 
02839   int j;
02840   nsAutoString attName, attValue;
02841 
02842   // Refresh event attributes
02843   for (j=0; j<SESSION_EVENT_TYPES; j++) {
02844     attName.AssignLiteral("on");
02845     attName.AppendASCII(sessionEventNames[j]);
02846 
02847     XMLT_LOG(mozXMLTermSession::DeepRefreshEventHandlers,89,
02848              ("Refreshing on%s attribute\n",sessionEventNames[j] ));
02849 
02850     attValue.SetLength(0);
02851     result = domElement->GetAttribute(attName, attValue);
02852 
02853     if (NS_SUCCEEDED(result) && !attValue.IsEmpty()) {
02854       // Refresh attribute value
02855       domElement->SetAttribute(attName, attValue);
02856     }
02857   }
02858 
02859   // Iterate over all child nodes for deep refresh
02860   nsCOMPtr<nsIDOMNode> child;
02861   result = domNode->GetFirstChild(getter_AddRefs(child));
02862   if (NS_FAILED(result))
02863     return NS_OK;
02864 
02865   while (child) {
02866     DeepRefreshEventHandlers(child);
02867 
02868     nsCOMPtr<nsIDOMNode> temp = child;
02869     result = temp->GetNextSibling(getter_AddRefs(child));
02870     if (NS_FAILED(result))
02871       break;
02872   }
02873 
02874   return NS_OK;
02875 }
02876 
02877 
02882 NS_IMETHODIMP mozXMLTermSession::FlushOutput(FlushActionType flushAction)
02883 {
02884   nsresult result;
02885 
02886   if (!mEntryHasOutput)
02887     return NS_OK;
02888 
02889   XMLT_LOG(mozXMLTermSession::FlushOutput,70,
02890           ("flushAction=%d, mOutputDisplayType=%d\n",
02891            flushAction, mOutputDisplayType));
02892 
02893   PRBool preDisplay = (mOutputDisplayType == PRE_STDOUT_NODE) ||
02894                       (mOutputDisplayType == PRE_STDERR_NODE) ||
02895                       (mOutputDisplayType == PRE_STDIN_NODE);
02896 
02897   if (preDisplay) {
02898     // PRE text display
02899     OutputDisplayType preDisplayType = mOutputDisplayType;
02900     nsAutoString preTextSplit; preTextSplit.SetLength(0);
02901 
02902     if (flushAction != DISPLAY_INCOMPLETE_FLUSH) {
02903       // Split/clear/close incomplete line
02904 
02905       XMLT_LOG(mozXMLTermSession::FlushOutput,72,
02906                ("mPreTextIncomplete.Length()=%d\n",
02907                 mPreTextIncomplete.Length() ));
02908 
02909       if (flushAction == SPLIT_INCOMPLETE_FLUSH) {
02910         // Move incomplete text to new PRE element
02911         preTextSplit = mPreTextIncomplete;
02912 
02913       } else if (flushAction == CLOSE_INCOMPLETE_FLUSH) {
02914         // Move incomplete text into buffer
02915         mPreTextBuffered += mPreTextIncomplete;
02916       }
02917 
02918       // Clear incomplete PRE text
02919       mPreTextIncomplete.SetLength(0);
02920 
02921       if ((mPreTextBufferLines == 0) && mPreTextBuffered.IsEmpty()) {
02922         // Remove lone text node
02923         nsCOMPtr<nsIDOMNode> resultNode;
02924         result = mOutputDisplayNode->RemoveChild(mOutputTextNode,
02925                                              getter_AddRefs(resultNode));
02926 
02927         // Check if PRE node has any child nodes
02928         PRBool hasChildNodes = PR_TRUE;
02929         result = mOutputDisplayNode->HasChildNodes(&hasChildNodes);
02930 
02931         if (!hasChildNodes) {
02932           // No child nodes left; Delete PRE node itself
02933           nsCOMPtr<nsIDOMNode> resultNode2;
02934           result = mOutputBlockNode->RemoveChild(mOutputDisplayNode,
02935                                                  getter_AddRefs(resultNode));
02936         }
02937 
02938         mOutputDisplayNode = nsnull;
02939         mOutputDisplayType = NO_NODE;
02940         mOutputTextNode = nsnull;
02941       }
02942     }
02943 
02944     if (mOutputDisplayNode != nsnull) {
02945       // Update displayed PRE text
02946       nsAutoString outString(mPreTextBuffered);
02947       outString += mPreTextIncomplete;
02948 
02949       // Increment total output line count for entry
02950       mEntryOutputLines += mPreTextBufferLines;
02951 
02952       if (outString != mPreTextDisplayed) {
02953         // Display updated buffer
02954         mPreTextDisplayed = outString;
02955 
02956         XMLT_LOG(mozXMLTermSession::FlushOutput,72,
02957                  ("mOutputTextNode=%d\n", (mOutputTextNode != nsnull)));
02958 
02959         result = SetDOMText(mOutputTextNode, mPreTextDisplayed);
02960         if (NS_FAILED(result))
02961           return NS_ERROR_FAILURE;
02962 
02963       }
02964     }
02965 
02966     if (flushAction != DISPLAY_INCOMPLETE_FLUSH) {
02967       // Split/clear/close incomplete line
02968       mOutputDisplayNode = nsnull;
02969       mOutputDisplayType = NO_NODE;
02970       mOutputTextNode = nsnull;
02971 
02972       if ( (flushAction == SPLIT_INCOMPLETE_FLUSH) &&
02973            !preTextSplit.IsEmpty() ) {
02974         // Create new PRE element with incomplete text
02975         nsAutoString styleStr; styleStr.SetLength(0);
02976 
02977         if (preDisplayType == PRE_STDIN_NODE) {
02978           styleStr += (PRUnichar) LTERM_STDIN_STYLE;
02979 
02980         } else if (preDisplayType == PRE_STDERR_NODE) {
02981           styleStr += (PRUnichar) LTERM_STDERR_STYLE;
02982 
02983         } else {
02984           styleStr += (PRUnichar) LTERM_STDOUT_STYLE;
02985         }
02986 
02987         XMLT_LOG(mozXMLTermSession::FlushOutput,72,("splitting\n"));
02988 
02989         AppendOutput(preTextSplit, styleStr, PR_FALSE);
02990 
02991         FlushOutput(DISPLAY_INCOMPLETE_FLUSH);
02992       }
02993     }
02994 
02995   } else if (mOutputDisplayNode != nsnull) {
02996     // Non-PRE node
02997     if (flushAction == CLEAR_INCOMPLETE_FLUSH) {
02998       // Clear incomplete line info
02999       nsCOMPtr<nsIDOMNode> resultNode;
03000       result = mOutputBlockNode->RemoveChild(mOutputDisplayNode,
03001                                              getter_AddRefs(resultNode));
03002       mOutputDisplayNode = nsnull;
03003       mOutputDisplayType = NO_NODE;
03004       mOutputTextNode = nsnull;
03005 
03006     } else if (flushAction == CLOSE_INCOMPLETE_FLUSH) {
03007       mOutputDisplayNode = nsnull;
03008       mOutputDisplayType = NO_NODE;
03009       mOutputTextNode = nsnull;
03010 
03011     }
03012   }
03013 
03014   XMLT_LOG(mozXMLTermSession::FlushOutput,71,("returning\n"));
03015 
03016   return NS_OK;
03017 }
03018 
03019 
03021 void mozXMLTermSession::PositionOutputCursor(mozILineTermAux* lineTermAux)
03022 {
03023   nsresult result;
03024 
03025   XMLT_LOG(mozXMLTermSession::PositionOutputCursor,80,("\n"));
03026 
03027   PRBool dummyOutput = PR_FALSE;
03028   if (!mOutputTextNode) {
03029     // Append dummy output line
03030     nsCOMPtr<nsIDOMNode> spanNode, textNode;
03031     nsAutoString tagName(NS_LITERAL_STRING("span"));
03032     nsAutoString elementName; elementName.AssignASCII(sessionElementNames[STDOUT_ELEMENT]);
03033     result = NewElementWithText(tagName, elementName, -1,
03034                                 mOutputBlockNode, spanNode, textNode);
03035 
03036     if (NS_FAILED(result) || !spanNode || !textNode)
03037       return;
03038 
03039     // Display NBSP for cursor positioning
03040     nsAutoString tempString;
03041     tempString += kNBSP;
03042     SetDOMText(textNode, tempString);
03043     dummyOutput = PR_TRUE;
03044 
03045     mOutputDisplayType = SPAN_DUMMY_NODE;
03046     mOutputDisplayNode = spanNode;
03047     mOutputTextNode = textNode;
03048     mOutputTextOffset = 0;
03049   }
03050 
03051   // Get selection
03052   nsCOMPtr<nsISelection> selection;
03053 
03054   nsCOMPtr<nsISelectionController> selCon;
03055   result = mXMLTerminal->GetSelectionController(getter_AddRefs(selCon));
03056   if (NS_FAILED(result) || !selCon)
03057     return; // NS_ERROR_FAILURE
03058 
03059   result = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
03060                                     getter_AddRefs(selection));
03061   if (NS_SUCCEEDED(result) && selection) {
03062     // Position cursor at end of line
03063     nsCOMPtr<nsIDOMText> domText( do_QueryInterface(mOutputTextNode) );
03064     nsAutoString text; text.SetLength(0);
03065     domText->GetData(text);
03066 
03067     PRInt32 textOffset = text.Length();
03068     if (textOffset && dummyOutput) textOffset--;
03069 
03070     if (lineTermAux && (mOutputDisplayType == PRE_STDIN_NODE)) {
03071       // Get cursor column
03072       PRInt32 cursorCol = 0;
03073       lineTermAux->GetCursorColumn(&cursorCol);
03074       textOffset = cursorCol - mOutputTextOffset;
03075       if (textOffset > (PRInt32)text.Length())
03076         textOffset = text.Length();
03077     }
03078     result = selection->Collapse(mOutputTextNode, textOffset);
03079   }
03080 }
03081 
03082 
03084 NS_IMETHODIMP mozXMLTermSession::ScrollToBottomLeft(void)
03085 {
03086   nsresult result;
03087 
03088   XMLT_LOG(mozXMLTermSession::ScrollToBottomLeft,70,("\n"));
03089 
03090   nsCOMPtr<nsIPresShell> presShell;
03091   result = mXMLTerminal->GetPresShell(getter_AddRefs(presShell));
03092   if (NS_FAILED(result) || !presShell)
03093     return NS_ERROR_FAILURE;
03094 
03095   nsIDocument* doc = presShell->GetDocument();
03096   if (doc) {
03097     doc->FlushPendingNotifications(Flush_Layout);
03098   }
03099 
03100   // Get DOM Window
03101   nsCOMPtr<nsIDocShell> docShell;
03102   result = mXMLTerminal->GetDocShell(getter_AddRefs(docShell));
03103   if (NS_FAILED(result) || !docShell)
03104     return NS_ERROR_FAILURE;
03105 
03106   nsCOMPtr<nsIDOMWindowInternal> domWindow;
03107   result = mozXMLTermUtils::ConvertDocShellToDOMWindow(docShell,
03108                                            getter_AddRefs(domWindow));
03109 
03110   if (NS_FAILED(result) || !domWindow)
03111     return NS_ERROR_FAILURE;
03112 
03113   // Scroll to bottom left of screen
03114   domWindow->ScrollBy(-99999,99999);
03115 
03116   return NS_OK;
03117 }
03118 
03119 
03123 NS_IMETHODIMP mozXMLTermSession::GetCurrentEntryNumber(PRInt32 *aNumber)
03124 {
03125   *aNumber = mCurrentEntryNumber;
03126   return NS_OK;
03127 }
03128 
03129 
03130 // Get size of entry history buffer
03131 NS_IMETHODIMP mozXMLTermSession::GetHistory(PRInt32 *aHistory)
03132 {
03133   *aHistory = mMaxHistory;
03134   return NS_OK;
03135 }
03136 
03137 
03138 // Set size of entry history buffer
03139 NS_IMETHODIMP mozXMLTermSession::SetHistory(PRInt32 aHistory)
03140 {
03141   nsresult result;
03142 
03143   XMLT_LOG(mozXMLTermSession::SetHistory,30,("\n"));
03144 
03145   if (aHistory < 1)
03146     aHistory = 1;
03147 
03148   if (mInitialized && mStartEntryNode && (aHistory < mMaxHistory)) {
03149     // Delete any extra entry blocks
03150     PRInt32 delEntries = (mCurrentEntryNumber-mStartEntryNumber)
03151                          - aHistory;
03152     PRInt32 j;
03153     for (j=0; j<delEntries; j++) {
03154       nsCOMPtr<nsIDOMNode> newStartNode;
03155       result = mStartEntryNode->GetNextSibling(getter_AddRefs(newStartNode));
03156       if (NS_FAILED(result) || !newStartNode) {
03157         return NS_ERROR_FAILURE;
03158       }
03159 
03160       nsCOMPtr<nsIDOMNode> resultNode;
03161       result = mSessionNode->RemoveChild(mStartEntryNode,
03162                                         getter_AddRefs(resultNode));
03163 
03164       if (NS_FAILED(result)) {
03165         return NS_ERROR_FAILURE;
03166       }
03167 
03168       mStartEntryNode = newStartNode;
03169       mStartEntryNumber++;
03170     }
03171   }
03172 
03173   mMaxHistory = aHistory;
03174 
03175   return NS_OK;
03176 }
03177 
03178 
03179 // Get HTML prompt string
03180 NS_IMETHODIMP mozXMLTermSession::GetPrompt(PRUnichar **_aPrompt)
03181 {
03182   // NOTE: Need to be sure that this may be freed by nsMemory::Free
03183   *_aPrompt = ToNewUnicode(mPromptHTML);
03184   return NS_OK;
03185 }
03186 
03187 
03188 // Set HTML prompt string
03189 NS_IMETHODIMP mozXMLTermSession::SetPrompt(const PRUnichar* aPrompt)
03190 {
03191   mPromptHTML = aPrompt;
03192   return NS_OK;
03193 }
03194 
03195 
03199 NS_IMETHODIMP mozXMLTermSession::GetScreenMode(PRBool* aFlag)
03200 {
03201   if (!aFlag)
03202     return NS_ERROR_NULL_POINTER;
03203 
03204   *aFlag = (mScreenNode != nsnull);
03205 
03206   return NS_OK;
03207 }
03208 
03209 
03214 NS_IMETHODIMP mozXMLTermSession::NewPreface(void)
03215 {
03216   nsresult result;
03217 
03218   XMLT_LOG(mozXMLTermSession::NewPreface,40,("\n"));
03219 
03220   // Create preface element and append as child of session element
03221   nsCOMPtr<nsIDOMNode> divNode;
03222   nsAutoString tagName(NS_LITERAL_STRING("div"));
03223   nsAutoString name(NS_LITERAL_STRING("preface"));
03224   result = NewElement(tagName, name, 0,
03225                       mSessionNode, divNode);
03226 
03227   if (NS_FAILED(result) || !divNode)
03228     return NS_ERROR_FAILURE;
03229 
03230   mOutputBlockNode = divNode;
03231 
03232   mOutputDisplayType = NO_NODE;
03233   mOutputDisplayNode = nsnull;
03234   mOutputTextNode = nsnull;
03235 
03236   // Command output being processed
03237   mEntryHasOutput = PR_TRUE;
03238 
03239   return NS_OK;
03240 }
03241 
03242 
03253 NS_IMETHODIMP mozXMLTermSession::NewEntry(const nsString& aPrompt)
03254 {
03255   nsresult result;
03256 
03257   XMLT_LOG(mozXMLTermSession::NewEntry,50,("\n"));
03258 
03259   if (mCurrentEntryNumber == 0) {
03260     // First entry
03261     mCurrentEntryNumber = 1;
03262     mStartEntryNumber = 1;
03263 
03264   } else {
03265     // Not first entry
03266 
03267     // Add event attributes to current command element
03268     nsAutoString cmdName; cmdName.AssignASCII(sessionElementNames[COMMAND_ELEMENT]);
03269     result = SetEventAttributes(cmdName,
03270                                 mCurrentEntryNumber,
03271                                 mCommandSpanNode);
03272     if (NS_FAILED(result))
03273       return NS_ERROR_FAILURE;
03274 
03275     // Increment entry number
03276     mCurrentEntryNumber++;
03277 
03278     if ((mCurrentEntryNumber - mStartEntryNumber) > mMaxHistory) {
03279       // Delete oldest displayed entry element
03280 
03281       nsCOMPtr<nsIDOMNode> newStartNode;
03282       result = mStartEntryNode->GetNextSibling(getter_AddRefs(newStartNode));
03283       if (NS_FAILED(result) || !newStartNode) {
03284         return NS_ERROR_FAILURE;
03285       }
03286 
03287       nsCOMPtr<nsIDOMNode> resultNode;
03288       result = mSessionNode->RemoveChild(mStartEntryNode,
03289                                       getter_AddRefs(resultNode));
03290 
03291       if (NS_FAILED(result)) {
03292         return NS_ERROR_FAILURE;
03293       }
03294 
03295       mStartEntryNode = newStartNode;
03296       mStartEntryNumber++;
03297     }
03298   }
03299 
03300   XMLT_LOG(mozXMLTermSession::NewEntry,50,
03301            ("%d (start=%d)\n", mCurrentEntryNumber, mStartEntryNumber));
03302 
03303   nsAutoString tagName, name;
03304 
03305   // Create "entry" element
03306   nsCOMPtr<nsIDOMNode> entryNode;
03307   tagName.AssignLiteral("div");
03308   name.AssignASCII(sessionElementNames[ENTRY_ELEMENT]);
03309   result = NewElement(tagName, name, mCurrentEntryNumber,
03310                       mSessionNode, entryNode);
03311   if (NS_FAILED(result) || !entryNode) {
03312     return NS_ERROR_FAILURE;
03313   }
03314 
03315   mCurrentEntryNode = entryNode;
03316 
03317   if (mCurrentEntryNumber == 1) {
03318     mStartEntryNode = mCurrentEntryNode;
03319   }
03320 
03321   // Create "input" element containing "prompt" and "command" elements
03322   nsCOMPtr<nsIDOMNode> inputNode;
03323   tagName.AssignLiteral("div");
03324   name.AssignASCII(sessionElementNames[INPUT_ELEMENT]);
03325   result = NewElement(tagName, name, mCurrentEntryNumber,
03326                       mCurrentEntryNode, inputNode);
03327   if (NS_FAILED(result) || !inputNode) {
03328     return NS_ERROR_FAILURE;
03329   }
03330 
03331   nsAutoString classAttribute;
03332 
03333   // Create prompt element
03334   nsCOMPtr<nsIDOMNode> promptSpanNode;
03335   tagName.AssignLiteral("span");
03336   name.AssignASCII(sessionElementNames[PROMPT_ELEMENT]);
03337   result = NewElement(tagName, name, mCurrentEntryNumber,
03338                       inputNode, promptSpanNode);
03339   if (NS_FAILED(result) || !promptSpanNode) {
03340     return NS_ERROR_FAILURE;
03341   }
03342 
03343   // Add event attributes to prompt element
03344   result = SetEventAttributes(name, mCurrentEntryNumber,
03345                                 promptSpanNode);
03346 
03347   nsCOMPtr<nsIDOMDocument> domDoc;
03348   result = mXMLTerminal->GetDOMDocument(getter_AddRefs(domDoc));
03349   if (NS_FAILED(result) || !domDoc)
03350     return NS_ERROR_FAILURE;
03351 
03352   nsCOMPtr<nsIDOMNode> resultNode;
03353 
03354   if (mPromptHTML.IsEmpty()) {
03355 
03356 #define DEFAULT_ICON_PROMPT
03357 #ifdef DEFAULT_ICON_PROMPT    // Experimental code; has scrolling problems
03358     // Create text node + image node as child of prompt element
03359     nsCOMPtr<nsIDOMNode> spanNode, textNode;
03360 
03361     tagName.AssignLiteral("span");
03362     name.AssignLiteral("noicons");
03363     result = NewElementWithText(tagName, name, -1,
03364                                 promptSpanNode, spanNode, textNode);
03365     if (NS_FAILED(result) || !spanNode || !textNode) {
03366       return NS_ERROR_FAILURE;
03367     }
03368 
03369     // Strip single trailing space, if any, from prompt string
03370     int spaceOffset = aPrompt.Length();
03371 
03372     if ((spaceOffset > 0) && (aPrompt.Last() == ((PRUnichar) ' ')))
03373       spaceOffset--;
03374 
03375     nsAutoString promptStr;
03376     aPrompt.Left(promptStr, spaceOffset);
03377 
03378     // Set prompt text
03379     result = SetDOMText(textNode, promptStr);
03380     if (NS_FAILED(result))
03381       return NS_ERROR_FAILURE;
03382 
03383     // Create IMG element
03384     tagName.AssignLiteral("img");
03385     nsCOMPtr<nsIDOMElement> imgElement;
03386     result = domDoc->CreateElement(tagName, getter_AddRefs(imgElement));
03387     if (NS_FAILED(result) || !imgElement)
03388       return NS_ERROR_FAILURE;
03389 
03390     // Set attributes
03391     nsAutoString attName(NS_LITERAL_STRING("class"));
03392     nsAutoString attValue(NS_LITERAL_STRING("icons"));
03393     imgElement->SetAttribute(attName, attValue);
03394 
03395     attName.AssignLiteral("src");
03396     attValue.AssignLiteral("chrome://xmlterm/skin/wheel.gif");
03397     imgElement->SetAttribute(attName, attValue);
03398 
03399     attName.AssignLiteral("align");
03400     attValue.AssignLiteral("middle");
03401     imgElement->SetAttribute(attName, attValue);
03402 
03403     // Append IMG element
03404     nsCOMPtr<nsIDOMNode> imgNode = do_QueryInterface(imgElement);
03405     result = promptSpanNode->AppendChild(imgNode,
03406                                           getter_AddRefs(resultNode));
03407     if (NS_FAILED(result))
03408       return NS_ERROR_FAILURE;
03409 
03410 #else // !DEFAULT_ICON_PROMPT
03411     // Create text node as child of prompt element
03412     nsCOMPtr<nsIDOMNode> textNode;
03413     result = NewTextNode(promptSpanNode, textNode);
03414 
03415     if (NS_FAILED(result) || !textNode)
03416       return NS_ERROR_FAILURE;
03417 
03418     // Set prompt text
03419     result = SetDOMText(textNode, aPrompt);
03420     if (NS_FAILED(result))
03421       return NS_ERROR_FAILURE;
03422 #endif // !DEFAULT_ICON_PROMPT
03423 
03424   } else {
03425     // User-specified HTML prompt
03426     result = InsertFragment(mPromptHTML, promptSpanNode,
03427                             mCurrentEntryNumber);
03428   }
03429 
03430   // Append text node containing single NBSP
03431   nsCOMPtr<nsIDOMText> stubText;
03432   nsAutoString spaceStr(kNBSP);
03433   result = domDoc->CreateTextNode(spaceStr, getter_AddRefs(stubText));
03434   if (NS_FAILED(result) || !stubText)
03435     return NS_ERROR_FAILURE;
03436 
03437   nsCOMPtr<nsIDOMNode> stubNode = do_QueryInterface(stubText);
03438   result = inputNode->AppendChild(stubNode, getter_AddRefs(resultNode));
03439   if (NS_FAILED(result))
03440     return NS_ERROR_FAILURE;
03441 
03442   mPromptTextNode = stubNode;
03443 
03444   // Create command element
03445   nsCOMPtr<nsIDOMNode> newCommandSpanNode;
03446   tagName.AssignLiteral("span");
03447   name.AssignASCII(sessionElementNames[COMMAND_ELEMENT]);
03448   result = NewElement(tagName, name, mCurrentEntryNumber,
03449                       inputNode, newCommandSpanNode);
03450   if (NS_FAILED(result) || !newCommandSpanNode) {
03451     return NS_ERROR_FAILURE;
03452   }
03453 
03454   mCommandSpanNode = newCommandSpanNode;
03455 
03456   // Create text node as child of command element
03457   nsCOMPtr<nsIDOMNode> textNode2;
03458   result = NewTextNode(mCommandSpanNode, textNode2);
03459 
03460   if (NS_FAILED(result) || !textNode2)
03461     return NS_ERROR_FAILURE;
03462 
03463   mInputTextNode = textNode2;
03464 
03465   // Create output element and append as child of current entry element
03466   nsCOMPtr<nsIDOMNode> divNode;
03467   tagName.AssignLiteral("div");
03468   name.AssignASCII(sessionElementNames[OUTPUT_ELEMENT]);
03469   result = NewElement(tagName, name, mCurrentEntryNumber,
03470                       mCurrentEntryNode, divNode);
03471 
03472   if (NS_FAILED(result) || !divNode)
03473     return NS_ERROR_FAILURE;
03474 
03475   mOutputBlockNode = divNode;
03476 
03477   mOutputDisplayType = NO_NODE;
03478   mOutputDisplayNode = nsnull;
03479   mOutputTextNode = nsnull;
03480 
03481   // No command output processed yet
03482   mEntryHasOutput = PR_FALSE;
03483 
03484   mEntryOutputLines = 0;
03485 
03486   return NS_OK;
03487 }
03488 
03489 
03494 NS_IMETHODIMP mozXMLTermSession::NewScreen(void)
03495 {
03496   nsresult result;
03497 
03498   XMLT_LOG(mozXMLTermSession::NewScreen,70,("\n"));
03499 
03500   // Create screen element and append as child of session element
03501   nsCOMPtr<nsIDOMNode> divNode;
03502   nsAutoString tagName(NS_LITERAL_STRING("div"));
03503   nsAutoString name(NS_LITERAL_STRING("screen"));
03504   result = NewElement(tagName, name, 0,
03505                       mBodyNode, divNode);
03506 
03507   if (NS_FAILED(result) || !divNode)
03508     return NS_ERROR_FAILURE;
03509 
03510   mScreenNode = divNode;
03511 
03512   // Collapse non-screen stuff
03513   nsAutoString attName(NS_LITERAL_STRING("xmlt-block-collapsed"));
03514   nsAutoString attValue(NS_LITERAL_STRING("true"));
03515 
03516   nsCOMPtr<nsIDOMElement> menusElement = do_QueryInterface(mMenusNode);
03517 
03518   if (NS_SUCCEEDED(result) && menusElement) {
03519     menusElement->SetAttribute(attName, attValue);
03520   }
03521 
03522   nsCOMPtr<nsIDOMElement> sessionElement = do_QueryInterface(mSessionNode);
03523 
03524   if (sessionElement) {
03525     sessionElement->SetAttribute(attName, attValue);
03526   }
03527 
03528   // Create individual row elements
03529   nsCOMPtr<nsIDOMNode> resultNode;
03530   PRInt32 row;
03531   for (row=0; row < mScreenRows; row++) {
03532     NewRow(nsnull, getter_AddRefs(resultNode));
03533   }
03534 
03535   // Collapse selection to bottom of screen (for scrolling)
03536   result = PositionScreenCursor(0, 0);
03537 
03538   if (NS_SUCCEEDED(result)) {
03539     nsCOMPtr<nsISelectionController> selCon;
03540     result = mXMLTerminal->GetSelectionController(getter_AddRefs(selCon));
03541     if (NS_FAILED(result) || !selCon)
03542       return NS_ERROR_FAILURE;
03543 
03544     result = selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
03545                                              nsISelectionController::SELECTION_FOCUS_REGION,
03546                                              PR_TRUE);
03547   }
03548 
03549   return NS_OK;
03550 }
03551 
03552 
03555 NS_IMETHODIMP mozXMLTermSession::GetRow(PRInt32 aRow, nsIDOMNode** aRowNode)
03556 {
03557   nsresult result;
03558 
03559   XMLT_LOG(mozXMLTermSession::GetRow,60,("aRow=%d\n", aRow));
03560 
03561   if (!aRowNode)
03562     return NS_ERROR_NULL_POINTER;
03563 
03564   nsCOMPtr<nsIDOMNodeList> childNodes;
03565   result = mScreenNode->GetChildNodes(getter_AddRefs(childNodes));
03566   if (NS_FAILED(result) || !childNodes)
03567     return NS_ERROR_FAILURE;
03568 
03569   PRUint32 nChildren = 0;
03570   childNodes->GetLength(&nChildren);
03571 
03572   XMLT_LOG(mozXMLTermSession::GetRow,62,("nChildren=%d, mScreenRows=%d\n",
03573                                          nChildren, mScreenRows));
03574 
03575   PRInt32 rowIndex = mScreenRows - aRow - 1;
03576   if ((rowIndex < 0) || (rowIndex >= (PRInt32)nChildren))
03577     return NS_ERROR_FAILURE;
03578 
03579   nsCOMPtr<nsIDOMNode> childNode;
03580   result = childNodes->Item(rowIndex, getter_AddRefs(childNode));
03581 
03582   if (NS_FAILED(result) || !childNode)
03583     return NS_ERROR_FAILURE;
03584 
03585   *aRowNode = childNode.get();
03586   NS_ADDREF(*aRowNode);
03587 
03588   XMLT_LOG(mozXMLTermSession::GetRow,61,("returning\n"));
03589 
03590   return NS_OK;
03591 }
03592 
03593 
03596 NS_IMETHODIMP mozXMLTermSession::PositionScreenCursor(PRInt32 aRow,
03597                                                       PRInt32 aCol)
03598 {
03599   nsresult result;
03600 
03601   XMLT_LOG(mozXMLTermSession::PositionScreenCursor,60,
03602            ("row=%d, col=%d\n",aRow,aCol));
03603 
03604   // Get row node
03605   nsCOMPtr<nsIDOMNode> rowNode;
03606   result = GetRow(aRow, getter_AddRefs(rowNode));
03607   if (NS_FAILED(result) || !rowNode)
03608     return NS_ERROR_FAILURE;
03609 
03610   nsCOMPtr<nsIDOMNodeList> childNodes;
03611   result = rowNode->GetChildNodes(getter_AddRefs(childNodes));
03612   if (NS_FAILED(result) || !childNodes)
03613     return NS_ERROR_FAILURE;
03614 
03615   PRUint32 nChildren = 0;
03616   childNodes->GetLength(&nChildren);
03617   XMLT_LOG(mozXMLTermSession::GetScreenText,60,("children=%d\n",nChildren));
03618 
03619   PRUint16 nodeType;
03620   PRUint32 j;
03621   PRInt32 prevCols = 0;
03622   PRInt32 textOffset = 0;
03623   nsCOMPtr<nsIDOMNode> textNode = nsnull;
03624   nsCOMPtr<nsIDOMNode> childNode;
03625   nsAutoString text; text.SetLength(0);
03626 
03627   for (j=0; j<nChildren; j++) {
03628     result = childNodes->Item(j, getter_AddRefs(childNode));
03629     if (NS_FAILED(result) || !childNode)
03630       return NS_ERROR_FAILURE;
03631 
03632     result = childNode->GetNodeType(&nodeType);
03633     if (NS_FAILED(result))
03634       return result;
03635 
03636     XMLT_LOG(mozXMLTermSession::GetScreenText,60,
03637              ("j=%d, nodeType=%d\n", j, nodeType));
03638     if (nodeType != nsIDOMNode::TEXT_NODE) {
03639       nsCOMPtr<nsIDOMNode> temNode;
03640       result = childNode->GetFirstChild(getter_AddRefs(temNode));
03641       if (NS_FAILED(result))
03642         return result;
03643 
03644       childNode = temNode;
03645 
03646       result = childNode->GetNodeType(&nodeType);
03647       if (NS_FAILED(result))
03648         return result;
03649       PR_ASSERT(nodeType == nsIDOMNode::TEXT_NODE);
03650     }
03651 
03652     nsCOMPtr<nsIDOMText> domText( do_QueryInterface(childNode) );
03653     result = domText->GetData(text);
03654     if (NS_FAILED(result))
03655       return result;
03656 
03657     XMLT_LOG(mozXMLTermSession::GetScreenText,60,("prevCols=%d\n",prevCols));
03658 
03659     if (prevCols+(PRInt32)text.Length() >= aCol) {
03660       // Determine offset in current text element
03661       textOffset = aCol - prevCols;
03662       textNode = childNode;
03663     } else if (j == nChildren-1) {
03664       // Position at end of line
03665       textOffset = text.Length();
03666       textNode = childNode;
03667     }
03668   }
03669 
03670   // Get selection
03671   nsCOMPtr<nsISelection> selection;
03672 
03673   nsCOMPtr<nsISelectionController> selCon;
03674   result = mXMLTerminal->GetSelectionController(getter_AddRefs(selCon));
03675   if (NS_FAILED(result) || !selCon)
03676     return NS_ERROR_FAILURE;
03677 
03678   result = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
03679                                     getter_AddRefs(selection));
03680 
03681   if (NS_SUCCEEDED(result) && selection) {
03682     // Collapse selection to cursor position
03683     result = selection->Collapse(textNode, textOffset);
03684   }
03685 
03686   return NS_OK;
03687 }
03688 
03689 
03695 NS_IMETHODIMP mozXMLTermSession::NewRow(nsIDOMNode* beforeRowNode,
03696                                         nsIDOMNode** resultNode)
03697 {
03698   nsresult result;
03699 
03700   XMLT_LOG(mozXMLTermSession::NewRow,60,("\n"));
03701 
03702   // Create PRE display node
03703   nsCOMPtr<nsIDOMNode> preNode, textNode;
03704   nsAutoString tagName(NS_LITERAL_STRING("pre"));
03705   nsAutoString elementName(NS_LITERAL_STRING("row"));
03706 
03707   result = NewElementWithText(tagName, elementName, -1,
03708                               mScreenNode, preNode, textNode);
03709 
03710   if (NS_FAILED(result) || !preNode || !textNode)
03711     return NS_ERROR_FAILURE;
03712 
03713   // Set PRE element attributes
03714   nsCOMPtr<nsIDOMElement> preElement = do_QueryInterface(preNode);
03715   nsAutoString att(NS_LITERAL_STRING("cols"));
03716   nsAutoString val; val.SetLength(0);
03717   val.AppendInt(mScreenCols,10);
03718   preElement->SetAttribute(att, val);
03719 
03720   att.AssignLiteral("rows");
03721   val.AssignLiteral("1");
03722   preElement->SetAttribute(att, val);
03723 
03724   if (beforeRowNode) {
03725     // Insert row node
03726     result = mScreenNode->InsertBefore(preNode, beforeRowNode, resultNode);
03727   } else {
03728     // Append row node
03729     result = mScreenNode->AppendChild(preNode, resultNode);
03730   }
03731 
03732   return NS_OK;
03733 }
03734 
03735 
03742 NS_IMETHODIMP mozXMLTermSession::DisplayRow(const nsString& aString,
03743                                             const nsString& aStyle,
03744                                             PRInt32 aRow)
03745 {
03746   nsresult result;
03747 
03748   const PRInt32   strLength   = aString.Length();
03749   const PRInt32   styleLength = aStyle.Length();
03750   const PRUnichar *strStyle   = aStyle.get();
03751 
03752   XMLT_LOG(mozXMLTermSession::DisplayRow,70,
03753            ("aRow=%d, strLength=%d, styleLength=%d\n",
03754             aRow, strLength, styleLength));
03755 
03756   // Check if line has uniform style
03757   PRUnichar uniformStyle = LTERM_STDOUT_STYLE;
03758 
03759   if (styleLength > 0) {
03760     PRInt32 j;
03761 
03762     PR_ASSERT(styleLength == strLength);
03763 
03764     uniformStyle = strStyle[0];
03765 
03766     for (j=1; j<strLength; j++) {
03767       if (strStyle[j] != strStyle[0]) {
03768         uniformStyle = 0;
03769       }
03770     }
03771   }
03772 
03773   nsCOMPtr<nsIDOMNode> rowNode;
03774   result = GetRow(aRow, getter_AddRefs(rowNode));
03775   if (NS_FAILED(result) || !rowNode)
03776     return NS_ERROR_FAILURE;
03777 
03778   nsCOMPtr<nsIDOMNodeList> childNodes;
03779   result = rowNode->GetChildNodes(getter_AddRefs(childNodes));
03780   if (NS_FAILED(result) || !childNodes)
03781     return NS_ERROR_FAILURE;
03782 
03783   PRUint32 nChildren = 0;
03784   childNodes->GetLength(&nChildren);
03785 
03786   XMLT_LOG(mozXMLTermSession::DisplayRow,79,("nChildren=%d\n", nChildren));
03787 
03788   if ((nChildren == 1) && (uniformStyle == LTERM_STDOUT_STYLE)) {
03789     // Get child node
03790     nsCOMPtr<nsIDOMNode> childNode;
03791 
03792     result = rowNode->GetFirstChild(getter_AddRefs(childNode));
03793     if (NS_FAILED(result) || !childNode)
03794       return NS_ERROR_FAILURE;
03795 
03796     nsCOMPtr<nsIDOMText> domText( do_QueryInterface(childNode) );
03797     if (domText) {
03798       // Display uniform style
03799       result = SetDOMText(childNode, aString);
03800       if (NS_FAILED(result))
03801         return result;
03802 
03803       return NS_OK;
03804     }
03805   }
03806 
03807   // Delete all child nodes for the row
03808   nsCOMPtr<nsIDOMNode> childNode;
03809   PRInt32 j;
03810   for (j=nChildren-1; j>=0; j--) {
03811     result = childNodes->Item(j, getter_AddRefs(childNode));
03812     if (NS_FAILED(result) || !childNode)
03813       return NS_ERROR_FAILURE;
03814 
03815     nsCOMPtr<nsIDOMNode> resultNode;
03816     result = rowNode->RemoveChild(childNode, getter_AddRefs(resultNode));
03817     if (NS_FAILED(result))
03818       return result;
03819   }
03820 
03821   nsCOMPtr<nsIDOMNode> spanNode, textNode;
03822   nsAutoString tagName(NS_LITERAL_STRING("span"));
03823   nsAutoString elementName;
03824   nsAutoString subString;
03825   PRInt32 k;
03826   PRUnichar currentStyle = LTERM_STDOUT_STYLE;
03827   if (styleLength > 0) 
03828     currentStyle = strStyle[0];
03829   PRInt32 offset = 0;
03830   offset = 0;
03831 
03832   PR_ASSERT(strLength > 0);
03833 
03834   for (k=1; k<strLength+1; k++) {
03835     if ((k == strLength) || ((k < styleLength) &&
03836                              (strStyle[k] != currentStyle)) ) {
03837       // Change of style or end of string
03838 
03839       if (currentStyle == LTERM_STDOUT_STYLE) {
03840         // Create text node
03841         result = NewTextNode(rowNode, textNode);
03842         if (NS_FAILED(result) || !textNode)
03843           return NS_ERROR_FAILURE;
03844 
03845       } else {
03846         // Span Node
03847 
03848         switch (currentStyle) {
03849         case LTERM_STDOUT_STYLE | LTERM_BOLD_STYLE:
03850           elementName.AssignLiteral("boldstyle");
03851           break;
03852         case LTERM_STDOUT_STYLE | LTERM_ULINE_STYLE:
03853           elementName.AssignLiteral("underlinestyle");
03854           break;
03855         case LTERM_STDOUT_STYLE | LTERM_BLINK_STYLE:
03856           elementName.AssignLiteral("blinkstyle");
03857           break;
03858         case LTERM_STDOUT_STYLE | LTERM_INVERSE_STYLE:
03859           elementName.AssignLiteral("inversestyle");
03860           break;
03861         default:
03862           elementName.AssignLiteral("boldstyle");
03863           break;
03864         }
03865 
03866         result = NewElementWithText(tagName, elementName, -1,
03867                                     rowNode, spanNode, textNode);
03868 
03869         if (NS_FAILED(result) || !spanNode || !textNode)
03870           return NS_ERROR_FAILURE;
03871       }
03872 
03873       aString.Mid(subString, offset, k-offset);
03874       result = SetDOMText(textNode, subString);
03875       if (NS_FAILED(result))
03876         return result;
03877 
03878       if (k < styleLength) {
03879         // Change style
03880         currentStyle = strStyle[k];
03881         offset = k;
03882       }
03883     }
03884   }
03885     
03886   return NS_OK;
03887 }
03888 
03889 
03893 NS_IMETHODIMP mozXMLTermSession::NewBreak(nsIDOMNode* parentNode)
03894 {
03895   nsresult result;
03896   nsAutoString tagName(NS_LITERAL_STRING("br"));
03897 
03898   XMLT_LOG(mozXMLTermSession::NewBreak,60,("\n"));
03899 
03900   // Create "br" element and append as child of specified parent
03901   nsCOMPtr<nsIDOMNode> brNode;
03902   nsAutoString name; name.SetLength(0);
03903   result = NewElement(tagName, name, -1, parentNode, brNode);
03904 
03905   if (NS_FAILED(result) || !brNode)
03906     return NS_ERROR_FAILURE;
03907 
03908   return NS_OK;
03909 }
03910 
03911 
03928 NS_IMETHODIMP mozXMLTermSession::NewElementWithText(const nsString& tagName,
03929                                       const nsString& name, PRInt32 number,
03930                                       nsIDOMNode* parentNode,
03931                                       nsCOMPtr<nsIDOMNode>& blockNode,
03932                                       nsCOMPtr<nsIDOMNode>& textNode,
03933                                       nsIDOMNode* beforeNode)
03934 {
03935   nsresult result;
03936 
03937   XMLT_LOG(mozXMLTermSession::NewElementWithText,80,("\n"));
03938 
03939   // Create block element
03940   result = NewElement(tagName, name, number, parentNode, blockNode,
03941                       beforeNode);
03942   if (NS_FAILED(result) || !blockNode)
03943     return NS_ERROR_FAILURE;
03944 
03945   // Create text node as child of block element
03946   result = NewTextNode(blockNode, textNode);
03947 
03948   if (NS_FAILED(result) || !textNode)
03949     return NS_ERROR_FAILURE;
03950 
03951   return NS_OK;
03952 }
03953 
03954 
03965 NS_IMETHODIMP mozXMLTermSession::NewAnchor(const nsString& classAttribute,
03966                                            PRInt32 number,
03967                                            nsIDOMNode* parentNode,
03968                                            nsCOMPtr<nsIDOMNode>& anchorNode)
03969 {
03970   nsresult result;
03971   nsAutoString tagName(NS_LITERAL_STRING("a"));
03972 
03973   XMLT_LOG(mozXMLTermSession::NewAnchor,80,("\n"));
03974 
03975   nsCOMPtr<nsIDOMDocument> domDoc;
03976   result = mXMLTerminal->GetDOMDocument(getter_AddRefs(domDoc));
03977   if (NS_FAILED(result) || !domDoc)
03978     return NS_ERROR_FAILURE;
03979 
03980   // Create anchor
03981   nsCOMPtr<nsIDOMElement> newElement;
03982   result = domDoc->CreateElement(tagName, getter_AddRefs(newElement));
03983   if (NS_FAILED(result) || !newElement)
03984     return NS_ERROR_FAILURE;
03985 
03986   // Set element attributes
03987   nsAutoString hrefAtt(NS_LITERAL_STRING("href"));
03988   nsAutoString hrefVal(NS_LITERAL_STRING("#"));
03989   newElement->SetAttribute(hrefAtt, hrefVal);
03990 
03991   if (!classAttribute.IsEmpty()) {
03992     nsAutoString classStr(NS_LITERAL_STRING("class"));
03993     newElement->SetAttribute(classStr, classAttribute);
03994 
03995     if (number >= 0) {
03996       nsAutoString idAtt(NS_LITERAL_STRING("id"));
03997       nsAutoString idVal(classAttribute);
03998       idVal.AppendInt(number,10);
03999       newElement->SetAttribute(idAtt, idVal);
04000     }
04001   }
04002 
04003   // Append child to parent
04004   nsCOMPtr<nsIDOMNode> newBlockNode = do_QueryInterface(newElement);
04005   result = parentNode->AppendChild(newBlockNode, getter_AddRefs(anchorNode));
04006   if (NS_FAILED(result) || !anchorNode)
04007     return NS_ERROR_FAILURE;
04008 
04009   return NS_OK;
04010 }
04011 
04012 
04027 NS_IMETHODIMP mozXMLTermSession::NewElement(const nsString& tagName,
04028                                      const nsString& name, PRInt32 number,
04029                                      nsIDOMNode* parentNode,
04030                                      nsCOMPtr<nsIDOMNode>& blockNode,
04031                                      nsIDOMNode* beforeNode)
04032 {
04033   nsresult result;
04034 
04035   XMLT_LOG(mozXMLTermSession::NewElement,80,("\n"));
04036 
04037   nsCOMPtr<nsIDOMDocument> domDoc;
04038   result = mXMLTerminal->GetDOMDocument(getter_AddRefs(domDoc));
04039   if (NS_FAILED(result) || !domDoc)
04040     return NS_ERROR_FAILURE;
04041 
04042   // Create element
04043   nsCOMPtr<nsIDOMElement> newElement;
04044   result = domDoc->CreateElement(tagName, getter_AddRefs(newElement));
04045   if (NS_FAILED(result) || !newElement)
04046     return NS_ERROR_FAILURE;
04047 
04048   if (!name.IsEmpty()) {
04049     // Set attributes
04050     nsAutoString classAtt(NS_LITERAL_STRING("class"));
04051     nsAutoString classVal(name);
04052     newElement->SetAttribute(classAtt, classVal);
04053 
04054     nsAutoString nameAtt(NS_LITERAL_STRING("name"));
04055     nsAutoString nameVal(name);
04056     newElement->SetAttribute(nameAtt, nameVal);
04057 
04058     if (number >= 0) {
04059       nsAutoString idAtt(NS_LITERAL_STRING("id"));
04060       nsAutoString idVal(name);
04061       idVal.AppendInt(number,10);
04062       newElement->SetAttribute(idAtt, idVal);
04063     }
04064   }
04065 
04066   nsCOMPtr<nsIDOMNode> newBlockNode = do_QueryInterface(newElement);
04067 
04068   if (beforeNode) {
04069     // Insert child
04070     result = parentNode->InsertBefore(newBlockNode, beforeNode,
04071                                       getter_AddRefs(blockNode));
04072     if (NS_FAILED(result) || !blockNode)
04073       return NS_ERROR_FAILURE;
04074 
04075   } else {
04076     // Append child
04077     result = parentNode->AppendChild(newBlockNode, getter_AddRefs(blockNode));
04078     if (NS_FAILED(result) || !blockNode)
04079       return NS_ERROR_FAILURE;
04080   }
04081 
04082   return NS_OK;
04083 }
04084 
04085 
04091 NS_IMETHODIMP mozXMLTermSession::NewTextNode( nsIDOMNode* parentNode,
04092                                        nsCOMPtr<nsIDOMNode>& textNode)
04093 {
04094   nsresult result;
04095 
04096   XMLT_LOG(mozXMLTermSession::NewTextNode,80,("\n"));
04097 
04098   nsCOMPtr<nsIDOMDocument> domDoc;
04099   result = mXMLTerminal->GetDOMDocument(getter_AddRefs(domDoc));
04100   if (NS_FAILED(result) || !domDoc)
04101     return NS_ERROR_FAILURE;
04102 
04103   // Create text node
04104   nsCOMPtr<nsIDOMText> newText;
04105   nsAutoString nullStr; nullStr.SetLength(0);
04106   result = domDoc->CreateTextNode(nullStr, getter_AddRefs(newText));
04107   if (NS_FAILED(result) || !newText)
04108     return NS_ERROR_FAILURE;
04109 
04110   // Append child to parent
04111   nsCOMPtr<nsIDOMNode> newTextNode = do_QueryInterface(newText);
04112   result = parentNode->AppendChild(newTextNode, getter_AddRefs(textNode));
04113   if (NS_FAILED(result))
04114     return NS_ERROR_FAILURE;
04115 
04116   return NS_OK;
04117 }
04118 
04119 
04131 NS_IMETHODIMP mozXMLTermSession::NewIFrame(nsIDOMNode* parentNode,
04132                                            PRInt32 number,
04133                                            PRInt32 frameBorder,
04134                                            const nsString& src,
04135                                            const nsString& width,
04136                                            const nsString& height)
04137                                            
04138 {
04139   nsresult result;
04140 
04141   XMLT_LOG(mozXMLTermSession::NewIFrame,80,("\n"));
04142 
04143   nsCOMPtr<nsIDOMDocument> domDoc;
04144   result = mXMLTerminal->GetDOMDocument(getter_AddRefs(domDoc));
04145   if (NS_FAILED(result) || !domDoc)
04146     return NS_ERROR_FAILURE;
04147 
04148 #if 0
04149   nsAutoString iframeFrag("<iframe name='iframe");
04150   iframeFrag.Append(number,10);
04151   iframeFrag.Append("' frameborder=")
04152   iframeFrag.Append(frameBorder,10);
04153   iframeFrag.Append(" src='");
04154   iframeFrag.Append(src)
04155   iframeFrag.Append("'> </iframe>\n");
04156   result = InsertFragment(iframeFrag, parentNode, number);
04157   if (NS_FAILED(result))
04158     return result;
04159 
04160   return NS_OK;
04161 #else
04162   // Create IFRAME element
04163   nsCOMPtr<nsIDOMElement> newElement;
04164   nsAutoString tagName(NS_LITERAL_STRING("iframe"));
04165   result = domDoc->CreateElement(tagName, getter_AddRefs(newElement));
04166   if (NS_FAILED(result) || !newElement)
04167     return NS_ERROR_FAILURE;
04168 
04169   nsAutoString attName, attValue;
04170 
04171   // Set attributes
04172   if (number >= 0) {
04173     attName.AssignLiteral("name");
04174     attValue.AssignLiteral("iframe");
04175     attValue.AppendInt(number,10);
04176     newElement->SetAttribute(attName, attValue);
04177   }
04178 
04179   attName.AssignLiteral("frameborder");
04180   attValue.SetLength(0);
04181   attValue.AppendInt(frameBorder,10);
04182   newElement->SetAttribute(attName, attValue);
04183 
04184   if (!src.IsEmpty()) {
04185     // Set SRC attribute
04186     attName.AssignLiteral("src");
04187     newElement->SetAttribute(attName, src);
04188   }
04189 
04190   if (!width.IsEmpty()) {
04191     // Set WIDTH attribute
04192     attName.AssignLiteral("width");
04193     newElement->SetAttribute(attName, width);
04194   }
04195 
04196   if (!height.IsEmpty()) {
04197     // Set HEIGHT attribute
04198     attName.AssignLiteral("height");
04199     newElement->SetAttribute(attName, height);
04200   }
04201 
04202   // Append child to parent
04203   nsCOMPtr<nsIDOMNode> iframeNode;
04204   nsCOMPtr<nsIDOMNode> newNode = do_QueryInterface(newElement);
04205   result = parentNode->AppendChild(newNode, getter_AddRefs(iframeNode));
04206   if (NS_FAILED(result) || !iframeNode)
04207     return NS_ERROR_FAILURE;
04208 
04209   return NS_OK;
04210 #endif
04211 }
04212 
04213 
04219 NS_IMETHODIMP mozXMLTermSession::SetEventAttributes(const nsString& name,
04220                                                     PRInt32 number,
04221                                              nsCOMPtr<nsIDOMNode>& domNode)
04222 {
04223   nsresult result;
04224 
04225   nsCOMPtr <nsIDOMElement> domElement = do_QueryInterface(domNode);
04226   if (!domElement)
04227     return NS_ERROR_FAILURE;
04228 
04229   int j;
04230   for (j=0; j<SESSION_EVENT_TYPES; j++) {
04231     nsAutoString attName(NS_LITERAL_STRING("on"));
04232     attName.AppendASCII(sessionEventNames[j]);
04233 
04234     nsAutoString attValue(NS_LITERAL_STRING("return HandleEvent(event, '"));
04235     attValue.AppendASCII(sessionEventNames[j]);
04236     attValue.AppendLiteral("','");
04237     attValue.Append(name);
04238     attValue.AppendLiteral("','");
04239     attValue.AppendInt(number,10);
04240     attValue.Append(NS_LITERAL_STRING("','');"));
04241 
04242     result = domElement->SetAttribute(attName, attValue);
04243     if (NS_FAILED(result))
04244       return NS_ERROR_FAILURE;
04245   }
04246 
04247   return NS_OK;
04248 }
04249 
04250 
04255 NS_IMETHODIMP mozXMLTermSession::SetDOMText(nsCOMPtr<nsIDOMNode>& textNode,
04256                                             const nsString& aString)
04257 {
04258   nsresult result;
04259 
04260   nsCOMPtr<nsIDOMText> domText (do_QueryInterface(textNode));
04261   if (!domText)
04262     return NS_ERROR_FAILURE;
04263 
04264   result = domText->SetData(aString);
04265 
04266   return result;
04267 }
04268 
04269 
04274 PRBool mozXMLTermSession::IsTextNode(nsIDOMNode *aNode)
04275 {
04276   if (!aNode) {
04277     NS_NOTREACHED("null node passed to IsTextNode()");
04278     return PR_FALSE;
04279   }
04280 
04281   XMLT_LOG(mozXMLTermSession::IsTextNode,90,("\n"));
04282 
04283   PRUint16 nodeType;
04284   aNode->GetNodeType(&nodeType);
04285   if (nodeType == nsIDOMNode::TEXT_NODE)
04286     return PR_TRUE;
04287     
04288   return PR_FALSE;
04289 }
04290 
04291 
04297 PRBool mozXMLTermSession::IsPREInlineNode(nsIDOMNode* aNode)
04298 {
04299   nsresult result;
04300   PRBool isPREInlineNode = PR_FALSE;
04301 
04302   nsCOMPtr<nsIDOMText> domText = do_QueryInterface(aNode);
04303 
04304   if (domText) {
04305     isPREInlineNode = PR_TRUE;
04306 
04307   } else {
04308     nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(aNode);
04309 
04310     if (domElement) {
04311       nsAutoString tagName; tagName.SetLength(0);
04312       result = domElement->GetTagName(tagName);
04313       if (NS_SUCCEEDED(result)) {
04314         isPREInlineNode = tagName.LowerCaseEqualsLiteral("span") ||
04315                           tagName.LowerCaseEqualsLiteral("a");
04316       }
04317     }
04318   }
04319 
04320   return isPREInlineNode;
04321 }
04322 
04323 
04334 NS_IMETHODIMP mozXMLTermSession::ToHTMLString(nsIDOMNode* aNode,
04335                                               nsString& indentString,
04336                                               nsString& htmlString,
04337                                               PRBool deepContent,
04338                                               PRBool insidePRENode)
04339 {
04340   nsresult result;
04341 
04342   XMLT_LOG(mozXMLTermSession::ToHTMLString,80,("\n"));
04343 
04344   nsAutoString newIndentString (indentString);
04345   newIndentString.AppendLiteral("  ");
04346 
04347   htmlString.SetLength(0);
04348 
04349   nsCOMPtr<nsIDOMText> domText( do_QueryInterface(aNode) );
04350 
04351   if (domText) {
04352     // Text node
04353     domText->GetData(htmlString);
04354     htmlString.ReplaceChar(kNBSP, ' ');
04355 
04356   } else {
04357     nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(aNode);
04358 
04359     if (domElement) {
04360       nsAutoString tagName; tagName.SetLength(0);
04361       domElement->GetTagName(tagName);
04362 
04363       if (!insidePRENode) {
04364         htmlString += indentString;
04365       }
04366       htmlString.AppendLiteral("<");
04367       htmlString += tagName;
04368 
04369       PRBool isPRENode = tagName.LowerCaseEqualsLiteral("pre");
04370 
04371       nsCOMPtr<nsIDOMNamedNodeMap> namedNodeMap(nsnull);
04372       result = aNode->GetAttributes(getter_AddRefs(namedNodeMap));
04373 
04374       if (NS_SUCCEEDED(result) && namedNodeMap) {
04375         // Print all attributes
04376         PRUint32 nodeCount, j;
04377         result = namedNodeMap->GetLength(&nodeCount);
04378 
04379         if (NS_SUCCEEDED(result)) {
04380           nsCOMPtr<nsIDOMNode> attrNode;
04381 
04382           for (j=0; j<nodeCount; j++) {
04383             result = namedNodeMap->Item(j, getter_AddRefs(attrNode));
04384 
04385             if (NS_SUCCEEDED(result)) {
04386               nsCOMPtr<nsIDOMAttr> attr = do_QueryInterface(attrNode);
04387 
04388               if (attr) {
04389                 nsAutoString attrName; attrName.SetLength(0);
04390                 nsAutoString attrValue; attrValue.SetLength(0);
04391 
04392                 result = attr->GetName(attrName);
04393                 if (NS_SUCCEEDED(result)) {
04394                   htmlString.AppendLiteral(" ");
04395                   htmlString.Append(attrName);
04396                 }
04397 
04398                 result = attr->GetValue(attrValue);
04399                 if (NS_SUCCEEDED(result) && !attrName.IsEmpty()) {
04400                   htmlString.AppendLiteral("=\"");
04401                   htmlString.Append(attrValue);
04402                   htmlString.AppendLiteral("\"");
04403                 }
04404               }
04405             }
04406           }
04407         }
04408       }
04409 
04410       if (!deepContent) {
04411         htmlString.AppendLiteral(">");
04412 
04413       } else {
04414         // Iterate over all child nodes to generate deep content
04415         nsCOMPtr<nsIDOMNode> child;
04416         result = aNode->GetFirstChild(getter_AddRefs(child));
04417 
04418         nsAutoString htmlInner;
04419         while (child) {
04420           nsAutoString innerString;
04421           ToHTMLString(child, newIndentString, innerString, deepContent,
04422                        isPRENode);
04423 
04424           htmlInner += innerString;
04425 
04426           nsCOMPtr<nsIDOMNode> temp = child;
04427           result = temp->GetNextSibling(getter_AddRefs(child));
04428           if (NS_FAILED(result))
04429             break;
04430         }
04431 
04432         if (!htmlInner.IsEmpty()) {
04433           if (insidePRENode)
04434             htmlString.AppendLiteral("\n>");
04435           else
04436             htmlString.AppendLiteral(">\n");
04437 
04438           htmlString += htmlInner;
04439 
04440           if (!insidePRENode)
04441             htmlString += indentString;
04442         } else {
04443           htmlString.AppendLiteral(">");
04444         }
04445 
04446         htmlString.AppendLiteral("</");
04447         htmlString += tagName;
04448 
04449         if (insidePRENode)
04450           htmlString.AppendLiteral("\n");
04451         htmlString.AppendLiteral(">");
04452 
04453         if (!insidePRENode)
04454           htmlString.AppendLiteral("\n");
04455       }
04456     }
04457   }
04458 
04459   return NS_OK;
04460 }
04461 
04462 
04469 void mozXMLTermSession::TraverseDOMTree(FILE* fileStream,
04470                                  nsIDOMNode* rootNode,
04471                                  nsCOMPtr<nsIDOMNode>& currentNode,
04472                                  TreeActionCode treeActionCode)
04473 {
04474   static const PRInt32 NODE_TYPE_NAMES = 12;
04475 
04476   static const char* const nodeTypeNames[NODE_TYPE_NAMES] = {
04477     "ELEMENT",
04478     "ATTRIBUTE",
04479     "TEXT",
04480     "CDATA_SECTION",
04481     "ENTITY_REFERENCE",
04482     "ENTITY_NODE",
04483     "PROCESSING_INSTRUCTION",
04484     "COMMENT",
04485     "DOCUMENT",
04486     "DOCUMENT_TYPE",
04487     "DOCUMENT_FRAGMENT",
04488     "NOTATION_NODE"
04489   };
04490 
04491   static const PRInt32 PRINT_ATTRIBUTE_NAMES = 2;
04492 
04493   static const char* const printAttributeNames[PRINT_ATTRIBUTE_NAMES] = {
04494     "class",
04495     "id"
04496   };
04497 
04498   nsresult result = NS_ERROR_FAILURE;
04499   nsCOMPtr<nsIDOMNode> moveNode(nsnull);
04500   nsCOMPtr<nsIDOMNamedNodeMap> namedNodeMap(nsnull);
04501 
04502   switch (treeActionCode) {
04503   case TREE_MOVE_UP:
04504     if (currentNode.get() != rootNode) {
04505       result = currentNode->GetParentNode(getter_AddRefs(moveNode));
04506 
04507       if (NS_SUCCEEDED(result) && moveNode) {
04508         // Move up to parent node
04509         currentNode = moveNode;
04510       }
04511 
04512     } else {
04513       fprintf(fileStream, "TraverseDOMTree: already at the root node \n");
04514     }
04515     break;
04516 
04517   case TREE_MOVE_DOWN:
04518     result = currentNode->GetFirstChild(getter_AddRefs(moveNode));
04519 
04520     if (NS_SUCCEEDED(result) && moveNode) {
04521       // Move down to child node
04522       currentNode = moveNode;
04523     } else {
04524       fprintf(fileStream, "TraverseDOMTree: already at a leaf node\n");
04525     }
04526     break;
04527 
04528   case TREE_MOVE_LEFT:
04529     if (currentNode.get() != rootNode) {
04530       result = currentNode->GetPreviousSibling(getter_AddRefs(moveNode));
04531 
04532       if (NS_SUCCEEDED(result) && moveNode) {
04533         // Move to previous sibling node
04534         currentNode = moveNode;
04535       } else {
04536         fprintf(fileStream, "TraverseDOMTree: already at leftmost node\n");
04537       }
04538     } else {
04539       fprintf(fileStream, "TraverseDOMTree: already at the root node \n");
04540     }
04541     break;
04542 
04543   case TREE_MOVE_RIGHT:
04544     if (currentNode.get() != rootNode) {
04545       result = currentNode->GetNextSibling(getter_AddRefs(moveNode));
04546 
04547       if (NS_SUCCEEDED(result) && moveNode) {
04548         // Move to next sibling node
04549         currentNode = moveNode;
04550       } else {
04551         fprintf(fileStream, "TraverseDOMTree: already at rightmost node\n");
04552       }
04553     } else {
04554       fprintf(fileStream, "TraverseDOMTree: already at the root node \n");
04555     }
04556     break;
04557 
04558   case TREE_PRINT_ATTS:
04559   case TREE_PRINT_HTML:
04560     if (PR_TRUE) {
04561       nsAutoString indentString; indentString.SetLength(0);
04562       nsAutoString htmlString;
04563       ToHTMLString(currentNode, indentString, htmlString,
04564                    (PRBool) (treeActionCode == TREE_PRINT_HTML) );
04565 
04566       fprintf(fileStream, "%s:\n", treeActionNames[treeActionCode-1]);
04567 
04568       char* htmlCString = ToNewCString(htmlString);
04569       fprintf(fileStream, "%s", htmlCString);
04570       nsCRT::free(htmlCString);
04571 
04572       fprintf(fileStream, "\n");
04573     }
04574     break;
04575 
04576   default:
04577     fprintf(fileStream, "mozXMLTermSession::TraverseDOMTree - unknown action %d\n",
04578             treeActionCode);
04579   }
04580 
04581   if (NS_SUCCEEDED(result) && moveNode) {
04582     PRUint16 nodeType = 0;
04583 
04584     moveNode->GetNodeType(&nodeType);
04585     fprintf(fileStream, "%s%s: ", treeActionNames[treeActionCode-1],
04586                                   nodeTypeNames[nodeType-1]);
04587 
04588     nsCOMPtr<nsIDOMElement> domElement;
04589     domElement = do_QueryInterface(moveNode);
04590     if (domElement) {
04591       nsAutoString tagName; tagName.SetLength(0);
04592 
04593       result = domElement->GetTagName(tagName);
04594       if (NS_SUCCEEDED(result)) {
04595         char* tagCString = ToNewCString(tagName);
04596         fprintf(fileStream, "%s", tagCString);
04597         nsCRT::free(tagCString);
04598 
04599         // Print selected attribute values
04600         int j;
04601         for (j=0; j<PRINT_ATTRIBUTE_NAMES; j++) {
04602           nsAutoString attName; attName.AssignASCII (printAttributeNames[j]);
04603           nsAutoString attValue;
04604          attValue.SetLength(0);
04605 
04606           result = domElement->GetAttribute(attName, attValue);
04607           if (NS_SUCCEEDED(result) && !attValue.IsEmpty()) {
04608             // Print attribute value
04609             char* tagCString2 = ToNewCString(attValue);
04610             fprintf(fileStream, " %s=%s", printAttributeNames[j], tagCString2);
04611             nsCRT::free(tagCString2);
04612           }
04613         }
04614       }
04615     }
04616     fprintf(fileStream, "\n");
04617   }
04618 }