diff options
author | iroul <iroul@iroul-VirtualBox.(none)> | 2014-04-04 07:35:14 -0700 |
---|---|---|
committer | iroul <iroul@iroul-VirtualBox.(none)> | 2014-04-04 07:35:14 -0700 |
commit | afd34f2893a06a3aecf17e8e83b1df6ed2ae91a2 (patch) | |
tree | 851102abc55d91a1b76e63e9e89f9a7733da95b5 /src/terminal/fqterm_session.cpp | |
parent | c4b028ad53f7b362a864de24828d7cc39ff67b0a (diff) | |
download | fqterm-afd34f2893a06a3aecf17e8e83b1df6ed2ae91a2.tar.xz |
move to my github.
Diffstat (limited to 'src/terminal/fqterm_session.cpp')
-rw-r--r-- | src/terminal/fqterm_session.cpp | 1648 |
1 files changed, 1648 insertions, 0 deletions
diff --git a/src/terminal/fqterm_session.cpp b/src/terminal/fqterm_session.cpp new file mode 100644 index 0000000..6c5b513 --- /dev/null +++ b/src/terminal/fqterm_session.cpp @@ -0,0 +1,1648 @@ +/*************************************************************************** + * fqterm, a terminal emulator for both BBS and *nix. * + * Copyright (C) 2008 fqterm development group. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "fqterm.h" +#include "common.h" +#include "fqterm_trace.h" +#include "fqterm_session.h" +#include "fqterm_buffer.h" +#include "fqterm_text_line.h" +#include "fqterm_telnet.h" +#include "fqterm_decode.h" +#include "fqterm_zmodem.h" + +#ifdef HAVE_PYTHON
+#include <Python.h>
+#endif //HAVE_PYTHON + +#ifndef WIN32 +#include <unistd.h> +#else +#include <windows.h> +#endif + + +#include <QString> +#include <QTimer> +#include <QMutex> +#include <QRegExp> +#include <QtAlgorithms> +#include <QChar> +#include <QPair> +#include <QReadLocker> +#include <QWriteLocker> +#include <QReadWriteLock> + +namespace FQTerm { + +const QString FQTermSession::endOfUrl[] = { + "ac","ad","ae","af","ag","ai","al","am","an","ao","aq","ar","as","at", + "au","aw","az","ba","bb","bd","be","bf","bg","bh","bi","bj","bm","bn","bo","br", + "bs","bt","bv","bw","by","bz","ca","cc","cd","cf","cg","ch","ci","ck","cl","cm", + "cn","co","uk","com","cr","cs","cu","cv","cx","cy","cz","de","dj","dk","dm", + "do","dz","ec","edu","ee","eg","eh","er","es","et","fi","fj","fk","fm","fo", + "fr","ga","gd","ge","gf","gg","gh","gi","gl","gm","gn","gov","gp","gq","aero", + "asia","biz","coop","eu","info","museum","name","pro","travel","gr","gs","gt", + "gu","gw","gy","hk","hm","hn","hr","ht","hu","id","ie","il","im","in","int", + "io","iq","ir","is","it","je","jm","jo","jp","ke","kg","kh","ki","km","kn","kp", + "kr","kw","ky","kz","la","lb","lc","li","lk","lr","ls","lt","lu","lv","ly","ma", + "mc","md","mg","mh","mil","mk","ml","mm","mn","mo","mp","mq","mr","ms","mt", + "mu","mv","mw","mx","my","mz","na","nc","ne","net","nf","ng","ni","nl","no", + "np","nr","nt","nu","nz","om","org","pa","pe","pf","pg","ph","pk","pl","pm", + "pn","pr","ps","pt","pw","py","qa","re","ro","ru","rw","sa","sb","sc","sd","se", + "sg","sh","si","sj","sk","sl","sm","sn","so","sr","sv","st","sy","sz","tc","td", + "tf","tg","th","tj","tk","tm","tn","to","tp","tr","tt","tv","tw","tz","ua","ug", + "uk","um","us","uy","uz","va","vc","ve","vg","vi","vn","vu","wf","ws","ye","yt", + "yu","za","zm","zw" +}; + +FQTermSession::FQTermSession(FQTermConfig *config, FQTermParam param) { + reconnectRetry_ = 0; + scriptListener_ = NULL; + param_ = param; + termBuffer_ = new FQTermBuffer(param_.numColumns_, + param_.numRows_, + param_.numScrollLines_, + param_.hostType_ == 0); + + if (param.protocolType_ == 0) { + telnet_ = new FQTermTelnet(param_.virtualTermType_.toLatin1(), + param_.numRows_, param_.numColumns_, param.protocolType_, param.hostType_ ); + } else if (param.protocolType_ == 3) { + telnet_ = new FQTermTelnet(param_.virtualTermType_.toLatin1(), + param_.numRows_, param_.numColumns_, param.protocolType_, param.hostType_ ); + } else { +#if defined(_NO_SSH_COMPILED) + QMessageBox::warning(this, "sorry", + "SSH support is not compiled, " + "FQTerm can only use Telnet!"); + telnet_ = new FQTermTelnet(param_.virtualTermType_.toUtf8(), + param_.numRows_, param_.numColumns_, param.protocolType_, param.hostType_ ); +#else + telnet_ = new FQTermTelnet(param_.virtualTermType_.toUtf8(), + param_.numRows_, param_.numColumns_, param.protocolType_ , param.hostType_ , + param_.sshUserName_.toUtf8(), + param_.sshPassword_.toUtf8()); +#endif + } + + zmodem_ = new FQTermZmodem(config, telnet_, param.protocolType_, param.serverEncodingID_); + decoder_ = new FQTermDecode(termBuffer_, param.serverEncodingID_); + FQ_VERIFY(connect(decoder_, SIGNAL(enqReceived()), this, SLOT(onEnqReceived()))); + FQ_VERIFY(connect(decoder_, SIGNAL(onTitleSet(const QString&)), this, SIGNAL(onTitleSet(const QString&)))); + + isConnected_ = false; +#ifndef _NO_SSH_COMPILED + if (param.protocolType_ != 0) { + isSSHLogining_ = true; + } else { + isSSHLogining_ = false; + } +#else + isSSHLogining_ = false; +#endif + isTelnetLogining_ = false; + isIdling_ = false; + isSendingMessage_ = false; + isMouseX11_ = false; + + idleTimer_ = new QTimer; + autoReplyTimer_ = new QTimer; + + acThread_ = new ArticleCopyThread(*this, waitCondition_, bufferWriteLock_); + + FQ_VERIFY(connect(decoder_, SIGNAL(mouseMode(bool)), + this, SLOT(setMouseMode(bool)))); + FQ_VERIFY(connect(telnet_, SIGNAL(readyRead(int, int)), + this, SLOT(readReady(int, int)))); + FQ_VERIFY(connect(telnet_, SIGNAL(TelnetState(int)), + this, SLOT(changeTelnetState(int)))); + FQ_VERIFY(connect(telnet_, SIGNAL(errorMessage(QString)), + this, SIGNAL(errorMessage(QString)))); + FQ_VERIFY(connect(telnet_, SIGNAL(requestUserPwd(QString*, QString*, bool*)), + this, SIGNAL(requestUserPwd(QString*, QString*, bool*)))); + + FQ_VERIFY(connect(telnet_, SIGNAL(onSSHAuthOK()), + this, SLOT(onSSHAuthOK()))); + + + + FQ_VERIFY(connect(termBuffer_, SIGNAL(onSetTermSize(int, int)), + telnet_, SLOT(windowSizeChanged(int, int)))); + + FQ_VERIFY(connect(zmodem_, SIGNAL(ZmodemState(int, int, const char *)), + this, SIGNAL(zmodemStateChanged(int, int, const char *)))); + + FQ_VERIFY(connect(idleTimer_, SIGNAL(timeout()), this, SLOT(onIdle()))); + FQ_VERIFY(connect(autoReplyTimer_, SIGNAL(timeout()), + this, SLOT(onAutoReply()))); + + FQ_VERIFY(connect(acThread_, SIGNAL(articleCopied(int, const QString)), + this, SIGNAL(articleCopied(int, const QString)))); + + setAntiIdle(param_.isAntiIdle_); +} + +FQTermSession::~FQTermSession() { + delete idleTimer_; + delete autoReplyTimer_; + delete acThread_; + delete termBuffer_; + delete telnet_; + delete zmodem_; + delete decoder_; +} + +const QString FQTermSession::protocolPrefix[] = { + "http://", "https://", "mms://", "rstp://", "ftp://", "mailto:", "telnet://" +}; + +void FQTermSession::setScreenStart(int nStart) { + screenStartLineNumber_ = nStart; +} + +bool FQTermSession::setCursorPos(const QPoint &pt, QRect &rc) { + QRect rectOld = getMenuRect(); + + cursorPoint_ = pt; + + detectMenuRect(); + QRect rectNew = getMenuRect(); + + rc = rectOld | rectNew; + + return rectOld != rectNew; +} + +QString FQTermSession::getMessage() { + const FQTermTextLine *line; + LineColorInfo colorInfo; + QString message; + + getLineColorInfo(termBuffer_->getTextLineInTerm(0), &colorInfo); + if (!colorInfo.uniBackgroundColor) { + return message; + } + + int i = 1; + termBuffer_->getTextLineInTerm(0)->getAllPlainText(message); + + line = termBuffer_->getTextLineInTerm(i); + getLineColorInfo(line, &colorInfo); + while (colorInfo.uniBackgroundColor && colorInfo.hasBackgroundColor) { + message += "\n"; + line->getAllPlainText(message); + i++; + line = termBuffer_->getTextLineInTerm(i); + getLineColorInfo(line, &colorInfo); + } + return message; +} + + +void FQTermSession::detectPageState() { + //for smth type bbs. + pageState_ = Undefined; + if (param_.hostType_ != 0) { + return; + } + + const FQTermTextLine *line[4]; + LineColorInfo colorInfo[4]; + int lineIndex[4] = {0, 1, 2}; + lineIndex[3] = termBuffer_->getNumRows() - 1; + for (int i = 0; i < 4; ++i) { + line[i] = termBuffer_->getTextLineInTerm(lineIndex[i]); + getLineColorInfo(line[i], colorInfo + i); + } + + //TODO: Detect PageState in a clearer way. + if (!colorInfo[0].hasBackgroundColor) { + if (colorInfo[3].foregroundColorIndex.count() != 0 && + colorInfo[3].hasBackgroundColor){ + if (colorInfo[3].uniBackgroundColor) { + QString text; + line[3]->getAllPlainText(text); + if (text[0] != L'\x3010') { + pageState_ = Read; + } else { + pageState_ = Edit; + } + } else if (colorInfo[3].backgroundColorIndex.count() == 2 && + colorInfo[3].backgroundColorIndex.at(0) == 4 && + colorInfo[3].backgroundColorIndex.at(1) == 0){ + pageState_ = Read; + } + } + return; + } + + if (colorInfo[0].backgroundColorIndex.at(0) != 4 + || !(colorInfo[3].hasBackgroundColor && colorInfo[3].backgroundColorIndex.at(0) == 4)) { + if (!colorInfo[3].hasBackgroundColor && + colorInfo[0].foregroundColorIndex.count() == 4 && + colorInfo[0].foregroundColorIndex.at(1) == 4 && + colorInfo[0].foregroundColorIndex.at(2) == 7 && + colorInfo[0].foregroundColorIndex.at(3) == 4){ + pageState_ = TOP10; + } + return; + } + + if (colorInfo[1].hasBackgroundColor && colorInfo[1].uniBackgroundColor) { + pageState_ = Message; + return; + } + + if (colorInfo[0].uniBackgroundColor) { + if (!colorInfo[2].hasBackgroundColor || + colorInfo[2].backgroundColorIndex.at(0) != 4 || + colorInfo[2].backgroundColorIndex.count() > 3) { + pageState_ = Menu; + return; + } + } + + if (!colorInfo[0].uniBackgroundColor && + colorInfo[0].backgroundColorIndex.at(0) == 4 && + !colorInfo[3].uniBackgroundColor) { + //announce, elite root + pageState_ = EliteArticleList; + return; + } + + if (colorInfo[2].hasBackgroundColor && + !colorInfo[2].uniBackgroundColor && + colorInfo[2].backgroundColorIndex.at(0) == 4 && + !colorInfo[3].uniBackgroundColor) { + pageState_ = EliteArticleList; + return; + } + + if (colorInfo[0].foregroundColorIndex.indexOf(14) != -1) { + pageState_ = ArticleList; + return; + } + + if (colorInfo[2].foregroundColorIndex.indexOf(7) != -1) { + QString text; + line[2]->getAllPlainText(text); + if (text[0] == ' ') { + pageState_ = BoardList; + } else { + pageState_ = MailMenu; + } + } + +} + +FQTermSession::CursorType FQTermSession::getCursorType(const QPoint &pt) { + if (screenStartLineNumber_ != + (termBuffer_->getNumLines() - termBuffer_->getNumRows())) { + return kNormal; + } + + QRect rc = getMenuRect(); + CursorType nCursorType = kNormal; + switch (pageState_) { + case Undefined: // not recognized + if (rc.contains(pt)) { + //HAND + nCursorType = kRight; + } else { + nCursorType = kNormal; + } + break; + case Menu: + case MailMenu: + // menu + if (pt.x() < 5) { + // LEFT + nCursorType = kLeft; + } else if (rc.contains(pt)) { + // HAND + nCursorType = kRight; + } else { + nCursorType = kNormal; + } + break; + case ArticleList: + case BoardList: + case EliteArticleList: + case FriendMailList: + // list + if (pt.x() < 12) { + // LEFT + nCursorType = kLeft; + } else if (pt.y() - screenStartLineNumber_ < 3) { + // HOME + nCursorType = kHome; + } else if (pt.y() == termBuffer_->getNumLines() - 1) { + // END + nCursorType = kEnd; + } else if (pt.x() > termBuffer_->getNumColumns() - 16 && + pt.y() - screenStartLineNumber_ <= termBuffer_->getNumRows() / 2) { + //PAGEUP + nCursorType = kPageUp; + } else if (pt.x() > termBuffer_->getNumColumns() - 16 + && pt.y() - screenStartLineNumber_ > + termBuffer_->getNumRows() / 2) { + // PAGEDOWN + nCursorType = kPageDown; + } else if (rc.contains(pt)) { + // HAND + nCursorType = kRight; + } else { + nCursorType = kNormal; + } + break; + case Read: + // read + if (pt.x() < 12) { + // LEFT + nCursorType = kLeft; + } else if (pt.x() > (termBuffer_->getNumColumns() - 16) && + (pt.y() - screenStartLineNumber_) + <= termBuffer_->getNumRows() / 2) { + // PAGEUP + nCursorType = kPageUp; + } else if (pt.x() > (termBuffer_->getNumColumns() - 16) && + (pt.y() - screenStartLineNumber_) + > termBuffer_->getNumRows() / 2) { + // PAGEDOWN + nCursorType = kPageDown; + } else if (rc.contains(pt)) { + //HAND + nCursorType = kRight; + } else { + nCursorType = kNormal; + } + break; + case Edit: + // TODO: add action for kEdit state. + if (rc.contains(pt)) { + //HAND + nCursorType = kRight; + } else { + nCursorType = kNormal; + } + break; + case TOP10: + if (pt.x() < 12) { + nCursorType = kLeft; + } else if (rc.contains(pt)){ + nCursorType = kRight; + } + break; + default: + FQ_TRACE("error", 2) << "Error, wrong PageState."; + break; + } + + return nCursorType; +} + +bool FQTermSession::isSelectedMenu(int line) { + // TODO: possible performance issue + QRect rect = getMenuRect(); + + // nothing selected + if (rect.isNull()) { + return false; + } + + return line >= rect.bottom() && line <= rect.top(); +} + +bool FQTermSession::isSelectedMenu(const QPoint &pt) { + // TODO: possible performance issue + QRect rect = getMenuRect(); + + // nothing selected + if (rect.isNull()) { + return false; + } + + return rect.contains(pt); +} + +FQTermSession::PageState FQTermSession::getPageState() { + return pageState_; +} + +char FQTermSession::getMenuChar() { + return menuChar_; +} + +void FQTermSession::setMenuRect(int row, int col, int len) { + menuRect_ = QRect(col, row, len, 1); +} + +QRect FQTermSession::detectMenuRect() { + QRect rect(0, 0, 0, 0); + menuRect_ = rect; + if (scriptListener_) + { + bool res = scriptListener_->postScriptCallback(SFN_DETECT_MENU +#ifdef HAVE_PYTHON + ,Py_BuildValue("l", scriptListener_->windowID()) +#endif //HAVE_PYTHON + ); + if (res) return menuRect_; + } + // current screen scrolled + if (screenStartLineNumber_ != + (termBuffer_->getNumLines() - termBuffer_->getNumRows())) { + return rect; + } + + const FQTermTextLine *line; + int menuStartLine = 8; + switch (pageState_) { + case Undefined: break; + case MailMenu: + menuStartLine = 7; + case Menu: + if (cursorPoint_.y() - screenStartLineNumber_ >= menuStartLine && + cursorPoint_.x() > 5) { + line = termBuffer_->getTextLineInBuffer(cursorPoint_.y()); + QString cstr; + int cell_end = line->getCellEnd(qMin(cursorPoint_.x(), + (int)line->getWidth())); + line->getPlainText(0, cell_end, cstr); + + int base = cstr.lastIndexOf(" "); + if (base == -1) { + base = 0; + } + + QRegExp reg("[a-zA-Z0-9][).\\]]"); + char indexChar = cstr.indexOf(reg, base); + if (indexChar != -1) { + menuChar_ = cstr.at(indexChar).toLatin1(); + + QString strTmp = cstr.left(cstr.indexOf(reg, base)); + int nMenuStart = get_str_width((const UTF16 *)strTmp.data(), + strTmp.size()); + if (cstr[indexChar - 1] == '(' || cstr[indexChar - 1] == '[') { + nMenuStart--; + } + + cstr.clear(); + line->getAllPlainText(cstr); + + + reg = QRegExp("[^ ]"); + + int nMenuBaseLength = 20; + int cell_begin = + line->getCellBegin( + qMin(nMenuStart + nMenuBaseLength, (int)line->getWidth() - 1)); + int char_begin = line->getCharBegin(cell_begin); + //last [^ ] until char_begin + strTmp = cstr.left(cstr.lastIndexOf(reg, char_begin) + 1); + + int nMenuLength = + get_str_width((const UTF16 *)strTmp.data(), strTmp.size()) + - nMenuStart; + if (nMenuLength == nMenuBaseLength + 1) { + strTmp = cstr.left(cstr.indexOf(" ", char_begin) + 1); + nMenuLength = + get_str_width((const UTF16 *)strTmp.data(), strTmp.size()) + - nMenuStart; //base length is not enough + } + + if (cursorPoint_.x() >= nMenuStart && cursorPoint_.x() <= + nMenuStart + nMenuLength) { + rect.setX(nMenuStart); + rect.setY(cursorPoint_.y()); + rect.setWidth(nMenuLength); + rect.setHeight(1); + } + } + } + break; + case ArticleList: + case BoardList: + case FriendMailList: + case EliteArticleList: + if ((cursorPoint_.y() - screenStartLineNumber_) >= 3 + && (cursorPoint_.y() - screenStartLineNumber_) + < termBuffer_->getNumRows() -1 + && cursorPoint_.x() >= 12 + && cursorPoint_.x() <= termBuffer_->getNumColumns() - 16) { + line = termBuffer_->getTextLineInBuffer(cursorPoint_.y()); + //QString str = line->getText(); + QString str; + line->getAllPlainText(str); + + if (str.count(" ") != (int)str.length()) { + rect.setX(0); + rect.setY(cursorPoint_.y()); + rect.setWidth(line->getWidth()); + rect.setHeight(1); + } + } + break; + case Read: + + break; + case Edit: + break; + case TOP10: + { + int ln = cursorPoint_.y() - screenStartLineNumber_; + if (ln >= 3 && (ln & 1) && ln <= 21 && + cursorPoint_.x() >= 12 && + cursorPoint_.x() <= termBuffer_->getNumColumns() - 8){ + line = termBuffer_->getTextLineInBuffer(cursorPoint_.y()); + + QString str; + line->getAllPlainText(str); + + if (str.count(" ") != (int)str.length()) { + if (ln == 21){ + menuChar_ = '0'; + } else { + menuChar_ = ((ln - 1) >> 1) + '0'; + } + + rect.setX(12); + rect.setY(cursorPoint_.y()); + rect.setWidth(line->getWidth() - 20); + rect.setHeight(1); + } + } + } + break; + default: + break; + } + menuRect_ = rect; + return rect; +} + +bool FQTermSession::isIllChar(char ch) { + static char illChars[] = ";'\"[]<>^"; + return ch > '~' || ch < '!' || strchr(illChars, ch) != NULL; +} + +bool FQTermSession::isUrl(QRect &rcUrl, QRect &rcOld) { + return checkUrl(rcUrl, rcOld, false); +} + +bool FQTermSession::isIP(QRect &rcUrl, QRect &rcOld) { + return checkUrl(rcUrl, rcOld, true); +} + +QString FQTermSession::expandUrl(const QPoint& pt, QPair<int, int>& range) +{ + // int at = pt.x(); + range.first = -1; + range.second = -2; + const FQTermTextLine *textLine = termBuffer_->getTextLineInBuffer(pt.y()); + if (textLine == NULL || pt.x() > (int)textLine->getWidth()) { + return ""; + } + + QString text; + textLine->getAllPlainText(text); + + int cell_begin = textLine->getCellBegin(pt.x()); + int at = textLine->getCharBegin(cell_begin); + if (at >= text.length()) { + return ""; + } + + int start; + int end; + for (start = at; start >= 0 && !isIllChar(text.at(start).toLatin1()); + start--) { + } + start++; + for (end = at; end < text.length() && !isIllChar(text.at(end).toLatin1()); + end++) { + } + range.first = get_str_width((const UTF16 *)text.data(), start); + range.second = get_str_width((const UTF16 *)text.data(), end); + return text.mid(start, end - start); +} + + +bool FQTermSession::checkUrl(QRect &rcUrl, QRect &rcOld, bool checkIP) { + + + + QPoint pt = cursorPoint_; + int at = pt.x(); + rcOld = urlRect_; + + if (at > urlRect_.left() && at < urlRect_.right() && urlRect_.y() == pt.y()) { + if ( (checkIP && !ip_.isEmpty()) || + (!checkIP && !url_.isEmpty()) ) { + rcUrl = urlRect_; + return true; + } + + } + + QPoint urlStartPoint; + QPoint urlEndPoint; + urlStartPoint_ = QPoint(); + urlEndPoint_ = QPoint(); + urlRect_ = QRect(0, 0, -1, -1); + if (!checkIP) { + url_.clear(); + } else { + ip_.clear(); + } + + QString urlText; + //phase 1: find all consecutive legal chars + QPair<int, int> range; + urlText = expandUrl(pt, range); + if (range.first < 0 || range.first >= range.second) { + return false; + } + + + QRect urlRect = QRect(range.first, pt.y(), range.second - range.first, 1); + urlStartPoint = QPoint(range.first, pt.y()); + urlEndPoint = QPoint(range.second, pt.y()); + + if (range.second == termBuffer_->getNumColumns()) { + for (int i = pt.y() + 1; i < termBuffer_->getNumLines(); ++i) { + QString lineText = expandUrl(QPoint(0, i), range); + if (range.first == 0) { + urlText += lineText; + urlEndPoint.setY(urlEndPoint.y() + 1); + urlEndPoint.setX(range.second); + if (range.second == termBuffer_->getNumColumns()) { + continue; + } + } + break; + } + } + + //phase 2: find protocol prefix for url + //if none, prefix to add is set to "mailto:" if '@' is found + //otherwise, the prefix is "http://" by default. + QString prefixToAdd; + int protocolIndex; + for (protocolIndex = 0; protocolIndex < ProtocolSupported; ++protocolIndex) { + int begin = urlText.indexOf(protocolPrefix[protocolIndex], + Qt::CaseInsensitive); + if (begin != -1 && begin <= at) { + prefixToAdd = protocolPrefix[protocolIndex]; + urlText = urlText.mid(begin + protocolPrefix[protocolIndex].length()); + urlStartPoint.setX(urlStartPoint.x() + begin); + break; + } + } + if (protocolIndex == ProtocolSupported) { + int begin = urlText.indexOf("://"); + if (begin != -1) { + return false; + } + if (urlText.indexOf('@') != -1) { + prefixToAdd = protocolPrefix[Mailto]; + } else { + prefixToAdd = protocolPrefix[Http]; + } + } + + //no point or duplicated points + if (urlText.indexOf("..") != -1 || urlText.indexOf('.') == -1) { + return false; + } + + //phase 3: (for check ip) if there is a ':' before ip, there must be a '@' + int host_begin = qMax(urlText.lastIndexOf('@') + 1, 0); + int host_end = urlText.indexOf(':', host_begin); + if (host_end == -1) { + host_end = urlText.indexOf('/', host_begin); + } + if (host_end == -1) { + host_end = urlText.length(); + } + if (host_begin >= host_end) { + return false; + } + if (checkIP && urlText[host_end - 1] == '*') { + urlText[host_end - 1] = '1'; + } + + for (int index = 0; index < urlText.length() && urlText.at(index) != '/'; + index++) { + QChar cur(urlText.at(index)); + if (!cur.isLetterOrNumber() && !QString("-_~:@.").contains(cur)) { + return false; + } + } + + QString newIP; + newIP = urlText.mid(host_begin, host_end - host_begin); + QStringList ipv4 = newIP.split(QLatin1String(".")); + bool isIPv4 = true; + if (ipv4.count() != 4){ + isIPv4 = false; + } + foreach(QString domain, ipv4) { + bool ok; + int num = domain.toInt(&ok); + //won't tolerant spaces. + if (!ok || num < 0 || num > 255 || domain.length() > 3) { + isIPv4 = false; + break; + } + } + + if (!checkIP){ + QString lastName = ipv4.back(); + + int lastCharIndex = lastName.lastIndexOf(QRegExp("[a-zA-Z]")); + if (lastCharIndex == -1) { + if (!isIPv4) { + return false; + } else if (urlText == newIP) { + return false; + } + } else { + const QString *begin = endOfUrl; + const QString *end = endOfUrl + sizeof(endOfUrl) / sizeof(QString *); + if (qFind(begin, end, lastName) == end) { + return false; + } + } + url_ = prefixToAdd + urlText; + } else { + if (!isIPv4) { + return false; + } + ip_ = newIP; + } + + urlRect_ = urlRect; + rcUrl = urlRect; + urlStartPoint_ = urlStartPoint; + urlEndPoint_ = urlEndPoint; + return true; +} + +QString FQTermSession::getUrl() { + return url_; +} + +QString FQTermSession::getIP() { + return ip_; +} + +bool FQTermSession::isPageComplete() { + return termBuffer_->getCaretRow() == (termBuffer_->getNumRows() - 1) + && termBuffer_->getCaretColumn() == (termBuffer_->getNumColumns() - 1); +} + +bool FQTermSession::isAntiIdle() { + return param_.isAntiIdle_; +} + +void FQTermSession::setAntiIdle(bool antiIdle) { + param_.isAntiIdle_ = antiIdle; + + // disabled + if (!param_.isAntiIdle_ && idleTimer_->isActive()) { + idleTimer_->stop(); + } + + // enabled + if (param_.isAntiIdle_) { + if (idleTimer_->isActive()) { + idleTimer_->stop(); + } + idleTimer_->start(param_.maxIdleSeconds_ *1000); + } +} + +void FQTermSession::setAutoReconnect(bool autoReconnect) { + param_.isAutoReconnect_ = autoReconnect; + reconnectRetry_ = 0; + if (autoReconnect && !isConnected_) { + reconnectProcess(); + } +} + + +void FQTermSession::autoReplyMessage() { + if (autoReplyTimer_->isActive()) { + autoReplyTimer_->stop(); + } + if (pageState_ != Message) { + return; + } + if (scriptListener_) + { + bool res = scriptListener_->postScriptCallback(SFN_AUTO_REPLY +#ifdef HAVE_PYTHON + ,Py_BuildValue("l", scriptListener_->windowID()) +#endif //HAVE_PYTHON + ); + if (res) return; + } + QByteArray cstrTmp = param_.replyKeyCombination_.toLocal8Bit(); + QByteArray cstr = parseString(cstrTmp.isEmpty() ? QByteArray("^Z"): cstrTmp); + //cstr += m_param.m_strAutoReply.toLocal8Bit(); + cstr += unicode2bbs(param_.autoReplyMessage_); + cstr += '\n'; + telnet_->write(cstr, cstr.length()); + + emit messageAutoReplied(); +} + +QByteArray FQTermSession::parseString(const QByteArray &cstr, int *len) { + QByteArray parsed = ""; + + if (len != 0) { + *len = 0; + } + + for (uint i = 0; (long)i < cstr.length(); i++) { + if (cstr.at(i) == '^') { + i++; + if ((long)i < cstr.length()) { + parsed += FQTERM_CTRL(cstr.at(i)); + if (len != 0) { + *len = *len + 1; + } + } + } else if (cstr.at(i) == '\\') { + i++; + if ((long)i < cstr.length()) { + if (cstr.at(i) == 'n') { + parsed += CHAR_CR; + } else if (cstr.at(i) == 'r') { + parsed += CHAR_LF; + } else if (cstr.at(i) == 't') { + parsed += CHAR_TAB; + } + if (len != 0) { + *len = *len + 1; + } + } + } else { + parsed += cstr.at(i); + if (len != 0) { + *len = *len + 1; + } + } + } + + return parsed; +} + +void FQTermSession::reconnect() { + if (!isConnected_) { + telnet_->connectHost(param_.hostAddress_, param_.port_); + reconnectRetry_++; + } +} + +void FQTermSession::reconnectProcess() { + if (!isConnected_ && param_.isAutoReconnect_ && (reconnectRetry_ < param_.retryTimes_ || param_.retryTimes_ == -1)) { + int interval = param_.reconnectInterval_ <= 0 ? 0 : param_.reconnectInterval_ * 1000; + QTimer::singleShot(interval, this, SLOT(reconnect())); + } +} + +void FQTermSession::setMouseMode(bool on) { + isMouseX11_ = on; +} + +void FQTermSession::doAutoLogin() { + if (!param_.preLoginCommand_.isEmpty()) { + QByteArray temp = parseString(param_.preLoginCommand_.toLatin1()); + telnet_->write((const char*)(temp), temp.length()); + } + if (!param_.userName_.isEmpty()) { + QByteArray temp = param_.userName_.toLocal8Bit(); + telnet_->write((const char*)(temp), temp.length()); + char ch = CHAR_CR; + telnet_->write(&ch, 1); + } + if (!param_.password_.isEmpty()) { + QByteArray temp = param_.password_.toLocal8Bit(); + telnet_->write((const char*)(temp), temp.length()); + char ch = CHAR_CR; + telnet_->write(&ch, 1); + } + + // smth ignore continous input, so sleep 1 sec :) +#if defined(_OS_WIN32_) || defined(Q_OS_WIN32) + Sleep(1000); +#else + sleep(1); +#endif + + if (!param_.postLoginCommand_.isEmpty()) { + QByteArray temp = parseString(param_.postLoginCommand_.toLatin1()); + telnet_->write((const char*)(temp), temp.length()); + } + isTelnetLogining_ = false; +} + +//read slot +void FQTermSession::readReady(int size, int raw_size) { + FQ_ASSERT(size > 0 || raw_size > 0); // maybe raw_size is greater than 0. + + raw_data_.resize(raw_size); + telnet_->read_raw(&raw_data_[0], raw_size); + + // read raw buffer + int zmodem_consumed; + if (param_.enableZmodem_) + zmodem_->ZmodemRcv((uchar*)&raw_data_[0], raw_data_.size(), &(zmodem_->info), + zmodem_consumed); + + if (zmodem_->transferstate == notransfer) { + //decode + if (size > 0) { + int last_size = telnet_data_.size(); + telnet_data_.resize(last_size + size); + telnet_->read(&telnet_data_[0] + last_size, size); + int processed = 0; + { + while (!bufferWriteLock_.tryLockForWrite()) {} + //QWriteLocker locker(&bufferWriteLock_); + processed = decoder_->decode(&telnet_data_[0], telnet_data_.size()); + bufferWriteLock_.unlock(); + } + telnet_data_.erase(telnet_data_.begin(), telnet_data_.begin() + processed); + } + + if (isTelnetLogining_) { + int n = termBuffer_->getCaretRow(); + for (int y = n - 5; y < n + 5; y++) { + y = qMax(0, y); + const FQTermTextLine *pTextLine = termBuffer_->getTextLineInTerm(y); + if (pTextLine == NULL) { + continue; + } + + // QString str = pTextLine->getText(); + QString str; + pTextLine->getAllPlainText(str); + + if (str.indexOf("guest") != -1 /*&& str.indexOf("new") != -1*/) { + doAutoLogin(); + break; + } + } + } + // page complete when caret at the right corner + // this works for most but not for all + const FQTermTextLine *pTextLine = + termBuffer_->getTextLineInTerm(termBuffer_->getNumRows() - 1); + + //QString strText = stripWhitespace(pTextLine->getText()); + // TODO_UTF16: fixme! performance issue! + QString strText; + pTextLine->getAllPlainText(strText); + + // TODO_UTF16: shall we disable trim? + strText = strText.trimmed(); + + if (termBuffer_->getCaretRow() == termBuffer_->getNumRows() - 1 + && termBuffer_->getCaretColumn() >= (strText.length() - 1) / 2) { + waitCondition_.wakeAll(); + } + + //QToolTip::remove(this, screen_->mapToRect(m_rcUrl)); + + // message received + // 03/19/2003. the caret posion removed as a message judgement + // because smth.org changed + if (decoder_->bellReceive()) { + emit startAlert(); + emit bellReceived(); + + bool bellConsumed = false; + if (scriptListener_) { + bellConsumed = scriptListener_->postScriptCallback(SFN_ON_BELL +#ifdef HAVE_PYTHON + ,Py_BuildValue("l", scriptListener_->windowID()) +#endif //HAVE_PYTHON + ); + } + + if (isAutoReply() && !bellConsumed) { + // TODO: save messages + if (isIdling_) { + autoReplyMessage(); + } else { + autoReplyTimer_->start(param_.maxIdleSeconds_ *1000 / 2); + } + } + } + + // set page state + detectPageState(); + if (scriptListener_) { + scriptListener_->postScriptCallback(SFN_DATA_EVENT +#ifdef HAVE_PYTHON + ,Py_BuildValue("l", scriptListener_->windowID()) +#endif //HAVE_PYTHON + ); + } + emit sessionUpdated(); + } + + if (zmodem_->transferstate == transferstop) { + zmodem_->transferstate = notransfer; + } +} + +/* 0-left 1-middle 2-right 3-relsase 4/5-wheel + * + */ +//void FQTermWindow::sendMouseState( int num, +// Qt::ButtonState btnstate, Qt::ButtonState keystate, const QPoint& pt ) +void FQTermSession::sendMouseState(int num, Qt::KeyboardModifier btnstate, + Qt::KeyboardModifier keystate, const QPoint &pt) { + /* + if(!m_bMouseX11) + return; + + QPoint ptc = screen_->mapToChar(pt); + + if(btnstate&Qt::LeftButton) + num = num==0?0:num; + else if(btnstate&Qt::MidButton) + num = num==0?1:num; + else if(btnstate&Qt::RightButton) + num = num==0?2:num; + + int state = 0; + if(keystate&Qt::ShiftModifier) + state |= 0x04; + if(keystate&Qt::MetaModifier) + state |= 0x08; + if(keystate&Qt::ControlModifier) + state |= 0x10; + + // normal buttons are passed as 0x20 + button, + // mouse wheel (buttons 4,5) as 0x5c + button + if(num>3) num += 0x3c; + + char mouse[10]; + sprintf(mouse, "\033[M%c%c%c", + num+state+0x20, + ptc.x()+1+0x20, + ptc.y()+1+0x20); + telnet_->write( mouse, strlen(mouse) ); + */ +} + +void FQTermSession::cancelZmodem() { + zmodem_->zmodemCancel(); +} + +void FQTermSession::disconnect() { + telnet_->close(); + finalizeConnection(); +} + +void FQTermSession::finalizeConnection() { + if (isConnected_) { + QString strMsg = ""; + strMsg += "\n\n\n\r\n\r"; + strMsg += "\x1b[17C\x1b[0m===========================================\n\r"; + strMsg += + "\x1b[17C Connection Closed, Press \x1b[1m\x1b[31;40mEnter\x1b[m\x1b[0m To Connect\n\r"; + strMsg += "\x1b[17C===========================================\n"; + decoder_->decode(strMsg.toLatin1(), strMsg.length()); + } + isConnected_ = false; + + if (autoReplyTimer_->isActive()) { + autoReplyTimer_->stop(); + } + + if (idleTimer_->isActive()) { + idleTimer_->stop(); + } + + emit connectionClosed(); +} + +// telnet state slot +void FQTermSession::changeTelnetState(int state) { + switch (state) { + case TSRESOLVING: + break; + case TSHOSTFOUND: + break; + case TSHOSTNOTFOUND: + finalizeConnection(); + break; + case TSCONNECTING: + break; + case TSHOSTCONNECTED: + isConnected_ = true; + reconnectRetry_ = 0; + if (param_.isAutoLogin_ && param_.protocolType_==0) { + isTelnetLogining_ = true; + } + + break; + case TSPROXYCONNECTED: + break; + case TSPROXYAUTH: + break; + case TSPROXYFAIL: + disconnect(); + break; + case TSREFUSED: + finalizeConnection(); + break; + case TSREADERROR: + disconnect(); + break; + case TSCLOSED: + finalizeConnection(); + if (param_.isAutoReconnect_) { + reconnectProcess(); + } + break; + case TSCLOSEFINISH: + finalizeConnection(); + break; + case TSCONNECTVIAPROXY: + break; + case TSEGETHOSTBYNAME: + finalizeConnection(); + break; + case TSEINIWINSOCK: + finalizeConnection(); + break; + case TSERROR: + disconnect(); + break; + case TSPROXYERROR: + disconnect(); + break; + case TSWRITED: + // restart the idle timer + if (idleTimer_->isActive()) { + idleTimer_->stop(); + } + if (param_.isAntiIdle_) { + idleTimer_->start(param_.maxIdleSeconds_ *1000); + } + isIdling_ = false; + break; + default: + break; + } + + emit telnetStateChanged(state); +} + +void FQTermSession::handleInput(const QString &text) { + if (text.length() > 0) { + QByteArray cstrTmp = unicode2bbs_smart(text); + telnet_->write(cstrTmp, cstrTmp.length()); + } +} + +QString FQTermSession::bbs2unicode(const QByteArray &text) +{ + return encoding2unicode(text, param_.serverEncodingID_); +} + +QByteArray FQTermSession::unicode2bbs(const QString &text) { + return unicode2encoding(text, param_.serverEncodingID_); +} + + +QByteArray FQTermSession::unicode2bbs_smart(const QString &text) { + QByteArray strTmp; + + switch(param_.serverEncodingID_) + { + case FQTERM_ENCODING_GBK: + if (FQTermPref::getInstance()->imeEncodingID_ == FQTERM_ENCODING_BIG5) + { + strTmp = U2B(text); + char* tmp = encodingConverter_.B2G(strTmp, strTmp.length()); + strTmp = tmp; + delete []tmp; + } + else + { + strTmp = U2G(text); + } + break; + case FQTERM_ENCODING_BIG5: + if (FQTermPref::getInstance()->imeEncodingID_ == FQTERM_ENCODING_GBK) + { + strTmp = U2G(text); + char* tmp = encodingConverter_.G2B(strTmp, strTmp.length()); + strTmp = tmp; + delete []tmp; + } + else + { + strTmp = U2B(text); + } + break; + case FQTERM_ENCODING_HKSCS: + if (FQTermPref::getInstance()->imeEncodingID_ == FQTERM_ENCODING_GBK) + { + strTmp = U2G(text); + char* tmp = encodingConverter_.G2B(strTmp, strTmp.length()); + strTmp = tmp; + delete []tmp; + } + else + { + strTmp = U2H(text); + } + break; + case FQTERM_ENCODING_UTF8: + strTmp = U2U8(text); + break; + case FQTERM_ENCODING_UAO: + if (FQTermPref::getInstance()->imeEncodingID_ == FQTERM_ENCODING_GBK) + { + strTmp = U2G(text); + char* tmp = encodingConverter_.G2B(strTmp, strTmp.length()); + strTmp = tmp; + delete []tmp; + } + else + { + strTmp = U2A(text); + } + break; + } + + return strTmp; +} + + +void FQTermSession::onIdle() { + // do as autoreply when it is enabled + if (autoReplyTimer_->isActive() && param_.isAutoReply_) { + autoReplyMessage(); + stopAlert(); + return ; + } + + isIdling_ = true; + // system script can handle that + if (scriptListener_) { + bool res = scriptListener_->postScriptCallback(SFN_ANTI_IDLE +#ifdef HAVE_PYTHON + ,Py_BuildValue("l", scriptListener_->windowID()) +#endif //HAVE_PYTHON + ); + if (res) + return; + } + // the default function + int length; + QByteArray cstr = parseString(param_.antiIdleMessage_.toLocal8Bit(), &length); + telnet_->write(cstr, length); +} + +void FQTermSession::onAutoReply() { + // if AutoReply still enabled, then autoreply + if (param_.isAutoReply_) { + autoReplyMessage(); + } else { + // else just stop the timer + autoReplyTimer_->stop(); + } + + stopAlert(); +} +bool FQTermSession::isAutoReply() { + return param_.isAutoReply_; +} + +void FQTermSession::setAutoReply(bool on) { + param_.isAutoReply_ = on; + if (!param_.isAutoReply_ && autoReplyTimer_->isActive()) { + autoReplyTimer_->stop(); + } +} + +int FQTermSession::write(const char *data, int len) { + return telnet_->write(data, len); +} + +int FQTermSession::writeStr(const char *str) { + return write(str, strlen(str)); +} + +void FQTermSession::setProxy(int type, bool needAuth, + const QString &hostName, quint16 portNumber, + const QString &userName, const QString &password) { + telnet_->setProxy(type, needAuth, hostName, portNumber, userName, password); +} + +void FQTermSession::connectHost(const QString &hostName, quint16 portNumber) { + telnet_->connectHost(hostName, portNumber); +} + +void FQTermSession::close() { + telnet_->close(); + finalizeConnection(); +} + +void FQTermSession::clearLineChanged(int index) { + termBuffer_->clearLineChanged(index); +} + +void FQTermSession::setLineAllChanged(int index) { + termBuffer_->setLineAllChanged(index); +} + +void FQTermSession::setTermSize(int col, int row) { + termBuffer_->setTermSize(col, row); + param_.numColumns_ = col; + param_.numRows_ = row; +} + +FQTermBuffer *FQTermSession::getBuffer() const { + return termBuffer_; +} + +void FQTermSession::setSelect(const QPoint &pt1, const QPoint &pt2) { + termBuffer_->setSelect(pt1, pt2); +} + +void FQTermSession::clearSelect() { + termBuffer_->clearSelect(); +} + +void FQTermSession::leaveIdle() { + if (autoReplyTimer_->isActive()) { + autoReplyTimer_->stop(); + } + + if (idleTimer_->isActive()) { + idleTimer_->stop(); + } + + if (param_.isAntiIdle_) { + idleTimer_->start(param_.maxIdleSeconds_ * 1000); + } +} + +void FQTermSession::copyArticle() { + if (!acThread_->isRunning()) { + acThread_->start(); + } +} + +void FQTermSession::getLineColorInfo(const FQTermTextLine * line, + LineColorInfo * colorInfo) +{ + colorInfo->backgroundColorIndex.clear(); + colorInfo->foregroundColorIndex.clear(); + colorInfo->hasBackgroundColor = false; + colorInfo->uniBackgroundColor = true; + colorInfo->uniForegroundColor = true; + colorInfo->hasForegroundColor = false; + + if (!line || line->getWidth() == 0) { + return; + } + + const unsigned char *color = line->getColors(); + unsigned char background = GETBG(color[0]); + unsigned char foreground = GETFG(color[0]); + colorInfo->backgroundColorIndex.append(background); + colorInfo->foregroundColorIndex.append(foreground); + //for (int i = 0; i < color.length() / 2; i++) { + // TODO_UTF16: why use color.length()/2 formerly? + for (int i = 0; i < (int)line->getWidth(); i++) { + if (GETBG(color[i]) != background) { + colorInfo->uniBackgroundColor = false; + background = GETBG(color[i]); + colorInfo->backgroundColorIndex.append(background); + } + if (GETBG(color[i]) != GETBG(NO_COLOR)) { + colorInfo->hasBackgroundColor = true; + } + if (GETFG(color[i]) != foreground) { + colorInfo->uniForegroundColor = false; + foreground = GETFG(color[i]); + colorInfo->foregroundColorIndex.append(foreground); + } + if (GETFG(color[i]) != GETFG(NO_COLOR)) { + colorInfo->hasForegroundColor = true; + } + } +} + +bool FQTermSession::readyForInput() +{ + return telnet_->readyForInput(); +} + +void FQTermSession::onEnqReceived() { + if (FQTermPref::getInstance()->replyENQ_) + telnet_->write(ANSWERBACK_MESSAGE, sizeof(ANSWERBACK_MESSAGE)); +} + +void FQTermSession::onSSHAuthOK() { + isSSHLogining_ = false; + //setTermSize(80, 24); + //setTermSize(param_.numColumns_, param_.numRows_); + telnet_->windowSizeChanged(param_.numColumns_, param_.numRows_); +} + +void FQTermSession::updateSetting( const FQTermParam& p ) { + bool toggleAutoReconnect = (p.isAutoReconnect_ != param_.isAutoReconnect_); + param_ = p; + setTermSize(p.numColumns_, p.numRows_); + setAntiIdle(isAntiIdle()); + if (toggleAutoReconnect) + setAutoReconnect(param_.isAutoReconnect_); +} + +ArticleCopyThread::ArticleCopyThread( + FQTermSession &bbs, QWaitCondition &waitCondition, QReadWriteLock &bufferLock) + : session_(bbs), + waitCondition_(waitCondition), + lock_(bufferLock) { + FQ_VERIFY(connect(this, SIGNAL(writeSession(const QString&)), + &session_, SLOT(handleInput(const QString&)), + Qt::QueuedConnection)); +} + +ArticleCopyThread::~ArticleCopyThread() { +} + +static void removeTrailSpace(QString &line) { + for (int last_non_space = line.size() - 1; + last_non_space >= 0; --last_non_space) { + QChar a = line.at(last_non_space); + if (!a.isSpace()) { + line.resize(last_non_space + 1); + break; + } + + if (last_non_space == 0) { + line.resize(0); + } + } +} + + +/////////////////////////////////////// +//analyze last line when copy article +static std::pair<int, int> ParseLastLine(QString str) { + int startLine = -1; + int endLine = -1; + int infoStart = str.indexOf('(', str.indexOf('(') + 1); + int infoEnd = str.indexOf(')', infoStart); + int infoSplit = str.indexOf('-', infoStart); + if (infoStart == -1 || infoEnd == -1 || infoSplit == -1) { + return std::make_pair(-1, -1); + } + bool ok = true; + startLine = str.mid(infoStart + 1, infoSplit - infoStart - 1).toInt(&ok); + if (!ok) { + return std::make_pair(-1, -1); + } + endLine = str.mid(infoSplit + 1, infoEnd - infoSplit - 1).toInt(&ok); + if (!ok) { + return std::make_pair(-1, -1); + } + return std::make_pair(startLine, endLine); +} +/////////////////////////////////////// + + +void ArticleCopyThread::run() { + QReadLocker locker(&lock_); + + typedef std::vector<QString> Page; + const FQTermBuffer *buffer = session_.getBuffer();; + Page page; + + QString firstPageLastLine; + buffer->getTextLineInTerm(buffer->getNumRows() - 1)->getAllPlainText(firstPageLastLine); + bool MultiPage = (firstPageLastLine.indexOf("%") != -1); + if (!MultiPage) { + emit writeSession("q"); + emit writeSession("\n"); + if (!waitCondition_.wait(&lock_, 10000)) { + emit articleCopied(DAE_TIMEOUT, ""); + return; + } + buffer->getTextLineInTerm(buffer->getNumRows() - 1)->getAllPlainText(firstPageLastLine); + MultiPage = (firstPageLastLine.indexOf("%") != -1); + } + + if (MultiPage) { + //session_.write("e", 1); + emit writeSession("e"); + if (!waitCondition_.wait(&lock_, 10000)) { + emit articleCopied(DAE_TIMEOUT, ""); + return; + } + QString LastPageLastLine; + buffer->getTextLineInTerm(buffer->getNumRows() - 1)->getAllPlainText(LastPageLastLine); + std::pair<int, int> range = ParseLastLine(LastPageLastLine); + if (range.first == -1 || range.second == -1) { + return; + } + page.resize(range.second); + for (int i = range.first; i <= range.second; ++i) { + QString strTemp; + buffer->getTextLineInTerm(i - range.first)->getAllPlainText(strTemp); + page[i - 1] = strTemp; + } + //session_.write("s", 1); + emit writeSession("s"); + if (!waitCondition_.wait(&lock_, 10000)) { + emit articleCopied(DAE_TIMEOUT, ""); + return; + } + } + else { + for (int i = 0; i < buffer->getNumRows() - 1; ++i) { + QString strTemp; + buffer->getTextLineInTerm(i)->getAllPlainText(strTemp); + page.push_back(strTemp); + } + } + + while (MultiPage) { + // the end of article + int lineIndex = buffer->getNumRows() - 1; + //QByteArray lastLine = buffer->getLineInScreen(lineIndex)->getText(); + QString lastLine; + buffer->getTextLineInTerm(lineIndex)->getAllPlainText(lastLine); + + std::pair<int, int> range = ParseLastLine(lastLine); + if (range.first == -1 || range.second == -1) { + page.push_back(lastLine); + break; + } + + // copy a page of lines exclude the last line. + for (int i = range.first; i <= range.second; ++i) { + QString strTemp; + buffer->getTextLineInTerm(i - range.first)->getAllPlainText(strTemp); + page[i - 1] = strTemp; + } + + + // wait for next page. + //session_.write(" ", 1); + emit writeSession(" "); + if (!waitCondition_.wait(&lock_, 10000)) { + emit articleCopied(DAE_TIMEOUT, ""); + break; + } + } + + + + QString articleText; + + for (Page::iterator line = page.begin(); line != page.end(); ++line) { + removeTrailSpace(*line); + articleText += (*line); + articleText += (OS_NEW_LINE); + } + + //qApp->postEvent(pWin, new QCustomEvent(DAE_FINISH)); + emit articleCopied(DAE_FINISH, articleText); +} + +} // namespace FQTerm + +#include "fqterm_session.moc" |