diff --git a/mozilla/extensions/xmlterm/base/README b/mozilla/extensions/xmlterm/base/README index 42ac1dc0bf6..44542fa84d9 100644 --- a/mozilla/extensions/xmlterm/base/README +++ b/mozilla/extensions/xmlterm/base/README @@ -9,9 +9,11 @@ of invoking XMLterm. XMLterm control-flow/layering hierarchy ======================================= - mozilla-executable xmlterm-executable + mozilla-executable geckoterm-executable | | - ../ui/content/xmlterm.html | + ../ui/content/xmlterm.xul | + | | + ../ui/content/xmlterm.html ../ui/content/xmlterm.html | | mozXMLTermShell ../geckoterm/mozGeckoTerm | | | @@ -24,11 +26,11 @@ of invoking XMLterm. mozXMLTermSession mozLineTermAux mozXMLTermListeners | | | | | | - mozXMLTermStream... (LineTerm) (user input) - (rendering ...) (pseudo-TTY/shell) + (rendering...) (LineTerm) (user input) + (pseudo-TTY/shell) -2 Dec 1999 +1 Mar 2000 =========================================================================== FILES: diff --git a/mozilla/extensions/xmlterm/base/lineterm.h b/mozilla/extensions/xmlterm/base/lineterm.h index a65c22e084b..579c1ae79f8 100644 --- a/mozilla/extensions/xmlterm/base/lineterm.h +++ b/mozilla/extensions/xmlterm/base/lineterm.h @@ -273,10 +273,11 @@ int lterm_metacomplete(int lterm, const UNICHAR *buf, int count); * OPCODES contains a bit mask describing the type of output (see below). * Using Extended Backus-Naur Form notation: * - * OPCODES ::= STREAMDATA NEWLINE? + * OPCODES ::= STREAMDATA NEWLINE? ERROR? * COOKIESTR? DOCSTREAM? XMLSTREAM? JSSTREAM? WINSTREAM? * if StreamMode data is being returned. - * (NEWLINE, if set, denotes that the stream has terminated) + * (NEWLINE, if set, denotes that the stream has terminated; + * if ERROR is also set, it means that the stream has terminated abnormally.) * * OPCODES ::= SCREENDATA BELL? ( OUTPUT | CLEAR | INSERT | DELETE | SCROLL )? * if ScreenMode data is being returned. @@ -337,12 +338,13 @@ int lterm_read(int lterm, int timeout, UNICHAR *buf, int count, #define LTERM_COMPLETION_CODE 0x1000U /* Completion requested */ #define LTERM_NEWLINE_CODE 0x2000U /* Complete (new) line */ #define LTERM_HIDE_CODE 0x4000U /* Hide output */ +#define LTERM_ERROR_CODE 0x8000U /* Error in output */ -#define LTERM_COOKIESTR_CODE 0x8000U /* Stream prefixed with cookie */ -#define LTERM_DOCSTREAM_CODE 0x10000U /* Stream contains complete document */ -#define LTERM_XMLSTREAM_CODE 0x20000U /* Stream contains XML, not HTML */ -#define LTERM_JSSTREAM_CODE 0x40000U /* Stream contains Javascript */ -#define LTERM_WINSTREAM_CODE 0x80000U /* Display stream in entire window */ +#define LTERM_COOKIESTR_CODE 0x10000U /* Stream prefixed with cookie */ +#define LTERM_DOCSTREAM_CODE 0x20000U /* Stream contains complete document */ +#define LTERM_XMLSTREAM_CODE 0x40000U /* Stream contains XML, not HTML */ +#define LTERM_JSSTREAM_CODE 0x80000U /* Stream contains Javascript */ +#define LTERM_WINSTREAM_CODE 0x100000U /* Display stream in entire window */ /* LTERM/XTERM 16-bit style mask: diff --git a/mozilla/extensions/xmlterm/base/ltermEscape.c b/mozilla/extensions/xmlterm/base/ltermEscape.c index 6fed6ad1f0a..47905b00c93 100644 --- a/mozilla/extensions/xmlterm/base/ltermEscape.c +++ b/mozilla/extensions/xmlterm/base/ltermEscape.c @@ -741,6 +741,11 @@ static int ltermProcessCSISequence(struct lterms *lts, const UNICHAR *buf, * Ps = 37 / 47 fg/bg White * Ps = 39 / 49 fg/bg Default */ + + /* Enforce default value for parameter (hack!) */ + if (paramCount == 0) + param1 = 0; + LTERM_LOG(ltermProcessCSISequence,52,("Character Attr %d\n", param1)); switch (param1) { case 0: @@ -868,6 +873,7 @@ static int ltermProcessDECPrivateMode(struct lterms *lts, const int *paramValues, int paramCount, UNICHAR uch, int *opcodes) { struct LtermOutput *lto = &(lts->ltermOutput); + int param1, param2; LTERM_LOG(ltermProcessDECPrivateMode,50,("ch='%c', cursorChar=%d, Chars=%d\n", (char) uch, lto->outputCursorChar, lto->outputChars)); @@ -875,13 +881,31 @@ static int ltermProcessDECPrivateMode(struct lterms *lts, /* Set returned opcodes to zero */ *opcodes = 0; + /* Default parameter values: 1, 1 */ + param1 = (paramCount > 0) ? paramValues[0] : 1; + param2 = (paramCount > 1) ? paramValues[1] : 1; + switch (uch) { case U_h_CHAR: /* DEC Private Mode Set (DECSET) */ LTERM_LOG(ltermProcessDECPrivateMode,2,("Unimplemented %c\n", (char) uch)); + if ((param1 % 100) == 47) { + /* Switch to screen mode */ + if (lto->outputMode == LTERM2_LINE_MODE) { + ltermSwitchToScreenMode(lts); + *opcodes = LTERM_SCREENDATA_CODE | LTERM_CLEAR_CODE; + } + } return 0; case U_l_CHAR: /* DEC Private Mode Reset (DECRST) */ LTERM_LOG(ltermProcessDECPrivateMode,2,("Unimplemented %c\n", (char) uch)); + if ((param1 % 100) == 47) { + /* Switch to line mode */ + if (lto->outputMode == LTERM1_SCREEN_MODE) { + ltermSwitchToLineMode(lts); + *opcodes = LTERM_LINEDATA_CODE; + } + } return 0; case U_r_CHAR: /* Restore previously saved DEC Private Mode Values */ diff --git a/mozilla/extensions/xmlterm/base/ltermIO.c b/mozilla/extensions/xmlterm/base/ltermIO.c index 3666f2cd96b..73096c9053c 100644 --- a/mozilla/extensions/xmlterm/base/ltermIO.c +++ b/mozilla/extensions/xmlterm/base/ltermIO.c @@ -438,7 +438,8 @@ int ltermWrite(struct lterms *lts, int *opcodes) /** Reads a (possibly incomplete) line from LTERM. * The LtermRead structure *LTR contains both input and output parameters, * returning opcodes values of - * OPCODES ::= STREAMDATA NEWLINE? COOKIESTR? DOCSTREAM? XMLSTREAM? WINSTREAM? + * OPCODES ::= STREAMDATA NEWLINE? ERROR? + * COOKIESTR? DOCSTREAM? XMLSTREAM? WINSTREAM? * if StreamMode data is being returned. * * OPCODES ::= SCREENDATA BELL? ( OUTPUT | CLEAR | INSERT | DELETE | SCROLL )? @@ -790,10 +791,27 @@ int ltermRead(struct lterms *lts, struct LtermRead *ltr, int timeout) return -1; } +/** Interrupts output operations in response to an input TTY interrupt signal + * @return 0 if successful, + * -1 if an error occurred + */ +int ltermInterruptOutput(struct lterms *lts) +{ + struct LtermOutput *lto = &(lts->ltermOutput); + + if (lto->outputMode == LTERM0_STREAM_MODE) { + /* Abnormally terminate output stream */ + lto->streamOpcodes |= LTERM_ERROR_CODE; + } + + return 0; +} + /** Returns stream data from STDOUT * (Auxiliary procedure for ltermRead.) - * OPCODES ::= STREAMDATA NEWLINE? COOKIESTR? DOCSTREAM? XMLSTREAM? WINSTREAM? + * OPCODES ::= STREAMDATA NEWLINE? ERROR? + * COOKIESTR? DOCSTREAM? XMLSTREAM? WINSTREAM? * The LtermRead structure *LTR contains both input and output parameters. * @return 0 if successful, * -1 if an error occurred while reading, @@ -806,9 +824,28 @@ static int ltermReturnStreamData(struct lterms *lts, struct LtermRead *ltr) LTERM_LOG(ltermReturnStreamData,30,("start\n")); - if (lto->decodedChars == 0) + if (lto->streamOpcodes & LTERM_ERROR_CODE) { + /* Error in stream output; terminate stream abnormally */ + LTERM_LOG(ltermReturnStreamData,32,("Error termination of STREAM mode\n")); + + if (lto->savedOutputMode == LTERM1_SCREEN_MODE) { + if (ltermSwitchToScreenMode(lts) != 0) + return -1; + } else { + if (ltermSwitchToLineMode(lts) != 0) + return -1; + } + + ltr->opcodes = lto->streamOpcodes | LTERM_STREAMDATA_CODE + | LTERM_NEWLINE_CODE; + ltr->read_count = 0; return 0; + } else if (lto->decodedChars == 0) { + /* No output data available; return null opcode */ + return 0; + } + ltr->opcodes = LTERM_STREAMDATA_CODE | lto->streamOpcodes; if (ucslen(lto->streamTerminator) == 0) { @@ -866,7 +903,7 @@ static int ltermReturnStreamData(struct lterms *lts, struct LtermRead *ltr) if (ltermSwitchToLineMode(lts) != 0) return -1; } - LTERM_LOG(ltermReturnStreamData,22,("terminating STREAM mode\n")); + LTERM_LOG(ltermReturnStreamData,32,("terminating STREAM mode\n")); } } diff --git a/mozilla/extensions/xmlterm/base/ltermInput.c b/mozilla/extensions/xmlterm/base/ltermInput.c index 325dd5d945b..3359c11d0da 100644 --- a/mozilla/extensions/xmlterm/base/ltermInput.c +++ b/mozilla/extensions/xmlterm/base/ltermInput.c @@ -460,6 +460,12 @@ static int ltermLineInput(struct lterms *lts, uch = U_LINEFEED; /* essentially newline behaviour otherwise */ } + if (uch == lts->control[TTYINTERRUPT]) { + /* Interrupt output operations, if necessary */ + if (ltermInterruptOutput(lts) != 0) + return -1; + } + if (metaInput) { /* meta input; do not send line */ *opcodes |= LTERM_META_CODE; @@ -536,6 +542,15 @@ static int ltermLineInput(struct lterms *lts, case U_CTL_Y: /* yank */ case U_TAB: /* command completion */ + if ( (lti->inputChars == 0) && (uch == U_CTL_D) && + !((lts->processType == LTERM_TCSH_PROCESS) && + (lti->inputMode >= LTERM3_COMPLETION_MODE)) ) { + /* If lone ^D and not TCSH completion, simply transmit it */ + if (ltermSendData(lts, &uch, 1) != 0) + return -1; + return 0; + } + /* Assert that completion character occurs at end of buffer; * enforced by lterm_write. */ @@ -633,14 +648,6 @@ static int ltermRequestCompletion(struct lterms *lts, UNICHAR uch) LTERM_LOG(ltermRequestCompletion,40, ("++++++++++++ COMPLETION REQUEST uch=0x%X\n\n", uch)); - if ((uch == U_CTL_D) && - !(lts->processType == LTERM_TCSH_PROCESS)){ - /* If ^D and not TCSH, simply transmit character */ - if (ltermSendData(lts, &uch, 1) != 0) - return -1; - return 0; - } - switch (uch) { case U_TAB: /* Send line and copy to echo buffer */ diff --git a/mozilla/extensions/xmlterm/base/ltermPrivate.h b/mozilla/extensions/xmlterm/base/ltermPrivate.h index 0847b13d916..8f80a296ad3 100644 --- a/mozilla/extensions/xmlterm/base/ltermPrivate.h +++ b/mozilla/extensions/xmlterm/base/ltermPrivate.h @@ -535,6 +535,7 @@ extern LtermGlobal ltermGlobal; /* Visible prototypes */ /* ltermIO.c */ +int ltermInterruptOutput(struct lterms *lts); int ltermSendLine(struct lterms *lts, UNICHAR uch, int echoControl, int completionCode); int ltermRead(struct lterms *lts, struct LtermRead *ltr, int timeout); diff --git a/mozilla/extensions/xmlterm/base/mozXMLTermListeners.cpp b/mozilla/extensions/xmlterm/base/mozXMLTermListeners.cpp index 41e300ee230..3e0c3458d1f 100644 --- a/mozilla/extensions/xmlterm/base/mozXMLTermListeners.cpp +++ b/mozilla/extensions/xmlterm/base/mozXMLTermListeners.cpp @@ -330,6 +330,12 @@ mozXMLTermKeyListener::KeyPress(nsIDOMEvent* aKeyEvent) case nsIDOMKeyEvent::DOM_VK_PAGE_DOWN: JSCommand = "ScrollPageDown"; break; + case nsIDOMKeyEvent::DOM_VK_F1: + JSCommand = "HideAll"; + break; + case nsIDOMKeyEvent::DOM_VK_F2: + JSCommand = "ShowAll"; + break; default: // ignore event without consuming return NS_OK; } diff --git a/mozilla/extensions/xmlterm/base/mozXMLTermSession.cpp b/mozilla/extensions/xmlterm/base/mozXMLTermSession.cpp index c05214abeea..46deae76297 100644 --- a/mozilla/extensions/xmlterm/base/mozXMLTermSession.cpp +++ b/mozilla/extensions/xmlterm/base/mozXMLTermSession.cpp @@ -74,9 +74,12 @@ const char* const mozXMLTermSession::sessionElementNames[] = { "command", "stdin", "stdout", - "stderr" + "stderr", + "mixed", + "warning" }; +// Should HTML event names should always be in lower case for DOM to work? const char* const mozXMLTermSession::sessionEventNames[] = { "click", "dblclick" @@ -119,7 +122,7 @@ mozXMLTermSession::mozXMLTermSession() : mStartEntryNode(nsnull), mCurrentEntryNode(nsnull), - mMaxHistory(50), + mMaxHistory(20), mStartEntryNumber(0), mCurrentEntryNumber(0), @@ -142,9 +145,10 @@ mozXMLTermSession::mozXMLTermSession() : mMetaCommandType(NO_META_COMMAND), mAutoDetect(FIRST_LINE), - mLineBreakNeeded(false), mFirstOutputLine(false), + mEntryOutputLines(0), + mPreTextBufferLines(0), mPreTextIncomplete(""), mPreTextBuffered(""), mPreTextDisplayed(""), @@ -456,7 +460,7 @@ NS_IMETHODIMP mozXMLTermSession::ReadAll(mozILineTermAux* lineTermAux, { PRInt32 opcodes, opvals, buf_row, buf_col; PRUnichar *buf_str, *buf_style; - PRBool newline, streamData, screenData; + PRBool newline, errorFlag, streamData, screenData; nsAutoString bufString, bufStyle; XMLT_LOG(mozXMLTermSession::ReadAll,60,("\n")); @@ -490,6 +494,7 @@ NS_IMETHODIMP mozXMLTermSession::ReadAll(mozILineTermAux* lineTermAux, screenData = (opcodes & LTERM_SCREENDATA_CODE); streamData = (opcodes & LTERM_STREAMDATA_CODE); newline = (opcodes & LTERM_NEWLINE_CODE); + errorFlag = (opcodes & LTERM_ERROR_CODE); // Copy character/style strings bufString = buf_str; @@ -507,8 +512,8 @@ NS_IMETHODIMP mozXMLTermSession::ReadAll(mozILineTermAux* lineTermAux, // Initiate screen mode XMLT_LOG(mozXMLTermSession::ReadAll,62,("Initiate SCREEN mode\n")); - // Break stream output display - result = BreakOutput(); + // Break output display + result = BreakOutput(PR_FALSE); if (NS_FAILED(result)) break; @@ -534,12 +539,26 @@ NS_IMETHODIMP mozXMLTermSession::ReadAll(mozILineTermAux* lineTermAux, // Delete screen element nsCOMPtr resultNode; mSessionNode->RemoveChild(mScreenNode, getter_AddRefs(resultNode)); + if (NS_FAILED(result)) + break; mScreenNode = nsnull; if (mRestoreInputEcho) { lineTermAux->SetEchoFlag(true); mRestoreInputEcho = false; } + + // Show the caret + // WORKAROUND for some unknown bug in the full screen implementation. + // Without this, if you delete a line using "vi" and save the file, + // the cursor suddenly disappears + nsCOMPtr caret; + if (NS_SUCCEEDED(mPresShell->GetCaret(getter_AddRefs(caret)))) { + caret->SetCaretVisible(PR_TRUE); + caret->SetCaretReadOnly(PR_FALSE); + } + + mPresShell->SetCaretEnabled(PR_TRUE); } if (streamData) { @@ -570,9 +589,9 @@ NS_IMETHODIMP mozXMLTermSession::ReadAll(mozILineTermAux* lineTermAux, } } else { - // Insecure stream; treat as text fragment + // Insecure stream; do not display streamURL = "http://in.sec.ure"; - streamMarkupType = TEXT_FRAGMENT; + streamMarkupType = INSECURE_FRAGMENT; } if (!(opcodes & LTERM_JSSTREAM_CODE) && @@ -604,8 +623,12 @@ NS_IMETHODIMP mozXMLTermSession::ReadAll(mozILineTermAux* lineTermAux, mEntryHasOutput = true; } + if (errorFlag) { + mOutputMarkupType = INCOMPLETE_FRAGMENT; + } + // Break stream output display - result = BreakOutput(); + result = BreakOutput(PR_TRUE); if (NS_FAILED(result)) break; @@ -669,7 +692,7 @@ NS_IMETHODIMP mozXMLTermSession::ReadAll(mozILineTermAux* lineTermAux, } for (row=0; row < opvals; row++) - NewRow(rowNode); + NewRow(rowNode, getter_AddRefs(resultNode)); } } else if (opcodes & LTERM_DELETE_CODE) { @@ -706,7 +729,7 @@ NS_IMETHODIMP mozXMLTermSession::ReadAll(mozILineTermAux* lineTermAux, } for (row=0; row < opvals; row++) - NewRow(rowNode); + NewRow(rowNode, getter_AddRefs(resultNode)); } } else if (opcodes & LTERM_SCROLL_CODE) { @@ -729,7 +752,7 @@ NS_IMETHODIMP mozXMLTermSession::ReadAll(mozILineTermAux* lineTermAux, break; } - // Determine cursor position + // Determine cursor position and position cursor PRInt32 cursorRow = 0; PRInt32 cursorCol = 0; result = lineTermAux->GetCursorRow(&cursorRow); @@ -738,26 +761,7 @@ NS_IMETHODIMP mozXMLTermSession::ReadAll(mozILineTermAux* lineTermAux, XMLT_LOG(mozXMLTermSession::ReadAll,62, ("cursorRow=%d, cursorCol=%d\n", cursorRow, cursorCol)); - // Get selection - nsCOMPtr selection; - - result = mPresShell->GetSelection(SELECTION_NORMAL, - getter_AddRefs(selection)); - if (NS_SUCCEEDED(result) && selection) { - // Collapse selection to cursor position - nsCOMPtr cursTextNode; - PRInt32 offset; - - result = GetScreenText(cursorRow, cursorCol, - getter_AddRefs(cursTextNode), &offset); - - if (NS_FAILED(result) || !cursTextNode) - break; - - result = selection->Collapse(cursTextNode, offset); - if (NS_FAILED(result)) - break; - } + result = PositionScreenCursor(cursorRow, cursorCol); } else { // Process line data @@ -875,7 +879,7 @@ NS_IMETHODIMP mozXMLTermSession::ReadAll(mozILineTermAux* lineTermAux, // Display meta command if (mEntryHasOutput) { // Break previous output display - result = BreakOutput(); + result = BreakOutput(PR_FALSE); // Create new entry block result = NewEntry(promptStr); @@ -1008,7 +1012,7 @@ NS_IMETHODIMP mozXMLTermSession::ReadAll(mozILineTermAux* lineTermAux, break; // Break metacommand output display - result = BreakOutput(); + result = BreakOutput(PR_FALSE); } // Reset newline flag @@ -1024,7 +1028,7 @@ NS_IMETHODIMP mozXMLTermSession::ReadAll(mozILineTermAux* lineTermAux, // Prompt line if (mEntryHasOutput) { // Break previous output display - result = BreakOutput(); + result = BreakOutput(PR_FALSE); // Create new entry block result = NewEntry(promptStr); @@ -1110,10 +1114,11 @@ NS_IMETHODIMP mozXMLTermSession::ReadAll(mozILineTermAux* lineTermAux, // Flush output, splitting off incomplete line result = FlushOutput(SPLIT_INCOMPLETE_FLUSH); - // printf("mozXMLTermSession::ReadAll (flush)\n"); + if (mEntryHasOutput) + PositionOutputCursor(lineTermAux); + result = mPresShell->ScrollSelectionIntoView(SELECTION_NORMAL, SELECTION_FOCUS_REGION); - } // Scroll frame (ignore result) @@ -1290,13 +1295,16 @@ NS_IMETHODIMP mozXMLTermSession::InitStream(const nsString& streamURL, streamMarkupType)); // Break previous output display - result = BreakOutput(); + result = BreakOutput(PR_FALSE); if (NS_FAILED(result)) return result; - if ((streamMarkupType == TEXT_FRAGMENT) || - (streamMarkupType == JS_FRAGMENT) || - (streamMarkupType == HTML_FRAGMENT)) { + if ((streamMarkupType == TEXT_FRAGMENT) || + (streamMarkupType == JS_FRAGMENT) || + (streamMarkupType == HTML_FRAGMENT) || + (streamMarkupType == INSECURE_FRAGMENT) || + (streamMarkupType == OVERFLOW_FRAGMENT) || + (streamMarkupType == INCOMPLETE_FRAGMENT)) { // Initialize fragment buffer mFragmentBuffer = ""; @@ -1379,18 +1387,22 @@ NS_IMETHODIMP mozXMLTermSession::InitStream(const nsString& streamURL, /** Breaks output display by flushing and deleting incomplete lines */ -NS_IMETHODIMP mozXMLTermSession::BreakOutput(void) +NS_IMETHODIMP mozXMLTermSession::BreakOutput(PRBool positionCursorBelow) { nsresult result; - XMLT_LOG(mozXMLTermSession::BreakOutput,70,("mOutputMarkupType=%d\n", - mOutputMarkupType)); + XMLT_LOG(mozXMLTermSession::BreakOutput,70, + ("positionCursorBelow=%x, mOutputMarkupType=%d\n", + positionCursorBelow, mOutputMarkupType)); if (!mEntryHasOutput) return NS_OK; switch (mOutputMarkupType) { + case INSECURE_FRAGMENT: + case OVERFLOW_FRAGMENT: + case INCOMPLETE_FRAGMENT: case TEXT_FRAGMENT: { // Display text fragment using new SPAN node @@ -1408,6 +1420,20 @@ NS_IMETHODIMP mozXMLTermSession::BreakOutput(void) result = mOutputBlockNode->AppendChild(spanNode, getter_AddRefs(resultNode)); + // Handle stream output error messages + switch (mOutputMarkupType) { + case INSECURE_FRAGMENT: + mFragmentBuffer = "XMLTerm: *Error* Insecure stream data; is LTERM_COOKIE set?"; + break; + + case INCOMPLETE_FRAGMENT: + mFragmentBuffer = "XMLTerm: *Error* Incomplete stream data"; + break; + + default: + break; + } + // Display text result = SetDOMText(textNode, mFragmentBuffer); if (NS_FAILED(result)) @@ -1467,6 +1493,7 @@ NS_IMETHODIMP mozXMLTermSession::BreakOutput(void) if (NS_FAILED(result)) return result; + mPreTextBufferLines = 0; mPreTextBuffered = ""; mPreTextDisplayed = ""; mOutputDisplayNode = nsnull; @@ -1478,6 +1505,10 @@ NS_IMETHODIMP mozXMLTermSession::BreakOutput(void) // Revert to plain text type mOutputMarkupType = PLAIN_TEXT; + if (positionCursorBelow) { + PositionOutputCursor(nsnull); + } + return NS_OK; } @@ -1512,14 +1543,32 @@ NS_IMETHODIMP mozXMLTermSession::ProcessOutput(const nsString& aString, switch (mOutputMarkupType) { + case INSECURE_FRAGMENT: + case OVERFLOW_FRAGMENT: + case INCOMPLETE_FRAGMENT: + // Do nothing + break; + case TEXT_FRAGMENT: case JS_FRAGMENT: case HTML_FRAGMENT: // Append complete lines to fragment buffer if (newline || streamOutput) { - mFragmentBuffer += aString; - if (newline) - mFragmentBuffer += '\n'; + PRInt32 strLen = mFragmentBuffer.Length()+aString.Length(); + + if (strLen < 100000) { + mFragmentBuffer += aString; + if (newline) + mFragmentBuffer += '\n'; + + } else { + mOutputMarkupType = OVERFLOW_FRAGMENT; + mFragmentBuffer = "XMLTerm: *Error* Stream data overflow ("; + mFragmentBuffer.Append(strLen,10); + mFragmentBuffer.Append(" chars)"); + break; + + } } break; @@ -1555,10 +1604,151 @@ NS_IMETHODIMP mozXMLTermSession::ProcessOutput(const nsString& aString, } +/** Ensures the total number of output lines stays within a limit + * by deleting the oldest output line. + * @param deleteAllOld if true, delete all previous display nodes + * (excluding the current one) + */ +NS_IMETHODIMP mozXMLTermSession::LimitOutputLines(PRBool deleteAllOld) +{ + nsresult result; + nsAutoString attValue; + + XMLT_LOG(mozXMLTermSession::LimitOutputLines,70, + ("deleteAllOld=%d, mEntryOutputLines=%d\n", + deleteAllOld, mEntryOutputLines)); + + nsCOMPtr firstChild; + result = mOutputBlockNode->GetFirstChild(getter_AddRefs(firstChild)); + if (NS_FAILED(result) || !firstChild) + return NS_ERROR_FAILURE; + + result = mozXMLTermUtils::GetNodeAttribute(firstChild, "class", attValue); + if (NS_FAILED(result)) + return result; + + if (!attValue.Equals(sessionElementNames[WARNING_ELEMENT])) { + // Create warning message element + nsCOMPtr divNode, textNode; + nsAutoString tagName = "div"; + nsAutoString elementName = sessionElementNames[WARNING_ELEMENT]; + result = NewElementWithText(tagName, elementName, -1, + mOutputBlockNode, divNode, textNode, + firstChild); + if (NS_FAILED(result) || !divNode || !textNode) + return NS_ERROR_FAILURE; + + firstChild = divNode; + + nsAutoString warningMsg ="XMLTerm: *WARNING* Command output truncated to "; + warningMsg.Append(300,10); + warningMsg.Append(" lines"); + result = SetDOMText(textNode, warningMsg); + } + + PR_ASSERT(mOutputDisplayNode != firstChild); + + nsCOMPtr nextChild; + + PRInt32 decrementedLineCount = 0; + + for (;;) { + result = firstChild->GetNextSibling(getter_AddRefs(nextChild)); + PR_ASSERT(NS_SUCCEEDED(result) && nextChild); + + // Do not modify current display node + if (nextChild.get() == mOutputDisplayNode.get()) + break; + + PRInt32 deleteNode = 0; + + if (deleteAllOld) { + deleteNode = 1; + + } else { + result = mozXMLTermUtils::GetNodeAttribute(nextChild, "class", attValue); + + if (NS_FAILED(result)|| (attValue.Length() == 0)) { + deleteNode = 1; + + } else { + + if (attValue.Equals(sessionElementNames[MIXED_ELEMENT])) { + // Delete single line containing mixed style output + deleteNode = 1; + decrementedLineCount = 1; + + XMLT_LOG(mozXMLTermSession::LimitOutputLines,79, + ("deleted mixed line\n")); + + } else if ( (attValue.Equals(sessionElementNames[STDIN_ELEMENT])) || + (attValue.Equals(sessionElementNames[STDOUT_ELEMENT])) || + (attValue.Equals(sessionElementNames[STDERR_ELEMENT]))) { + // Delete first line from STDIN/STDOUT/STDERR PRE output + + nsCOMPtr textNode; + result = nextChild->GetFirstChild(getter_AddRefs(textNode)); + PR_ASSERT( NS_SUCCEEDED(result) && textNode); + + nsCOMPtr domText (do_QueryInterface(textNode)); + PR_ASSERT(domText); + + // Delete first line from text + nsAutoString text; + domText->GetData(text); + + PRInt32 offset = text.FindChar((PRUnichar) U_LINEFEED); + + if (offset < 0) { + deleteNode = 1; + } else { + text.Cut(0,offset+1); + domText->SetData(text); + } + decrementedLineCount = 1; + + XMLT_LOG(mozXMLTermSession::LimitOutputLines,79, + ("deleted PRE line\n")); + + } else { + // Unknown type of DOM element, delete + deleteNode = 1; + } + } + } + + if (deleteNode) { + // Delete next child node + nsCOMPtr resultNode; + result = mOutputBlockNode->RemoveChild(nextChild, + getter_AddRefs(resultNode)); + if (NS_FAILED(result)) + return result; + } + + if (decrementedLineCount || !deleteNode) + break; + } + + if (deleteAllOld) { + mEntryOutputLines = 0; + return NS_OK; + + } else if (decrementedLineCount) { + mEntryOutputLines--; + return NS_OK; + + } else { + return NS_ERROR_FAILURE; + } +} + + /** Appends text string to output buffer * (appended text may need to be flushed for it to be actually displayed) - * @param aString string to be processed + * @param aString string to be processed (may be null string, for dummy line) * @param aStyle style values for string (see lineterm.h) + * (may be a single Unichar, for uniform style) * (if it is a null string, STDOUT style is assumed) * @param newline true if this is a complete line of output */ @@ -1572,21 +1762,21 @@ NS_IMETHODIMP mozXMLTermSession::AppendOutput(const nsString& aString, const PRInt32 styleLength = aStyle.Length(); const PRUnichar *strStyle = aStyle.GetUnicode(); - XMLT_LOG(mozXMLTermSession::AppendOutput,70,("\n")); + XMLT_LOG(mozXMLTermSession::AppendOutput,70,("strLength=%d\n", strLength)); // Check if line has uniform style - PRUnichar allStyles = LTERM_STDOUT_STYLE; PRUnichar uniformStyle = LTERM_STDOUT_STYLE; + PRInt32 styleChanges = 0; if (styleLength > 0) { PRInt32 j; - allStyles = strStyle[0]; uniformStyle = strStyle[0]; - for (j=1; j 0) { + if (mPreTextBufferLines > 0) { mPreTextBuffered += '\n'; } + mPreTextBufferLines++; mPreTextBuffered += mPreTextIncomplete; mPreTextIncomplete = ""; - } - mLineBreakNeeded = false; + if (mPreTextBufferLines > 300) { + // Delete all earlier PRE/mixed blocks and first line of current block + + result = LimitOutputLines(true); + if (NS_FAILED(result)) + return result; + + // Delete first line from PRE text buffer + PRInt32 offset = mPreTextBuffered.FindChar((PRUnichar) U_LINEFEED); + if (offset < 0) { + mPreTextBuffered = ""; + } else { + mPreTextBuffered.Cut(0,offset+1); + } + + mPreTextBufferLines--; + + } else if (mEntryOutputLines+mPreTextBufferLines > 300) { + // Delete oldest PRE/mixed line so as to stay within the limit + + result = LimitOutputLines(false); + if (NS_FAILED(result)) + return result; + } + } XMLT_LOG(mozXMLTermSession::AppendOutput,72, - ("mPreTextDisplayed.Length()=%d, mPreTextBuffered.Length()=%d\n", - mPreTextDisplayed.Length(), mPreTextBuffered.Length())); + ("mPreTextDisplayed.Length()=%d, mPreTextBufferLines()=%d\n", + mPreTextDisplayed.Length(), mPreTextBufferLines)); } else { - // Create uniform style SPAN display node - OutputDisplayType spanDisplayType; - nsAutoString elementName = ""; + // Create uniform style DIV display node - if (uniformStyle == LTERM_STDERR_STYLE) { - // STDERR style - spanDisplayType = SPAN_STDERR_NODE; - elementName = sessionElementNames[STDERR_ELEMENT]; - XMLT_LOG(mozXMLTermSession::AppendOutput,72,("SPAN_STDERR_NODE\n")); + XMLT_LOG(mozXMLTermSession::AppendOutput,72,("DIV_MIXED_NODE\n")); - } else { - // STDOUT style (the default output style) - spanDisplayType = SPAN_STDOUT_NODE; - elementName = sessionElementNames[STDOUT_ELEMENT]; - XMLT_LOG(mozXMLTermSession::AppendOutput,72,("SPAN_STDOUT_NODE\n")); - } - - PRBool preDisplay = (mOutputDisplayType == PRE_STDOUT_NODE) || - (mOutputDisplayType == PRE_STDERR_NODE); - - if (preDisplay) { - // Flush buffer, clearing incomplete line - result = FlushOutput(CLEAR_INCOMPLETE_FLUSH); - } - - if (mLineBreakNeeded) { - // Insert line break element - result = NewBreak(mOutputBlockNode); - mLineBreakNeeded = false; - } - - if (elementName.Length() > 0) { - // Create new SPAN node - nsCOMPtr spanNode, textNode; - nsAutoString tagName = "span"; - result = NewElementWithText(tagName, elementName, -1, - mOutputBlockNode, spanNode, textNode); - - if (NS_FAILED(result) || !spanNode || !textNode) - return NS_ERROR_FAILURE; - - XMLT_LOG(mozXMLTermSession::AppendOutput,72, - ("Creating new SPAN node\n")); - - if (mOutputDisplayNode != nsnull) { - // Replace node - nsCOMPtr resultNode; - result = mOutputBlockNode->ReplaceChild(spanNode, mOutputDisplayNode, - getter_AddRefs(resultNode)); - } else { - // Append node - nsCOMPtr resultNode; - result = mOutputBlockNode->AppendChild(spanNode, - getter_AddRefs(resultNode)); - } - - mOutputDisplayType = spanDisplayType; - mOutputDisplayNode = spanNode; - mOutputTextNode = textNode; - } - - // Display line - result = SetDOMText(mOutputTextNode, aString); + // Flush buffer, clearing incomplete line + result = FlushOutput(CLEAR_INCOMPLETE_FLUSH); if (NS_FAILED(result)) + return result; + + // Create new DIV node + nsAutoString elementName = sessionElementNames[MIXED_ELEMENT]; + nsCOMPtr divNode; + nsAutoString tagName = "div"; + result = NewElement(tagName, elementName, -1, + mOutputBlockNode, divNode); + + if (NS_FAILED(result) || !divNode) return NS_ERROR_FAILURE; + // Append node + nsCOMPtr resultNode; + result = mOutputBlockNode->AppendChild(divNode, + getter_AddRefs(resultNode)); + if (NS_FAILED(result)) + return result; + + nsCOMPtr spanNode, textNode; + nsAutoString subString; + PRInt32 k; + PRInt32 passwordPrompt = 0; + PRUnichar currentStyle = LTERM_STDOUT_STYLE; + if (styleLength > 0) + currentStyle = strStyle[0]; + + mOutputTextOffset = 0; + tagName = "span"; + + PR_ASSERT(strLength > 0); + + for (k=1; k 300) { + // Delete oldest PRE/mixed line so as to stay within the limit + result = LimitOutputLines(false); + if (NS_FAILED(result)) + return result; + } + + if (passwordPrompt) { + result = mOutputBlockNode->RemoveChild(mOutputDisplayNode, + getter_AddRefs(resultNode)); + } mOutputDisplayType = NO_NODE; mOutputDisplayNode = nsnull; mOutputTextNode = nsnull; - mLineBreakNeeded = true; } } @@ -1874,11 +2130,11 @@ NS_IMETHODIMP mozXMLTermSession::AppendLineLS(const nsString& aString, for (j=0; j= 0, all '#' characters in aString - * are substituted by entryNumber) + * (if entryNumber >= 0, all '#' characters in + * id/onclick/ondblclick attribute values are substituted + * with entryNumber) * @param beforeNode child node before which to insert fragment; * if null, insert after last child node * (default value is null) @@ -2019,6 +2276,15 @@ NS_IMETHODIMP mozXMLTermSession::AppendLineLS(const nsString& aString, if (!docfragNode) return NS_ERROR_FAILURE; + // Sanitize all nodes in document fragment (deep) + result = DeepSanitizeFragment(docfragNode, nsnull, entryNumber); + if (NS_FAILED(result)) + return NS_ERROR_FAILURE; + + // If fragment was deleted during the sanitization process, simply return + if (!docfragNode) + return NS_OK; + // Insert child nodes of document fragment before PRE text node nsCOMPtr childNode; result = docfragNode->GetFirstChild(getter_AddRefs(childNode)); @@ -2068,7 +2334,7 @@ NS_IMETHODIMP mozXMLTermSession::AppendLineLS(const nsString& aString, return result; // Refresh attributes of inserted child node (deep) - DeepRefreshAttributes(resultNode, entryNumber); + DeepRefreshEventHandlers(resultNode); childNode = nextChild; } @@ -2078,58 +2344,268 @@ NS_IMETHODIMP mozXMLTermSession::AppendLineLS(const nsString& aString, } -/** Deep refresh of selected attributes for DOM elements - * (WORKAROUND for inserting HTML fragments properly) - * @param domNode DOM node of branch to be refreshed - * @param entryNumber entry number (default value = -1) - * (if entryNumber >= 0, all '#' characters in event - * handler scripts are substituted by entryNumber) +/** Substitute all occurrences of the '#' character in aString with + * aNumber, if aNumber >= 0; + * @ param aString string to be modified + * @ param aNumber number to substituted */ -NS_IMETHODIMP mozXMLTermSession::DeepRefreshAttributes( - nsCOMPtr& domNode, - PRInt32 entryNumber) +void mozXMLTermSession::SubstituteCommandNumber(nsString& aString, + PRInt32 aNumber) { - static const PRInt32 REFRESH_ATTRIBUTE_NAMES = 3; - static const char* const refreshAttributeNames[] = { - "id", - "onclick", - "ondblclick" - }; - nsresult result; + if (aNumber < 0) + return; + + PRInt32 numberOffset; nsAutoString numberString = ""; - if (entryNumber >= 0) - numberString.Append(entryNumber,10); + numberString.Append(aNumber,10); + + for (;;) { + // Search for '#' character + numberOffset = aString.FindChar((PRUnichar) '#'); + + if (numberOffset < 0) + break; + + // Substitute '#' with supplied number + aString.Cut(numberOffset,1); + aString.Insert(numberString, numberOffset); + } +} + + +/** Sanitize event handler attribute values by imposing syntax checks. + * @param aAttrValue attribute value to be sanitized + * @param aEventName name of event being handled ("click", "dblclick", ...) + */ +void mozXMLTermSession::SanitizeAttribute(nsString& aAttrValue, + const char* aEventName) +{ + // ****************NOTE*************** + // At the moment this method simply prevents the word function and the + // the character '{' both occurring in the event handler attribute. + // NEEDS TO BE IMPROVED TO ENFORCE STRICTER REQUIREMENTS + // such as: the event handler attribute should always be of the form + // "return EventHandler(str_arg1, num_arg2, str_arg3, str_arg4);" + + if ((aAttrValue.FindChar((PRUnichar)'{') >= 0) && + (aAttrValue.Find("function") >= 0)) { + // Character '{' and string "function" both found in attribute value; + // set to null string + + char* temCString = aAttrValue.ToNewCString(); + XMLT_WARNING("mozXMLTermSession::SanitizeAttribute: Warning - deleted attribute on%s='%s'\n", aEventName, temCString); + nsCRT::free(temCString); + + aAttrValue = ""; + } + + return; +} + + +/** Deep sanitizing of event handler attributes ("on*") prior to insertion + * of HTML fragments, to enfore consistent UI behaviour in XMLTerm and + * for security. The following actions are carried out: + * 1. Any SCRIPT tags in the fragment are simply deleted + * 2. All event handler attributes, except a few selected ones, are deleted. + * 3. The retained event handler attribute values are subject to strict + * checks. + * 4. If entryNumber >= 0, all '#' characters in the ID attribute and + * retained event handler attributes are substituted with entryNumber. + * + * @param domNode DOM node for HTML fragment to be sanitized + * @param parentNode parent DOM node (needed to delete SCRIPT elements; + * set to null if root element) + * @param entryNumber entry number (default value = -1) + */ +NS_IMETHODIMP mozXMLTermSession::DeepSanitizeFragment( + nsCOMPtr& domNode, + nsIDOMNode* parentNode, + PRInt32 entryNumber) +{ + nsresult result; + PRInt32 j; + + XMLT_LOG(mozXMLTermSession::DeepSanitizeFragment,72,("entryNumber=%d\n", + entryNumber)); + + nsCOMPtr domElement = do_QueryInterface(domNode); + + if (domElement) { + // Check if this is a script element (IGNORE CASE) + nsAutoString tagName = ""; + result = domElement->GetTagName(tagName); + + if (NS_SUCCEEDED(result) && tagName.EqualsIgnoreCase("script")) { + // Remove script element and return + + XMLT_WARNING("mozXMLTermSession::DeepSanitizeFragment: Warning - rejected SCRIPT element in inserted HTML fragment\n"); + + if (parentNode) { + nsCOMPtr resultNode; + result = parentNode->RemoveChild(domNode, getter_AddRefs(resultNode)); + if (NS_FAILED(result)) + return result; + + } else { + domNode = nsnull; + } + + return NS_OK; + } + + nsAutoString eventAttrVals[SESSION_EVENT_TYPES]; + for (j=0; jGetAttribute(attName, attValue); + if (NS_SUCCEEDED(result) && (attValue.Length() > 0)) { + // Save allowed event attribute value for re-insertion + eventAttrVals[j] = attValue; + } + } + + nsCOMPtr namedNodeMap(nsnull); + result = domNode->GetAttributes(getter_AddRefs(namedNodeMap)); + + if (NS_SUCCEEDED(result) && namedNodeMap) { + // Cycle through all attributes and delete all event attributes ("on*") + PRUint32 nodeCount; + result = namedNodeMap->GetLength(&nodeCount); + + if (NS_SUCCEEDED(result)) { + nsCOMPtr attrNode; + PRUint32 k; + nsAutoString attrName, attrValue, prefix; + nsAutoString nullStr = ""; + + for (k=0; kItem(k, getter_AddRefs(attrNode)); + + if (NS_SUCCEEDED(result)) { + nsCOMPtr attr = do_QueryInterface(attrNode); + + if (attr) { + result = attr->GetName(attrName); + + if (NS_SUCCEEDED(result)) { + result = attr->GetValue(attrValue); + if (NS_SUCCEEDED(result) && (attrName.Length() >= 2)) { + + attrName.Left(prefix,2); + + if (prefix.EqualsIgnoreCase("on")) { + // Delete event handler attribute + + XMLT_LOG(mozXMLTermSession::DeepSanitizeFragment,79, + ("Deleting event handler in fragment\n")); + + result = domElement->SetAttribute(attrName, nullStr); + if (NS_FAILED(result)) + return result; + } + } + + } + } + + } + } + + } + } + + if (entryNumber >= 0) { + // Process ID attribute + attName = "id"; + + result = domElement->GetAttribute(attName, attValue); + + if (NS_SUCCEEDED(result) && (attValue.Length() > 0)) { + // Modify attribute value + SubstituteCommandNumber(attValue, entryNumber); + domElement->SetAttribute(attName, attValue); + } + } + + for (j=0; j 0) { + SubstituteCommandNumber(attValue, entryNumber); + + // Sanitize attribute value + SanitizeAttribute(attValue, sessionEventNames[j]); + + // Insert attribute value + domElement->SetAttribute(attName, attValue); + } + } + + } + + // Iterate over all child nodes for deep refresh + nsCOMPtr child; + result = domNode->GetFirstChild(getter_AddRefs(child)); + if (NS_FAILED(result)) + return NS_OK; + + while (child) { + DeepSanitizeFragment(child, domNode, entryNumber); + + nsCOMPtr temp = child; + result = temp->GetNextSibling(getter_AddRefs(child)); + if (NS_FAILED(result)) + break; + } + + return NS_OK; +} + + +/** Deep refresh of selected event handler attributes for DOM elements + * (WORKAROUND for inserting HTML fragments properly) + * @param domNode DOM node of branch to be refreshed + */ +NS_IMETHODIMP mozXMLTermSession::DeepRefreshEventHandlers( + nsCOMPtr& domNode) +{ + nsresult result; + + XMLT_LOG(mozXMLTermSession::DeepRefreshEventHandlers,82,("\n")); nsCOMPtr domElement = do_QueryInterface(domNode); if (!domElement) return NS_OK; int j; - for (j=0; jGetAttribute(attName, attValue); + if (NS_SUCCEEDED(result) && (attValue.Length() > 0)) { - - if (entryNumber >= 0) { - // Search for number character - PRInt32 numberOffset = attValue.FindChar((PRUnichar) '#'); - - if (numberOffset >= 0) { - // Substitute number sign with supplied number - attValue.Cut(numberOffset,1); - attValue.Insert(numberString, numberOffset); - } - } - // Refresh attribute value domElement->SetAttribute(attName, attValue); - - XMLT_LOG(mozXMLTermSession::DeepRefreshEventAttributes,82, - ("Refreshing on%s attribute\n",sessionEventNames[j] )); } } @@ -2140,7 +2616,7 @@ NS_IMETHODIMP mozXMLTermSession::DeepRefreshAttributes( return NS_OK; while (child) { - DeepRefreshAttributes(child, entryNumber); + DeepRefreshEventHandlers(child); nsCOMPtr temp = child; result = temp->GetNextSibling(getter_AddRefs(child)); @@ -2168,7 +2644,8 @@ NS_IMETHODIMP mozXMLTermSession::FlushOutput(FlushActionType flushAction) flushAction, mOutputDisplayType)); PRBool preDisplay = (mOutputDisplayType == PRE_STDOUT_NODE) || - (mOutputDisplayType == PRE_STDERR_NODE); + (mOutputDisplayType == PRE_STDERR_NODE) || + (mOutputDisplayType == PRE_STDIN_NODE); if (preDisplay) { // PRE text display @@ -2178,6 +2655,10 @@ NS_IMETHODIMP mozXMLTermSession::FlushOutput(FlushActionType flushAction) if (flushAction != DISPLAY_INCOMPLETE_FLUSH) { // Split/clear/close incomplete line + XMLT_LOG(mozXMLTermSession::FlushOutput,72, + ("mPreTextIncomplete.Length()=%d\n", + mPreTextIncomplete.Length() )); + if (flushAction == SPLIT_INCOMPLETE_FLUSH) { // Move incomplete text to new PRE element preTextSplit = mPreTextIncomplete; @@ -2190,8 +2671,8 @@ NS_IMETHODIMP mozXMLTermSession::FlushOutput(FlushActionType flushAction) // Clear incomplete PRE text mPreTextIncomplete = ""; - if (mPreTextBuffered.Length() == 0) { - // Remove last text node + if ((mPreTextBufferLines == 0) && (mPreTextBuffered.Length() == 0)) { + // Remove lone text node nsCOMPtr resultNode; result = mOutputDisplayNode->RemoveChild(mOutputTextNode, getter_AddRefs(resultNode)); @@ -2218,6 +2699,9 @@ NS_IMETHODIMP mozXMLTermSession::FlushOutput(FlushActionType flushAction) nsAutoString outString = mPreTextBuffered; outString += mPreTextIncomplete; + // Increment total output line count for entry + mEntryOutputLines += mPreTextBufferLines; + if (outString != mPreTextDisplayed) { // Display updated buffer mPreTextDisplayed = outString; @@ -2228,29 +2712,36 @@ NS_IMETHODIMP mozXMLTermSession::FlushOutput(FlushActionType flushAction) result = SetDOMText(mOutputTextNode, mPreTextDisplayed); if (NS_FAILED(result)) return NS_ERROR_FAILURE; + } + } - if (flushAction != DISPLAY_INCOMPLETE_FLUSH) { - // Split/clear/close incomplete line - mOutputDisplayNode = nsnull; - mOutputDisplayType = NO_NODE; - mOutputTextNode = nsnull; + if (flushAction != DISPLAY_INCOMPLETE_FLUSH) { + // Split/clear/close incomplete line + mOutputDisplayNode = nsnull; + mOutputDisplayType = NO_NODE; + mOutputTextNode = nsnull; - if ( (flushAction == SPLIT_INCOMPLETE_FLUSH) && - (preTextSplit.Length() > 0) ) { - // Create new PRE element with incomplete text - nsAutoString styleStr = ""; + if ( (flushAction == SPLIT_INCOMPLETE_FLUSH) && + (preTextSplit.Length() > 0) ) { + // Create new PRE element with incomplete text + nsAutoString styleStr = ""; - if (preDisplayType == PRE_STDERR_NODE) { - styleStr += (PRUnichar) LTERM_STDERR_STYLE; - } else { - styleStr += (PRUnichar) LTERM_STDOUT_STYLE; - } + if (preDisplayType == PRE_STDIN_NODE) { + styleStr += (PRUnichar) LTERM_STDIN_STYLE; - XMLT_LOG(mozXMLTermSession::FlushOutput,72,("splitting\n")); + } else if (preDisplayType == PRE_STDERR_NODE) { + styleStr += (PRUnichar) LTERM_STDERR_STYLE; - AppendOutput(preTextSplit, styleStr, false); + } else { + styleStr += (PRUnichar) LTERM_STDOUT_STYLE; } + + XMLT_LOG(mozXMLTermSession::FlushOutput,72,("splitting\n")); + + AppendOutput(preTextSplit, styleStr, false); + + FlushOutput(DISPLAY_INCOMPLETE_FLUSH); } } @@ -2269,6 +2760,7 @@ NS_IMETHODIMP mozXMLTermSession::FlushOutput(FlushActionType flushAction) mOutputDisplayNode = nsnull; mOutputDisplayType = NO_NODE; mOutputTextNode = nsnull; + } } @@ -2278,6 +2770,55 @@ NS_IMETHODIMP mozXMLTermSession::FlushOutput(FlushActionType flushAction) } +/** Positions cursor below the last output element */ +void mozXMLTermSession::PositionOutputCursor(mozILineTermAux* lineTermAux) +{ + nsresult result; + + XMLT_LOG(mozXMLTermSession::PositionOutputCursor,80,("\n")); + + if (!mOutputTextNode) { + // Append dummy output line + nsCOMPtr spanNode, textNode; + nsAutoString tagName = "span"; + nsAutoString elementName = sessionElementNames[STDOUT_ELEMENT]; + result = NewElementWithText(tagName, elementName, -1, + mOutputBlockNode, spanNode, textNode); + + if (NS_FAILED(result) || !spanNode || !textNode) + return; + + mOutputDisplayType = SPAN_DUMMY_NODE; + mOutputDisplayNode = spanNode; + mOutputTextNode = textNode; + mOutputTextOffset = 0; + } + + // Get selection + nsCOMPtr selection; + + result = mPresShell->GetSelection(SELECTION_NORMAL, + getter_AddRefs(selection)); + if (NS_SUCCEEDED(result) && selection) { + // Position cursor at end of line + nsCOMPtr domText( do_QueryInterface(mOutputTextNode) ); + nsAutoString text = ""; + domText->GetData(text); + + PRInt32 textOffset = text.Length(); + if (lineTermAux && (mOutputDisplayType == PRE_STDIN_NODE)) { + // Get cursor column + PRInt32 cursorCol = 0; + lineTermAux->GetCursorColumn(&cursorCol); + textOffset = cursorCol - mOutputTextOffset; + if (textOffset > text.Length()) + textOffset = text.Length(); + } + result = selection->Collapse(mOutputTextNode, textOffset); + } +} + + /** Scrolls document to align bottom and left margin with screen */ NS_IMETHODIMP mozXMLTermSession::ScrollToBottomLeft(void) { @@ -2578,6 +3119,8 @@ NS_IMETHODIMP mozXMLTermSession::NewEntry(const nsString& aPrompt) // No command output processed yet mEntryHasOutput = false; + mEntryOutputLines = 0; + return NS_OK; } @@ -2605,9 +3148,18 @@ NS_IMETHODIMP mozXMLTermSession::NewScreen(void) mScreenNode = divNode; // Create individual row elements + nsCOMPtr resultNode; PRInt32 row; for (row=0; row < mScreenRows; row++) { - NewRow(nsnull); + NewRow(nsnull, getter_AddRefs(resultNode)); + } + + // Collapse selection to bottom of screen (for scrolling) + result = PositionScreenCursor(0, 0); + + if (NS_SUCCEEDED(result)) { + result = mPresShell->ScrollSelectionIntoView(SELECTION_NORMAL, + SELECTION_FOCUS_REGION); } return NS_OK; @@ -2655,18 +3207,15 @@ NS_IMETHODIMP mozXMLTermSession::GetRow(PRInt32 aRow, nsIDOMNode** aRowNode) } -/** Returns DOM text node and offset corresponding to screen row/col position +/** Positions cursor to specified screen row/col position */ -NS_IMETHODIMP mozXMLTermSession::GetScreenText(PRInt32 aRow, PRInt32 aCol, - nsIDOMNode** aTextNode, - PRInt32 *aOffset) +NS_IMETHODIMP mozXMLTermSession::PositionScreenCursor(PRInt32 aRow, + PRInt32 aCol) { nsresult result; - XMLT_LOG(mozXMLTermSession::GetScreenText,60,("row=%d, col=%d\n",aRow,aCol)); - - if (!aTextNode || !aOffset) - return NS_ERROR_NULL_POINTER; + XMLT_LOG(mozXMLTermSession::PositionScreenCursor,60, + ("row=%d, col=%d\n",aRow,aCol)); // Get row node nsCOMPtr rowNode; @@ -2674,27 +3223,75 @@ NS_IMETHODIMP mozXMLTermSession::GetScreenText(PRInt32 aRow, PRInt32 aCol, if (NS_FAILED(result) || !rowNode) return NS_ERROR_FAILURE; - // Get text node - nsCOMPtr textNode; - result = rowNode->GetFirstChild(getter_AddRefs(textNode)); - if (NS_FAILED(result) || !textNode) - return result; + nsCOMPtr childNodes; + result = rowNode->GetChildNodes(getter_AddRefs(childNodes)); + if (NS_FAILED(result) || !childNodes) + return NS_ERROR_FAILURE; + + PRUint32 nChildren = 0; + childNodes->GetLength(&nChildren); + XMLT_LOG(mozXMLTermSession::GetScreenText,60,("children=%d\n",nChildren)); PRUint16 nodeType; - result = textNode->GetNodeType(&nodeType); - if (NS_FAILED(result)) - return result; + PRUint32 j; + PRInt32 prevCols = 0; + PRInt32 textOffset = 0; + nsCOMPtr textNode = nsnull; + nsCOMPtr childNode; + nsAutoString text = ""; - if (nodeType == nsIDOMNode::TEXT_NODE) { - /* Text node */ - *aTextNode = textNode.get(); - NS_ADDREF(*aTextNode); - *aOffset = aCol; + for (j=0; jItem(j, getter_AddRefs(childNode)); + if (NS_FAILED(result) || !childNode) + return NS_ERROR_FAILURE; - } else { - /* Not a text node */ - *aTextNode = nsnull; - *aOffset = 0; + result = childNode->GetNodeType(&nodeType); + if (NS_FAILED(result)) + return result; + + XMLT_LOG(mozXMLTermSession::GetScreenText,60, + ("j=%d, nodeType=%d\n", j, nodeType)); + if (nodeType != nsIDOMNode::TEXT_NODE) { + nsCOMPtr temNode; + result = childNode->GetFirstChild(getter_AddRefs(temNode)); + if (NS_FAILED(result)) + return result; + + childNode = temNode; + + result = childNode->GetNodeType(&nodeType); + if (NS_FAILED(result)) + return result; + PR_ASSERT(nodeType == nsIDOMNode::TEXT_NODE); + } + + nsCOMPtr domText( do_QueryInterface(childNode) ); + result = domText->GetData(text); + if (NS_FAILED(result)) + return result; + + XMLT_LOG(mozXMLTermSession::GetScreenText,60,("prevCols=%d\n",prevCols)); + + if (prevCols+text.Length() >= aCol) { + // Determine offset in current text element + textOffset = aCol - prevCols; + textNode = childNode; + } else if (j == nChildren-1) { + // Position at end of line + textOffset = text.Length(); + textNode = childNode; + } + } + + // Get selection + nsCOMPtr selection; + + result = mPresShell->GetSelection(SELECTION_NORMAL, + getter_AddRefs(selection)); + + if (NS_SUCCEEDED(result) && selection) { + // Collapse selection to cursor position + result = selection->Collapse(textNode, textOffset); } return NS_OK; @@ -2706,7 +3303,8 @@ NS_IMETHODIMP mozXMLTermSession::GetScreenText(PRInt32 aRow, PRInt32 aCol, * child of the SCREEN element before beforeRowNode, or at the * end if beforeRowNode is null. */ -NS_IMETHODIMP mozXMLTermSession::NewRow(nsIDOMNode* beforeRowNode) +NS_IMETHODIMP mozXMLTermSession::NewRow(nsIDOMNode* beforeRowNode, + nsIDOMNode** resultNode) { nsresult result; @@ -2734,16 +3332,12 @@ NS_IMETHODIMP mozXMLTermSession::NewRow(nsIDOMNode* beforeRowNode) val = "1"; preElement->SetAttribute(att, val); - nsCOMPtr resultNode; - if (beforeRowNode) { // Insert row node - result = mScreenNode->InsertBefore(preNode, beforeRowNode, - getter_AddRefs(resultNode)); + result = mScreenNode->InsertBefore(preNode, beforeRowNode, resultNode); } else { // Append row node - result = mScreenNode->AppendChild(preNode, - getter_AddRefs(resultNode)); + result = mScreenNode->AppendChild(preNode, resultNode); } return NS_OK; @@ -2761,18 +3355,145 @@ NS_IMETHODIMP mozXMLTermSession::DisplayRow(const nsString& aString, PRInt32 aRow) { nsresult result; - PRInt32 offset; - XMLT_LOG(mozXMLTermSession::DisplayRow,70,("aRow=%d\n", aRow)); + const PRInt32 strLength = aString.Length(); + const PRInt32 styleLength = aStyle.Length(); + const PRUnichar *strStyle = aStyle.GetUnicode(); - nsCOMPtr rowTextNode; - result = GetScreenText(aRow, 0, getter_AddRefs(rowTextNode), &offset); - if (NS_FAILED(result) || !rowTextNode) - return result; + XMLT_LOG(mozXMLTermSession::DisplayRow,70, + ("aRow=%d, strLength=%d, styleLength=%d\n", + aRow, strLength, styleLength)); - result = SetDOMText(rowTextNode, aString); - if (NS_FAILED(result)) - return result; + // Check if line has uniform style + PRUnichar uniformStyle = LTERM_STDOUT_STYLE; + + if (styleLength > 0) { + PRInt32 j; + + PR_ASSERT(styleLength == strLength); + + uniformStyle = strStyle[0]; + + for (j=1; j rowNode; + result = GetRow(aRow, getter_AddRefs(rowNode)); + if (NS_FAILED(result) || !rowNode) + return NS_ERROR_FAILURE; + + nsCOMPtr childNodes; + result = rowNode->GetChildNodes(getter_AddRefs(childNodes)); + if (NS_FAILED(result) || !childNodes) + return NS_ERROR_FAILURE; + + PRUint32 nChildren = 0; + childNodes->GetLength(&nChildren); + + XMLT_LOG(mozXMLTermSession::DisplayRow,79,("nChildren=%d\n", nChildren)); + + if ((nChildren == 1) && (uniformStyle == LTERM_STDOUT_STYLE)) { + // Get child node + nsCOMPtr childNode; + + result = rowNode->GetFirstChild(getter_AddRefs(childNode)); + if (NS_FAILED(result) || !childNode) + return NS_ERROR_FAILURE; + + nsCOMPtr domText( do_QueryInterface(childNode) ); + if (domText) { + // Display uniform style + result = SetDOMText(childNode, aString); + if (NS_FAILED(result)) + return result; + + return NS_OK; + } + } + + // Delete all child nodes for the row + nsCOMPtr childNode; + PRInt32 j; + for (j=nChildren-1; j>=0; j--) { + result = childNodes->Item(j, getter_AddRefs(childNode)); + if (NS_FAILED(result) || !childNode) + return NS_ERROR_FAILURE; + + nsCOMPtr resultNode; + result = rowNode->RemoveChild(childNode, getter_AddRefs(resultNode)); + if (NS_FAILED(result)) + return result; + } + + nsCOMPtr spanNode, textNode; + nsAutoString tagName = "span"; + nsAutoString elementName; + nsAutoString subString; + PRInt32 k; + PRUnichar currentStyle = LTERM_STDOUT_STYLE; + if (styleLength > 0) + currentStyle = strStyle[0]; + PRInt32 offset = 0; + offset = 0; + + PR_ASSERT(strLength > 0); + + for (k=1; k& blockNode, - nsCOMPtr& textNode) + nsCOMPtr& textNode, + nsIDOMNode* beforeNode) { nsresult result; XMLT_LOG(mozXMLTermSession::NewElementWithText,80,("\n")); // Create block element - result = NewElement(tagName, name, number, parentNode, blockNode); + result = NewElement(tagName, name, number, parentNode, blockNode, + beforeNode); if (NS_FAILED(result) || !blockNode) return NS_ERROR_FAILURE; @@ -2900,11 +3626,15 @@ NS_IMETHODIMP mozXMLTermSession::NewAnchor(const nsString& classAttribute, * (If < 0, no ID attribute is defined) * @param parentNode parent node for element * @param blockNode (output) block-level DOM node for created element + * @param beforeNode child node before which to insert new node + * if null, insert after last child node + * (default value is null) */ NS_IMETHODIMP mozXMLTermSession::NewElement(const nsString& tagName, const nsString& name, PRInt32 number, nsIDOMNode* parentNode, - nsCOMPtr& blockNode) + nsCOMPtr& blockNode, + nsIDOMNode* beforeNode) { nsresult result; @@ -2934,11 +3664,21 @@ NS_IMETHODIMP mozXMLTermSession::NewElement(const nsString& tagName, } } - // Append child to parent nsCOMPtr newBlockNode = do_QueryInterface(newElement); - result = parentNode->AppendChild(newBlockNode, getter_AddRefs(blockNode)); - if (NS_FAILED(result) || !blockNode) - return NS_ERROR_FAILURE; + + if (beforeNode) { + // Insert child + result = parentNode->InsertBefore(newBlockNode, beforeNode, + getter_AddRefs(blockNode)); + if (NS_FAILED(result) || !blockNode) + return NS_ERROR_FAILURE; + + } else { + // Append child + result = parentNode->AppendChild(newBlockNode, getter_AddRefs(blockNode)); + if (NS_FAILED(result) || !blockNode) + return NS_ERROR_FAILURE; + } return NS_OK; } @@ -3082,9 +3822,9 @@ NS_IMETHODIMP mozXMLTermSession::SetEventAttributes(const nsString& name, nsAutoString attName("on"); attName += sessionEventNames[j]; - nsAutoString attValue("return "); + nsAutoString attValue("return HandleEvent(event, '"); attValue += sessionEventNames[j]; - attValue += "XMLTerm('"; + attValue += "','"; attValue += name; attValue += "','"; attValue.Append(number,10); diff --git a/mozilla/extensions/xmlterm/base/mozXMLTermSession.h b/mozilla/extensions/xmlterm/base/mozXMLTermSession.h index 27f3515399a..2c459fc758f 100644 --- a/mozilla/extensions/xmlterm/base/mozXMLTermSession.h +++ b/mozilla/extensions/xmlterm/base/mozXMLTermSession.h @@ -118,10 +118,12 @@ protected: STDIN_ELEMENT, STDOUT_ELEMENT, STDERR_ELEMENT, + MIXED_ELEMENT, + WARNING_ELEMENT, SESSION_ELEMENT_TYPES }; - /** user-generated input event type */ + /** allowed user-generated input event type */ enum SessionEventType { CLICK_EVENT = 0, DBLCLICK_EVENT, @@ -141,9 +143,9 @@ protected: NO_NODE = 0, PRE_STDOUT_NODE, PRE_STDERR_NODE, - SPAN_STDOUT_NODE, - SPAN_STDERR_NODE, - SPAN_MIXED_NODE, + PRE_STDIN_NODE, + DIV_MIXED_NODE, + SPAN_DUMMY_NODE, OUTPUT_DISPLAY_TYPES }; @@ -155,6 +157,9 @@ protected: HTML_FRAGMENT, HTML_DOCUMENT, XML_DOCUMENT, + INSECURE_FRAGMENT, + OVERFLOW_FRAGMENT, + INCOMPLETE_FRAGMENT, OUTPUT_MARKUP_TYPES }; @@ -237,7 +242,7 @@ protected: PRBool streamIsSecure); /** Breaks output display by flushing and deleting incomplete lines */ - NS_IMETHOD BreakOutput(void); + NS_IMETHOD BreakOutput(PRBool positionCursorBelow); /** Processes output string with specified style * @param aString string to be processed @@ -251,6 +256,13 @@ protected: PRBool newline, PRBool streamOutput); + /** Ensures the total number of output lines stays within a limit + * by deleting the oldest output line. + * @param deleteAllOld if true, delete all previous display nodes + * (excluding the current one) + */ + NS_IMETHOD LimitOutputLines(PRBool deleteAllOld); + /** Appends text string to output buffer * (appended text may need to be flushed for it to be actually displayed) * @param aString string to be processed @@ -289,15 +301,45 @@ protected: nsIDOMNode* beforeNode = nsnull, PRBool replace = false); - /** Deep refresh of selected attributes for DOM elements + /** Substitute all occurrences of the '#' character in aString with + * aNumber, if aNumber >= 0; + * @ param aString string to be modified + * @ param aNumber number to substituted + */ + void SubstituteCommandNumber(nsString& aString, + PRInt32 aNumber); + + /** Sanitize event handler attribute values by imposing syntax checks. + * @param aAttrValue attribute value to be sanitized + * @param aEventName name of event being handled ("Click", "DblClick", ...) + */ + void SanitizeAttribute(nsString& aAttrValue, + const char* aEventName); + + /** Deep sanitizing of event handler attributes ("on*") prior to insertion + * of HTML fragments, to enfore consistent UI behaviour in XMLTerm and + * for security. The following actions are carried out: + * 1. Any SCRIPT tags in the fragment are simply deleted + * 2. All event handler attributes, except a few selected ones, are deleted. + * 3. The retained event handler attribute values are subject to strict + * checks. + * 4. If entryNumber >= 0, all '#' characters in the ID attribute and + * retained event handler attributes are substituted with entryNumber. + * + * @param domNode DOM node for HTML fragment to be sanitized + * @param parentNode parent DOM node (needed to delete SCRIPT elements; + * set to null if root element) + * @param entryNumber entry number (default value = -1) + */ + NS_IMETHOD DeepSanitizeFragment(nsCOMPtr& domNode, + nsIDOMNode* parentNode, + PRInt32 entryNumber); + + /** Deep refresh of selected event handler attributes for DOM elements * (WORKAROUND for inserting HTML fragments properly) * @param domNode DOM node of branch to be refreshed - * @param entryNumber entry number (default value = -1) - * (if entryNumber >= 0, all '#' characters in event - * handler scripts are substituted by entryNumber) */ - NS_IMETHOD DeepRefreshAttributes(nsCOMPtr& domNode, - PRInt32 entryNumber = -1); + NS_IMETHOD DeepRefreshEventHandlers(nsCOMPtr& domNode); /** Forces display of data in output buffer * @param flushAction type of flush action: display, split-off, clear, or @@ -305,6 +347,9 @@ protected: */ NS_IMETHOD FlushOutput(FlushActionType flushAction); + /** Positions cursor below the last output element */ + void PositionOutputCursor(mozILineTermAux* lineTermAux); + /** Scrolls document to align bottom and left margin with screen */ NS_IMETHOD ScrollToBottomLeft(void); @@ -336,18 +381,17 @@ protected: */ NS_IMETHOD GetRow(PRInt32 aRow, nsIDOMNode** aRowNode); - /** Returns DOM text node and offset corresponding to screen row/col position + /** Positions cursor to specified screen row/col position */ - NS_IMETHOD GetScreenText(PRInt32 aRow, PRInt32 aCol, - nsIDOMNode** aTextNode, - PRInt32 *aOffset); + NS_IMETHOD PositionScreenCursor(PRInt32 aRow, PRInt32 aCol); /** Create a PRE element with attributes NAME="row", CLASS="row", * containing an empty text node, and insert it as a * child of the SCREEN element before beforeRowNode, or at the * end if beforeRowNode is null. */ - NS_IMETHOD NewRow(nsIDOMNode* beforeRowNode); + NS_IMETHOD NewRow(nsIDOMNode* beforeRowNode, + nsIDOMNode** resultNode); /** Displays screen output string with specified style * @param aString string to be processed @@ -375,12 +419,16 @@ protected: * @param parentNode parent node for element * @param blockNode (output) block-level DOM node for created element * @param textNode (output) child text DOM node of element + * @param beforeNode child node before which to insert new node + * if null, insert after last child node + * (default value is null) */ NS_IMETHOD NewElementWithText(const nsString& tagName, const nsString& name, PRInt32 number, nsIDOMNode* parentNode, nsCOMPtr& blockNode, - nsCOMPtr& textNode); + nsCOMPtr& textNode, + nsIDOMNode* beforeNode = nsnull); /** Creates an empty anchor (A) element with tag name tagName with attributes * CLASS="classAttribute", and ID="classAttribute#", and appends it as a @@ -407,11 +455,15 @@ protected: * (If < 0, no ID attribute is defined) * @param parentNode parent node for element * @param blockNode (output) block-level DOM node for created element + * @param beforeNode child node before which to insert new node + * if null, insert after last child node + * (default value is null) */ NS_IMETHOD NewElement(const nsString& tagName, const nsString& name, PRInt32 number, nsIDOMNode* parentNode, - nsCOMPtr& blockNode); + nsCOMPtr& blockNode, + nsIDOMNode* beforeNode = nsnull); /** Creates a new DOM text node, and appends it as a child of the * specified parent. @@ -571,6 +623,9 @@ protected: /** current text node for command output */ nsCOMPtr mOutputTextNode; + /** line offset of current text node for command output */ + PRInt32 mOutputTextOffset; + /** current XMLTerm stream interface for stream display */ nsCOMPtr mXMLTermStream; @@ -592,13 +647,16 @@ protected: AutoDetectOption mAutoDetect; - /** flag indicating whether a line break needs to be output */ - PRBool mLineBreakNeeded; - /** flag marking the first line of output */ PRBool mFirstOutputLine; + /** total count of PRE/mixed text lines displayed for this entry */ + PRInt32 mEntryOutputLines; + + /** count of PRE complete text lines in buffer */ + PRInt32 mPreTextBufferLines; + /** buffer for incomplete line of PRE text */ nsString mPreTextIncomplete; diff --git a/mozilla/extensions/xmlterm/base/mozXMLTermUtils.cpp b/mozilla/extensions/xmlterm/base/mozXMLTermUtils.cpp index 7a1cde30c73..18e2a117373 100644 --- a/mozilla/extensions/xmlterm/base/mozXMLTermUtils.cpp +++ b/mozilla/extensions/xmlterm/base/mozXMLTermUtils.cpp @@ -38,6 +38,7 @@ #include "nsIScriptContext.h" #include "nsIScriptGlobalObject.h" #include "nsIDOMWindowCollection.h" +#include "nsIDOMElement.h" #include "nsIDocument.h" #include "mozXMLT.h" @@ -275,6 +276,32 @@ mozXMLTermUtils::ExecuteScript(nsIDOMDocument* aDOMDocument, } +/** Returns the specified attribute value associated with a DOM node, + * or a null string if the attribute is not defined, or if the DOM node + * is not an element. + * @param aDOMNode node whose attribute is to be determined + * @param aAttName attribute to be determined + * @param aAttValue output attribute value + * @return NS_OK if no errors occurred + */ +NS_EXPORT nsresult +mozXMLTermUtils::GetNodeAttribute(nsIDOMNode* aDOMNode, + const char* aAttName, + nsString& aAttValue) +{ + XMLT_LOG(mozXMLTermUtils::GetNodeAttribute,20,("aAttName=%s\n", aAttName)); + + nsCOMPtr domElement = do_QueryInterface(aDOMNode); + if (!domElement) { + aAttValue = ""; + return NS_OK; + } + + nsAutoString attName = aAttName; + return domElement->GetAttribute(attName, aAttValue); +} + + /** Returns a timestamp string containing the local time, if at least * deltaSec seconds have elapsed since the last timestamp. Otherwise, * a null string is returned. diff --git a/mozilla/extensions/xmlterm/base/mozXMLTermUtils.h b/mozilla/extensions/xmlterm/base/mozXMLTermUtils.h index d7aa8494631..aaa72ce7584 100644 --- a/mozilla/extensions/xmlterm/base/mozXMLTermUtils.h +++ b/mozilla/extensions/xmlterm/base/mozXMLTermUtils.h @@ -103,6 +103,19 @@ class mozXMLTermUtils const nsString& aScript, nsString& aOutput); + /** Returns the specified attribute value associated with a DOM node, + * or a null string if the attribute is not defined, or if the DOM node + * is not an element. + * @param aDOMNode node whose attribute is to be determined + * @param aAttName attribute to be determined + * @param aAttValue output attribute value + * @return NS_OK if no errors occurred + */ + static NS_EXPORT nsresult + GetNodeAttribute(nsIDOMNode* aDOMNode, + const char* aAttName, + nsString& aAttValue); + /** Returns a timestamp string containing the local time, if at least * deltaSec seconds have elapsed since the last timestamp. Otherwise, * a null string is returned. diff --git a/mozilla/extensions/xmlterm/scripts/xcat b/mozilla/extensions/xmlterm/scripts/xcat index a9151b87476..695baf8e5bf 100755 --- a/mozilla/extensions/xmlterm/scripts/xcat +++ b/mozilla/extensions/xmlterm/scripts/xcat @@ -23,13 +23,14 @@ my $dir = cwd(); foreach my $url (@ARGV) { # for each argument my ($protocol, $slashpair, $username, $host, $port, $pathname); + # Check if argument is a valid URL if ( $url =~ m%\b # initiator ([a-zA-Z]\w*)?: # protocol (//)? # slashpair (?:([\w.]+)@)? # username ([\w\-]+(?:\.[\w\-]+)*)? # host (?::(\d+))? # port - (/\S*?)? # pathname + (/\S*?) # pathname (?=>|\"|\'|\s|[.,!](?:\s|\Z)|\Z) # terminator (look ahead) %x ) { @@ -45,6 +46,7 @@ foreach my $url (@ARGV) { # for each argument ## print STDERR "Not an URL; assume local file $url\n"; + # Create a file URL ($protocol, $slashpair, $username, $host, $port, $pathname) = ("file", "//", "", "", "", $url); @@ -105,7 +107,7 @@ foreach my $url (@ARGV) { # for each argument (?:([\w.]+)@)? # username ([\w\-]+(?:\.[\w\-]+)*)? # host (?::(\d+))? # port - (/\S*?)? # pathname + (/\S*?) # pathname (?=>|\"|\'|\s|[.,!](?:\s|\Z)|\Z) # terminator (look ahead) %x ) { $urlvals[$nurl] = $&; @@ -120,7 +122,7 @@ foreach my $url (@ARGV) { # for each argument $urldesc = $urlstr if !$urldesc; my $clickcmd = - qq%onclick="return clickXMLTerm('textlink',-#,'$urlstr')"%; + qq%onClick="return HandleEvent(event,'click','textlink',-\#,'$urlstr')"%; print "\e{S$cookie\a"; # HTML stream escape sequence if ($nurl >= 2) { @@ -138,25 +140,28 @@ foreach my $url (@ARGV) { # for each argument print "
";
 
         while () {
-            s/&/&/g;
-            s//">"/g;
-                s%\b                              # initiator
-                 ([a-zA-Z]\w*)?:                  # protocol
-                 (//)?                            # slashpair
-                 (?:([\w.]+)@)?                   # username
-                 ([\w\-]+(?:\.[\w\-]+)*)?         # host
-                 (?::(\d+))?                      # port
-                 (/\S*?)?                         # pathname
-                 (?=>|\"|\'|\s|[.,!](?:\s|\Z)|\Z) # terminator (look ahead)
-                 %$&%xg;
-                s/">"/>/g;
+            s/&/&/g;       # Replace & with &
+            s//">"/g;      # Temporarily replace > with ">"
+                               # to allow termination of  etc.
+
+            s%\b                              # URL word boundary
+             ([a-zA-Z]\w*)?:                  # protocol
+             (//)?                            # slashpair
+             (?:([\w.]+)@)?                   # username
+             ([\w\-]+(?:\.[\w\-]+)*)?         # host
+             (?::(\d+))?                      # port
+             (/\S*?)                          # pathname
+             (?=>|\"|\'|\s|[.,!](?:\s|\Z)|\Z) # URL terminator (look ahead)
+             %$&%xg;
+
+            s/">"/>/g;   # Replace ">" with > in the end
 
             print $_;
         }
 
         print "
"; - print "\000"; # Terminate HTML stream + print "\000"; # Terminate HTML stream close INFILE; } else { # unknown file type diff --git a/mozilla/extensions/xmlterm/scripts/xls b/mozilla/extensions/xmlterm/scripts/xls index 0c8b8364981..b5d9eb44c18 100755 --- a/mozilla/extensions/xmlterm/scripts/xls +++ b/mozilla/extensions/xmlterm/scripts/xls @@ -46,7 +46,7 @@ foreach $file (glob("*")) { # for each file in current directory if ($opt_window) { $sendcmd = "createln"; } else { - $sendcmd = "sendln"; + $sendcmd = "exec"; } my ($filetype, $fileimg, $sendtxt1, $sendtxt2); @@ -74,22 +74,23 @@ foreach $file (glob("*")) { # for each file in current directory $_ = ; close INFILE; + # Extract content URL and the icon URL (if any) my @urlvals; my $nurl = 0; - while ( m%\b # initiator - (http|file|mailto): # scheme + while ( m%\b # URL word boundary + (http|file|mailto): # protocol (//)? # slashpair (?:([\w.]+)@)? # username ([\w\-]+(?:\.[\w\-]+)*)? # host (?::(\d+))? # port - (/\S*?)? # pathname - (?=>|\"|\'|\s|[.,!](?:\s|\Z)|\Z) # terminator (look ahead) + (/\S*?) # pathname + (?=>|\"|\'|\s|[.,!](?:\s|\Z)|\Z) # URL terminator (look ahead) %x ) { $urlvals[$nurl] = $&; s%$&%%; $nurl++; } - s%\A\s*(\S.*?)?\s*\Z%$1%; + s%\A\s*(\S.*?)?\s*\Z%$1%; # trim leading/trailing space if ($nurl >= 1) { my $urldesc = $_; @@ -100,9 +101,9 @@ foreach $file (glob("*")) { # for each file in current directory $filetype = "urlfile"; if ($nurl >= 2) { - $fileimg = "$urlvals[1]"; + $fileimg = "$urlvals[1]"; # use icon URL } else { - $fileimg = "$imgdir/$img{$filetype}"; + $fileimg = "$imgdir/$img{$filetype}"; #default URL icon } $sendtxt1 = "$urlstr"; $sendtxt2 = "$urlstr"; @@ -124,7 +125,7 @@ foreach $file (glob("*")) { # for each file in current directory my $tail = $comps[$#comps]; # file name my $clickcmd = - qq%onclick="return clickXMLTerm('$sendcmd',-\#,'$sendtxt1','$sendtxt2')"%; + qq%onClick="return HandleEvent(event,'click','$sendcmd',-\#,'$sendtxt1','$sendtxt2')"%; $rowimg .= ""; $rowtxt .= ""; diff --git a/mozilla/extensions/xmlterm/scripts/xls.csh b/mozilla/extensions/xmlterm/scripts/xls.csh index 1cd43bcc240..c34493f45c9 100755 --- a/mozilla/extensions/xmlterm/scripts/xls.csh +++ b/mozilla/extensions/xmlterm/scripts/xls.csh @@ -55,7 +55,7 @@ foreach file ($files) else set cmd="sendln" endif - set clickcmd="onclick="'"'"return clickXMLTerm('$cmd',-1,'$sendtxt')"'"' + set clickcmd="onClick="'"'"return ClickXMLTerm('$cmd',-1,'$sendtxt')"'"' set rowimg="${rowimg}" set rowtxt="${rowtxt}" diff --git a/mozilla/extensions/xmlterm/tests/DocStream.c b/mozilla/extensions/xmlterm/tests/DocStream.c index 8240abe2058..733623199e5 100644 --- a/mozilla/extensions/xmlterm/tests/DocStream.c +++ b/mozilla/extensions/xmlterm/tests/DocStream.c @@ -20,11 +20,11 @@ int main(void) \ Please click a button
\ \ + onClick=\"return HandleEvent(event, 'click', 'sendln','#','b')\"> \ \ + onClick=\"return HandleEvent(event, 'click', 'sendln','#','e')\"> \ \ + onClick=\"return HandleEvent(event, 'click', 'sendln','#','q')\"> \
\ "); diff --git a/mozilla/extensions/xmlterm/tests/HelloWorld.c b/mozilla/extensions/xmlterm/tests/HelloWorld.c index b03255e9b22..18ec6e3a729 100644 --- a/mozilla/extensions/xmlterm/tests/HelloWorld.c +++ b/mozilla/extensions/xmlterm/tests/HelloWorld.c @@ -18,11 +18,11 @@ int main(void) \ Please click a button
\ \ + onClick=\"return HandleEvent(event, 'click', 'sendln','#','b')\"> \ \ + onClick=\"return HandleEvent(event, 'click', 'sendln','#','e')\"> \ \ + onClick=\"return HandleEvent(event, 'click', 'sendln','#','q')\"> \
"); printf("%c", '\0'); /* Escape sequence signalling end of HTML */ diff --git a/mozilla/extensions/xmlterm/ui/content/XMLTermCommands.js b/mozilla/extensions/xmlterm/ui/content/XMLTermCommands.js index da763cda2ae..eb75775a75e 100644 --- a/mozilla/extensions/xmlterm/ui/content/XMLTermCommands.js +++ b/mozilla/extensions/xmlterm/ui/content/XMLTermCommands.js @@ -4,10 +4,10 @@ function StartupXMLTerm() { dump("StartupXMLTerm:"+window.frames[0].name+"\n"); if (window.frames.length == 2) { - window.frames[1].xmltbrowser = window.frames[0]; - xmltwin = frames[1]; + xmltwin = window.frames[1]; + xmltwin.xmltbrowser = window.frames[0]; } else { - xmltwin = frames[0]; + xmltwin = window.frames[0]; } dump("StartupXMLterm: WINDOW.ARGUMENTS="+window.arguments+"\n"); @@ -27,11 +27,10 @@ function StartupXMLTerm() { return; } - // Store the XMLTerm shell in the window + // Store the XMLTerm shell in current window and in the XMLTerm frame window.xmlterm = xmltshell; xmltwin.xmlterm = xmltshell; // Initialize XMLTerm shell in content window with argvals - window.xmlterm.Init(xmltwin, "", - window.arguments); + window.xmlterm.Init(xmltwin, "", window.arguments); } diff --git a/mozilla/extensions/xmlterm/ui/content/xmlterm.html b/mozilla/extensions/xmlterm/ui/content/xmlterm.html index 8c675ce9d6f..a12997a462b 100644 --- a/mozilla/extensions/xmlterm/ui/content/xmlterm.html +++ b/mozilla/extensions/xmlterm/ui/content/xmlterm.html @@ -8,6 +8,11 @@ + + + + + +
+

+ + +

+
+ + + diff --git a/mozilla/extensions/xmlterm/ui/content/xmlterm2.xul b/mozilla/extensions/xmlterm/ui/content/xmlterm2.xul index 2f3a3d0f8f8..271635b03c7 100644 --- a/mozilla/extensions/xmlterm/ui/content/xmlterm2.xul +++ b/mozilla/extensions/xmlterm/ui/content/xmlterm2.xul @@ -36,6 +36,6 @@ html:src="about:blank" flex="100%"/> + html:src="chrome://xmlterm/content/xmlterm2.html" flex="100%"/> diff --git a/mozilla/extensions/xmlterm/ui/skin/xmltpage.css b/mozilla/extensions/xmlterm/ui/skin/xmltpage.css index d6d2b86022c..3e92b23eb89 100644 --- a/mozilla/extensions/xmlterm/ui/skin/xmltpage.css +++ b/mozilla/extensions/xmlterm/ui/skin/xmltpage.css @@ -14,11 +14,16 @@ SPAN.prompt { color: blue } SPAN.command { color: blue } /* Screen display */ -PRE.row { margin: 0; padding-top: 0; padding-bottom: 0 } -SPAN.row { margin: 0; padding-top: 0; padding-bottom: 0 } +PRE.row { margin: 0; padding-top: 0; padding-bottom: 0 } +SPAN.row { margin: 0; padding-top: 0; padding-bottom: 0 } +SPAN.boldstyle { font-weight: bold; margin: 0; padding-top: 0; padding-bottom: 0 } +SPAN.underlinestyle { text-decoration: underline; margin: 0; padding-top: 0; padding-bottom: 0 } +SPAN.blinkstyle { font-weight: bold; margin: 0; padding-top: 0; padding-bottom: 0 } +SPAN.inversestyle { font-weight: bold; margin: 0; padding-top: 0; padding-bottom: 0 } /* Tips */ -SPAN.tips { font-family: sans-serif } +SPAN.tiphead { font-family: sans-serif; font-weight: bold } +SPAN.tipdata { font-family: sans-serif } SPAN.moretips { font-family: sans-serif; color: blue; cursor: hand; font-weight: bold; text-decoration: underline };