summaryrefslogtreecommitdiff
path: root/src/terminal/fqterm_session.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/terminal/fqterm_session.cpp')
-rw-r--r--src/terminal/fqterm_session.cpp1648
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"