~ubuntu-branches/ubuntu/jaunty/fqterm/jaunty

« back to all changes in this revision

Viewing changes to src/terminal/fqterm_session.cpp

  • Committer: Bazaar Package Importer
  • Author(s): LI Daobing
  • Date: 2009-02-14 09:32:53 UTC
  • Revision ID: james.westby@ubuntu.com-20090214093253-s2e6544ox2aj79rj
Tags: upstream-0.9.3+svn632
ImportĀ upstreamĀ versionĀ 0.9.3+svn632

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *   fqterm, a terminal emulator for both BBS and *nix.                    *
 
3
 *   Copyright (C) 2008 fqterm development group.                          *
 
4
 *                                                                         *
 
5
 *   This program is free software; you can redistribute it and/or modify  *
 
6
 *   it under the terms of the GNU General Public License as published by  *
 
7
 *   the Free Software Foundation; either version 2 of the License, or     *
 
8
 *   (at your option) any later version.                                   *
 
9
 *                                                                         *
 
10
 *   This program is distributed in the hope that it will be useful,       *
 
11
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 
12
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 
13
 *   GNU General Public License for more details.                          *
 
14
 *                                                                         *
 
15
 *   You should have received a copy of the GNU General Public License     *
 
16
 *   along with this program; if not, write to the                         *
 
17
 *   Free Software Foundation, Inc.,                                       *
 
18
 *   51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.               *
 
19
 ***************************************************************************/
 
20
 
 
21
#include <stdio.h>
 
22
#include <ctype.h>
 
23
 
 
24
#include <algorithm>
 
25
#include <vector>
 
26
#include <list>
 
27
 
 
28
#ifndef WIN32
 
29
#include <unistd.h>
 
30
#else
 
31
#include <windows.h>
 
32
#endif
 
33
 
 
34
#include <QString>
 
35
#include <QTimer>
 
36
#include <QMutex>
 
37
#include <QRegExp>
 
38
#include <QtAlgorithms>
 
39
#include <QChar>
 
40
#include <QPair>
 
41
 
 
42
#include "fqterm.h"
 
43
#include "common.h"
 
44
#include "fqterm_trace.h"
 
45
#include "fqterm_session.h"
 
46
#include "fqterm_buffer.h"
 
47
#include "fqterm_text_line.h"
 
48
#include "fqterm_telnet.h"
 
49
#include "fqterm_decode.h"
 
50
#include "fqterm_zmodem.h"
 
51
 
 
52
namespace FQTerm {
 
53
 
 
54
const QString  FQTermSession::endOfUrl[] = {
 
55
  "ac","ad","ae","af","ag","ai","al","am","an","ao","aq","ar","as","at",
 
56
  "au","aw","az","ba","bb","bd","be","bf","bg","bh","bi","bj","bm","bn","bo","br",
 
57
  "bs","bt","bv","bw","by","bz","ca","cc","cd","cf","cg","ch","ci","ck","cl","cm",
 
58
  "cn","co","uk","com","cr","cs","cu","cv","cx","cy","cz","de","dj","dk","dm",
 
59
  "do","dz","ec","edu","ee","eg","eh","er","es","et","fi","fj","fk","fm","fo",
 
60
  "fr","ga","gd","ge","gf","gg","gh","gi","gl","gm","gn","gov","gp","gq","aero",
 
61
  "asia","biz","coop","eu","info","museum","name","pro","travel","gr","gs","gt",
 
62
  "gu","gw","gy","hk","hm","hn","hr","ht","hu","id","ie","il","im","in","int",
 
63
  "io","iq","ir","is","it","je","jm","jo","jp","ke","kg","kh","ki","km","kn","kp",
 
64
  "kr","kw","ky","kz","la","lb","lc","li","lk","lr","ls","lt","lu","lv","ly","ma",
 
65
  "mc","md","mg","mh","mil","mk","ml","mm","mn","mo","mp","mq","mr","ms","mt",
 
66
  "mu","mv","mw","mx","my","mz","na","nc","ne","net","nf","ng","ni","nl","no",
 
67
  "np","nr","nt","nu","nz","om","org","pa","pe","pf","pg","ph","pk","pl","pm",
 
68
  "pn","pr","ps","pt","pw","py","qa","re","ro","ru","rw","sa","sb","sc","sd","se",
 
69
  "sg","sh","si","sj","sk","sl","sm","sn","so","sr","sv","st","sy","sz","tc","td",
 
70
  "tf","tg","th","tj","tk","tm","tn","to","tp","tr","tt","tv","tw","tz","ua","ug",
 
71
  "uk","um","us","uy","uz","va","vc","ve","vg","vi","vn","vu","wf","ws","ye","yt",
 
72
  "yu","za","zm","zw"
 
73
};
 
74
 
 
75
FQTermSession::FQTermSession(FQTermConfig *config, FQTermParam param, bool isBeep,
 
76
                             int serverEncodingID, const QString &zmodemDir) {
 
77
  param_ = param;
 
78
  termBuffer_ = new FQTermBuffer(param_.numColumns_,
 
79
                                 param_.numRows_,
 
80
                                 param_.numScrollLines_,
 
81
                                 param_.hostType_ == 0);
 
82
 
 
83
  if (param.protocolType_ == 0) {
 
84
    telnet_ = new FQTermTelnet(param_.virtualTermType_.toLatin1(),
 
85
                               param_.numRows_, param_.numColumns_, false);
 
86
  } else {
 
87
#if defined(_NO_SSH_COMPILED)
 
88
    QMessageBox::warning(this, "sorry",
 
89
                         "SSH support is not compiled, "
 
90
                         "FQTerm can only use Telnet!");
 
91
    telnet_ = new FQTermTelnet(param_.virtualTermType_.toUtf8(),
 
92
                               param_.numRows_, param_.numColumns_, false);
 
93
#else
 
94
    telnet_ = new FQTermTelnet(param_.virtualTermType_.toUtf8(),
 
95
                               param_.numRows_, param_.numColumns_, true,
 
96
                               param_.sshUserName_.toUtf8(),
 
97
                               param_.sshPassword_.toUtf8());
 
98
#endif
 
99
  }
 
100
 
 
101
  zmodem_ = new FQTermZmodem(config, telnet_, param.protocolType_, zmodemDir);
 
102
  decoder_ = new FQTermDecode(termBuffer_, telnet_, param.serverEncodingID_);
 
103
 
 
104
  //  isColorCopy_ = param.isColorCopy_;
 
105
  //  isRectangleCopy_ = param.isRectSelect_;
 
106
  //  isAutoCopy_ = param.isAutoCopy_;
 
107
  isWordWrap_ = false;
 
108
  isAntiIdle_ = true;
 
109
  isAutoReply_ = param_.isAutoReply_;
 
110
  isBeep_ = isBeep;
 
111
  isMouseSupported_ = true;
 
112
  isAutoReconnect_ = param_.isAutoReconnect_;
 
113
  isConnected_ = false;
 
114
#ifndef _NO_SSH_COMPILED
 
115
  if (param.protocolType_ != 0) {
 
116
        isLogining_ = true;
 
117
  } else {
 
118
    isLogining_ = false;
 
119
  }
 
120
#else
 
121
  isLogining_ = false;
 
122
#endif
 
123
  isIdling_ = false;
 
124
  isSendingMessage_ = false;
 
125
  isMouseX11_ = false;
 
126
 
 
127
  serverEncodingID_ = serverEncodingID;
 
128
 
 
129
  idleTimer_ = new QTimer;
 
130
  autoReplyTimer_ = new QTimer;
 
131
  reconnectTimer_ = new QTimer;
 
132
 
 
133
  acThread_ = new ArticleCopyThread(*this, waitCondition_);
 
134
 
 
135
  FQ_VERIFY(connect(reconnectTimer_, SIGNAL(timeout()),
 
136
                    this, SLOT(reconnect())));
 
137
  FQ_VERIFY(connect(decoder_, SIGNAL(mouseMode(bool)),
 
138
                    this, SLOT(setMouseMode(bool))));
 
139
  FQ_VERIFY(connect(telnet_, SIGNAL(readyRead(int, int)),
 
140
                    this, SLOT(readReady(int, int))));
 
141
  FQ_VERIFY(connect(telnet_, SIGNAL(TelnetState(int)),
 
142
                    this, SLOT(changeTelnetState(int))));
 
143
  FQ_VERIFY(connect(telnet_, SIGNAL(errorMessage(const char *)),
 
144
                    this, SIGNAL(errorMessage(const char *))));
 
145
  FQ_VERIFY(connect(telnet_, SIGNAL(requestUserPwd(QString*, QString*, bool*)),
 
146
                    this, SIGNAL(requestUserPwd(QString*, QString*, bool*))));
 
147
 
 
148
  FQ_VERIFY(connect(termBuffer_, SIGNAL(termSizeChanged(int, int)),
 
149
                    telnet_, SLOT(windowSizeChanged(int, int))));
 
150
 
 
151
  FQ_VERIFY(connect(zmodem_, SIGNAL(ZmodemState(int, int, const char *)),
 
152
                    this, SIGNAL(zmodemStateChanged(int, int, const char *))));
 
153
 
 
154
  FQ_VERIFY(connect(idleTimer_, SIGNAL(timeout()), this, SLOT(onIdle())));
 
155
  FQ_VERIFY(connect(autoReplyTimer_, SIGNAL(timeout()),
 
156
                    this, SLOT(onAutoReply())));
 
157
 
 
158
  FQ_VERIFY(connect(acThread_, SIGNAL(articleCopied(int, const QString)),
 
159
                    this, SIGNAL(articleCopied(int, const QString))));
 
160
 
 
161
  setAntiIdle(isAntiIdle_);
 
162
}
 
163
 
 
164
FQTermSession::~FQTermSession() {
 
165
  delete idleTimer_;
 
166
  delete autoReplyTimer_;
 
167
  delete reconnectTimer_;
 
168
  delete acThread_;
 
169
  delete termBuffer_;
 
170
  delete telnet_;
 
171
  delete zmodem_;
 
172
  delete decoder_;
 
173
}
 
174
 
 
175
const QString FQTermSession::protocolPrefix[] = {
 
176
  "http://", "https://", "mms://", "rstp://", "ftp://", "mailto:", "telnet://"
 
177
};
 
178
 
 
179
void FQTermSession::setScreenStart(int nStart) {
 
180
  screenStartLineNumber_ = nStart;
 
181
}
 
182
 
 
183
bool FQTermSession::setCursorPos(const QPoint &pt, QRect &rc) {
 
184
  QRect rectOld = getSelectRect();
 
185
 
 
186
  cursorPoint_ = pt;
 
187
 
 
188
  QRect rectNew = getSelectRect();
 
189
 
 
190
  rc = rectOld | rectNew;
 
191
 
 
192
  return rectOld != rectNew;
 
193
}
 
194
 
 
195
QString FQTermSession::getMessage() {
 
196
  const FQTermTextLine *line;
 
197
  LineColorInfo colorInfo;
 
198
  QString message;
 
199
 
 
200
  getLineColorInfo(termBuffer_->getTextLineInTerm(0), &colorInfo);
 
201
  if (!colorInfo.uniBackgroundColor) {
 
202
    return message;
 
203
  }
 
204
 
 
205
  int i = 1;
 
206
  termBuffer_->getTextLineInTerm(0)->getAllPlainText(message);
 
207
 
 
208
  line = termBuffer_->getTextLineInTerm(i);
 
209
  getLineColorInfo(line, &colorInfo);
 
210
  while (colorInfo.uniBackgroundColor && colorInfo.hasBackgroundColor) {
 
211
    message += "\n";
 
212
    line->getAllPlainText(message);
 
213
    i++;
 
214
    line = termBuffer_->getTextLineInTerm(i);
 
215
    getLineColorInfo(line, &colorInfo);
 
216
  }
 
217
  return message;
 
218
}
 
219
 
 
220
 
 
221
void FQTermSession::detectPageState() {
 
222
  //for smth type bbs.
 
223
  pageState_ = Undefined;
 
224
 
 
225
  const FQTermTextLine *line[4];
 
226
  LineColorInfo colorInfo[4];
 
227
  int lineIndex[4] = {0, 1, 2};
 
228
  lineIndex[3] = termBuffer_->getNumRows() - 1;
 
229
  for (int i = 0; i < 4; ++i) {
 
230
    line[i] = termBuffer_->getTextLineInTerm(lineIndex[i]);
 
231
    getLineColorInfo(line[i], colorInfo + i);
 
232
  }
 
233
 
 
234
  //TODO: Detect PageState in a clearer way.
 
235
  if (!colorInfo[0].hasBackgroundColor) {
 
236
    if (colorInfo[3].foregroundColorIndex.count() != 0 &&
 
237
        colorInfo[3].hasBackgroundColor){
 
238
        if (colorInfo[3].uniBackgroundColor) {
 
239
            QString text;
 
240
            line[3]->getAllPlainText(text);
 
241
            if (text[0] != L'\x3010') {
 
242
                pageState_ = Read;
 
243
              } else {
 
244
                  pageState_ = Edit;
 
245
                }
 
246
            } else if (colorInfo[3].backgroundColorIndex.count() == 2 &&
 
247
                  colorInfo[3].backgroundColorIndex.at(0) == 4 &&
 
248
                  colorInfo[3].backgroundColorIndex.at(1) == 0){
 
249
          pageState_ = Read;
 
250
      }
 
251
    }
 
252
    return;
 
253
  }
 
254
 
 
255
  if (colorInfo[0].backgroundColorIndex.at(0) != 4
 
256
      || !(colorInfo[3].hasBackgroundColor && colorInfo[3].backgroundColorIndex.at(0) == 4)) {
 
257
      if (!colorInfo[3].hasBackgroundColor &&
 
258
            colorInfo[0].foregroundColorIndex.count() == 4 &&
 
259
            colorInfo[0].foregroundColorIndex.at(1) == 4 &&
 
260
            colorInfo[0].foregroundColorIndex.at(2) == 7 &&
 
261
            colorInfo[0].foregroundColorIndex.at(3) == 4){
 
262
            pageState_ = TOP10;
 
263
          }
 
264
    return;
 
265
  }
 
266
 
 
267
  if (colorInfo[1].hasBackgroundColor && colorInfo[1].uniBackgroundColor) {
 
268
    pageState_ = Message;
 
269
    return;
 
270
  }
 
271
 
 
272
  if (colorInfo[0].uniBackgroundColor) {
 
273
    if (!colorInfo[2].hasBackgroundColor ||
 
274
        colorInfo[2].backgroundColorIndex.at(0) != 4 ||
 
275
        colorInfo[2].backgroundColorIndex.count() > 3) {
 
276
      pageState_ = Menu;
 
277
      return;
 
278
    }
 
279
  }
 
280
 
 
281
  if (!colorInfo[0].uniBackgroundColor &&
 
282
      colorInfo[0].backgroundColorIndex.at(0) == 4 &&
 
283
      !colorInfo[3].uniBackgroundColor) {
 
284
    //announce, elite root
 
285
    pageState_ = EliteArticleList;
 
286
    return;
 
287
  }
 
288
 
 
289
  if (colorInfo[2].hasBackgroundColor &&
 
290
      !colorInfo[2].uniBackgroundColor &&
 
291
      colorInfo[2].backgroundColorIndex.at(0) == 4 &&
 
292
      !colorInfo[3].uniBackgroundColor) {
 
293
    pageState_ = EliteArticleList;
 
294
    return;
 
295
  }
 
296
 
 
297
  if (colorInfo[0].foregroundColorIndex.indexOf(14) != -1) {
 
298
    pageState_ = ArticleList;
 
299
    return;
 
300
  }
 
301
 
 
302
  if (colorInfo[2].foregroundColorIndex.indexOf(7) != -1) {
 
303
    QString text;
 
304
    line[2]->getAllPlainText(text);
 
305
    if (text[0] == ' ') {
 
306
      pageState_ = BoardList;
 
307
    } else {
 
308
      pageState_ = MailMenu;
 
309
    }
 
310
  }
 
311
 
 
312
}
 
313
 
 
314
FQTermSession::CursorType FQTermSession::getCursorType(const QPoint &pt) {
 
315
  if (screenStartLineNumber_ !=
 
316
      (termBuffer_->getNumLines() - termBuffer_->getNumRows())) {
 
317
    return kNormal;
 
318
  }
 
319
 
 
320
  QRect rc = getSelectRect();
 
321
  CursorType nCursorType = kNormal;
 
322
  switch (pageState_) {
 
323
    case Undefined:  // not recognized
 
324
      nCursorType = kNormal;
 
325
      break;
 
326
    case Menu:
 
327
    case MailMenu:
 
328
      // menu
 
329
      if (pt.x() < 5) {
 
330
        // LEFT
 
331
        nCursorType = kLeft;
 
332
      } else if (rc.contains(pt)) {
 
333
        // HAND
 
334
        nCursorType = kRight;
 
335
      } else {
 
336
        nCursorType = kNormal;
 
337
      }
 
338
      break;
 
339
    case ArticleList:
 
340
    case BoardList:
 
341
    case EliteArticleList:
 
342
    case FriendMailList:
 
343
      // list
 
344
      if (pt.x() < 12) {
 
345
        // LEFT
 
346
        nCursorType = kLeft;
 
347
      } else if (pt.y() - screenStartLineNumber_ < 3) {
 
348
        // HOME
 
349
        nCursorType = kHome;
 
350
      } else if (pt.y() == termBuffer_->getNumLines() - 1) {
 
351
        // END
 
352
        nCursorType = kEnd;
 
353
      } else if (pt.x() > termBuffer_->getNumColumns() - 16 &&
 
354
                 pt.y() - screenStartLineNumber_ <= termBuffer_->getNumRows() / 2) {
 
355
        //PAGEUP
 
356
        nCursorType = kPageUp;
 
357
      } else if (pt.x() > termBuffer_->getNumColumns() - 16
 
358
                 && pt.y() - screenStartLineNumber_ >
 
359
                 termBuffer_->getNumRows() / 2) {
 
360
        // PAGEDOWN
 
361
        nCursorType = kPageDown;
 
362
      } else if (rc.contains(pt)) {
 
363
        // HAND
 
364
        nCursorType = kRight;
 
365
      } else {
 
366
        nCursorType = kNormal;
 
367
      }
 
368
      break;
 
369
    case Read:
 
370
      // read
 
371
      if (pt.x() < 12) {
 
372
        // LEFT
 
373
        nCursorType = kLeft;
 
374
      } else if (pt.x() > (termBuffer_->getNumColumns() - 16) &&
 
375
                 (pt.y() - screenStartLineNumber_)
 
376
                 <= termBuffer_->getNumRows() / 2) {
 
377
        // PAGEUP
 
378
        nCursorType = kPageUp;
 
379
      } else if (pt.x() > (termBuffer_->getNumColumns() - 16) &&
 
380
                 (pt.y() - screenStartLineNumber_)
 
381
                 > termBuffer_->getNumRows() / 2) {
 
382
        // PAGEDOWN
 
383
        nCursorType = kPageDown;
 
384
      } else {
 
385
        nCursorType = kNormal;
 
386
      }
 
387
      break;
 
388
    case Edit:
 
389
      // TODO: add action for kEdit state.
 
390
      break;
 
391
    case TOP10:
 
392
      if (pt.x() < 12) {
 
393
        nCursorType = kLeft;
 
394
        } else if (rc.contains(pt)){
 
395
          nCursorType = kRight;
 
396
          }
 
397
      break;
 
398
    default:
 
399
      FQ_TRACE("error", 2) << "Error, wrong PageState.";
 
400
      break;
 
401
  }
 
402
 
 
403
  return nCursorType;
 
404
}
 
405
 
 
406
bool FQTermSession::isSelected(int line) {
 
407
  // TODO: possible performance issue
 
408
  QRect rect = getSelectRect();
 
409
 
 
410
  // nothing selected
 
411
  if (rect.isNull()) {
 
412
    return false;
 
413
  }
 
414
 
 
415
  return line >= rect.bottom() && line <= rect.top();
 
416
}
 
417
 
 
418
bool FQTermSession::isSelected(const QPoint &pt) {
 
419
  // TODO: possible performance issue
 
420
  QRect rect = getSelectRect();
 
421
 
 
422
  // nothing selected
 
423
  if (rect.isNull()) {
 
424
    return false;
 
425
  }
 
426
 
 
427
  return rect.contains(pt);
 
428
}
 
429
 
 
430
FQTermSession::PageState FQTermSession::getPageState() {
 
431
  return pageState_;
 
432
}
 
433
 
 
434
char FQTermSession::getMenuChar() {
 
435
  return menuChar_;
 
436
}
 
437
//getSelectRect:
 
438
QRect FQTermSession::getSelectRect() {
 
439
  QRect rect(0, 0, 0, 0);
 
440
 
 
441
  // current screen scrolled
 
442
  if (screenStartLineNumber_ !=
 
443
      (termBuffer_->getNumLines() - termBuffer_->getNumRows())) {
 
444
    return rect;
 
445
  }
 
446
 
 
447
  const FQTermTextLine *line;
 
448
  int menuStartLine = 8;
 
449
  switch (pageState_) {
 
450
    case Undefined: break;
 
451
    case MailMenu:
 
452
      menuStartLine = 7;
 
453
    case Menu:
 
454
      if (cursorPoint_.y() - screenStartLineNumber_ >= menuStartLine &&
 
455
          cursorPoint_.x() > 5) {
 
456
        line = termBuffer_->getTextLineInBuffer(cursorPoint_.y());
 
457
        QString cstr;
 
458
        int cell_end = line->getCellEnd(qMin(cursorPoint_.x(),
 
459
                                             (int)line->getWidth()));
 
460
        line->getPlainText(0, cell_end, cstr);
 
461
 
 
462
        int base = cstr.lastIndexOf("   ");
 
463
        if (base == -1) {
 
464
          base = 0;
 
465
        }
 
466
 
 
467
        QRegExp reg("[a-zA-Z0-9][).\\]]");
 
468
        char indexChar = cstr.indexOf(reg, base);
 
469
        if (indexChar != -1) {
 
470
          menuChar_ = cstr.at(indexChar).toLatin1();
 
471
 
 
472
          QString strTmp = cstr.left(cstr.indexOf(reg, base));
 
473
          int nMenuStart = get_str_width((const UTF16 *)strTmp.data(),
 
474
                                         strTmp.size());
 
475
          if (cstr[indexChar - 1] == '(' || cstr[indexChar - 1] == '[') {
 
476
            nMenuStart--;
 
477
          }
 
478
 
 
479
          cstr.clear();
 
480
          line->getAllPlainText(cstr);
 
481
 
 
482
 
 
483
          reg = QRegExp("[^ ]");
 
484
 
 
485
          int nMenuBaseLength = 20;
 
486
          int cell_begin =
 
487
              line->getCellBegin(
 
488
                  qMin(nMenuStart + nMenuBaseLength, (int)line->getWidth() - 1));
 
489
          int char_begin = line->getCharBegin(cell_begin);
 
490
          //last [^ ] until char_begin
 
491
          strTmp = cstr.left(cstr.lastIndexOf(reg, char_begin) + 1);
 
492
 
 
493
          int nMenuLength =
 
494
              get_str_width((const UTF16 *)strTmp.data(), strTmp.size())
 
495
              - nMenuStart;
 
496
          if (nMenuLength == nMenuBaseLength + 1) {
 
497
            strTmp = cstr.left(cstr.indexOf(" ", char_begin) + 1);
 
498
            nMenuLength =
 
499
                get_str_width((const UTF16 *)strTmp.data(), strTmp.size())
 
500
                - nMenuStart;  //base length is not enough
 
501
          }
 
502
 
 
503
          if (cursorPoint_.x() >= nMenuStart && cursorPoint_.x() <=
 
504
              nMenuStart + nMenuLength) {
 
505
            rect.setX(nMenuStart);
 
506
            rect.setY(cursorPoint_.y());
 
507
            rect.setWidth(nMenuLength);
 
508
            rect.setHeight(1);
 
509
          }
 
510
        }
 
511
      }
 
512
      break;
 
513
    case ArticleList:
 
514
    case BoardList:
 
515
    case FriendMailList:
 
516
    case EliteArticleList:
 
517
      if ((cursorPoint_.y() - screenStartLineNumber_) >= 3
 
518
          && (cursorPoint_.y() - screenStartLineNumber_)
 
519
          < termBuffer_->getNumRows() -1
 
520
          && cursorPoint_.x() >= 12
 
521
          && cursorPoint_.x() <= termBuffer_->getNumColumns() - 16) {
 
522
        line = termBuffer_->getTextLineInBuffer(cursorPoint_.y());
 
523
        //QString str = line->getText();
 
524
        QString str;
 
525
        line->getAllPlainText(str);
 
526
 
 
527
        if (str.count(" ") != (int)str.length()) {
 
528
          rect.setX(0);
 
529
          rect.setY(cursorPoint_.y());
 
530
          rect.setWidth(line->getWidth());
 
531
          rect.setHeight(1);
 
532
        }
 
533
      }
 
534
      break;
 
535
    case Read:
 
536
 
 
537
      break;
 
538
    case Edit:
 
539
      break;
 
540
    case TOP10:
 
541
      {
 
542
        int ln = cursorPoint_.y() - screenStartLineNumber_;
 
543
        if (ln >= 3 && (ln & 1) && ln <= 21 &&
 
544
              cursorPoint_.x() >= 12 &&
 
545
              cursorPoint_.x() <= termBuffer_->getNumColumns() - 8){
 
546
            line = termBuffer_->getTextLineInBuffer(cursorPoint_.y());
 
547
  
 
548
            QString str;
 
549
            line->getAllPlainText(str);
 
550
    
 
551
            if (str.count(" ") != (int)str.length()) {
 
552
              if (ln == 21){
 
553
                  menuChar_ = '0';
 
554
                } else {
 
555
                    menuChar_ = ((ln - 1) >> 1) + '0';
 
556
                  }
 
557
    
 
558
                  rect.setX(12);
 
559
                rect.setY(cursorPoint_.y());
 
560
                rect.setWidth(line->getWidth() - 20);
 
561
                rect.setHeight(1);
 
562
              }
 
563
        }
 
564
      }
 
565
      break;
 
566
    default:
 
567
      break;
 
568
  }
 
569
 
 
570
  return rect;
 
571
}
 
572
 
 
573
bool FQTermSession::isIllChar(char ch) {
 
574
  static char illChars[] = ",;'\"()[]<>^";
 
575
  return ch > '~' || ch < '!' || strchr(illChars, ch) != NULL;
 
576
}
 
577
 
 
578
bool FQTermSession::isUrl(QRect &rcUrl, QRect &rcOld) {
 
579
  return checkUrl(rcUrl, rcOld, false);
 
580
}
 
581
 
 
582
bool FQTermSession::isIP(QRect &rcUrl, QRect &rcOld) {
 
583
  return checkUrl(rcUrl, rcOld, true);
 
584
}
 
585
 
 
586
QString FQTermSession::expandUrl(const QPoint& pt, QPair<int, int>& range)
 
587
{
 
588
  //  int at = pt.x();
 
589
  range.first = -1;
 
590
  range.second = -2;
 
591
  const FQTermTextLine *textLine = termBuffer_->getTextLineInBuffer(pt.y());
 
592
  if (textLine == NULL || pt.x() > (int)textLine->getWidth()) {
 
593
    return "";
 
594
  }
 
595
 
 
596
  QString text;
 
597
  textLine->getAllPlainText(text);
 
598
 
 
599
  int cell_begin = textLine->getCellBegin(pt.x());
 
600
  int at = textLine->getCharBegin(cell_begin);
 
601
  if (at >= text.length()) {
 
602
    return "";
 
603
  }
 
604
 
 
605
  int start;
 
606
  int end;
 
607
  for (start = at; start >= 0 && !isIllChar(text.at(start).toLatin1());
 
608
       start--) {
 
609
  }
 
610
  start++;
 
611
  for (end = at; end < text.length() && !isIllChar(text.at(end).toLatin1());
 
612
       end++) {
 
613
  }
 
614
  range.first = get_str_width((const UTF16 *)text.data(), start);
 
615
  range.second = get_str_width((const UTF16 *)text.data(), end);
 
616
  return text.mid(start, end - start);
 
617
}
 
618
 
 
619
 
 
620
bool FQTermSession::checkUrl(QRect &rcUrl, QRect &rcOld, bool checkIP) {
 
621
 
 
622
 
 
623
 
 
624
  QPoint pt = cursorPoint_;
 
625
  int at = pt.x();
 
626
  rcOld = urlRect_;
 
627
 
 
628
  if (at > urlRect_.left() && at < urlRect_.right() && urlRect_.y() == pt.y()) {
 
629
    if ( (checkIP && !ip_.isEmpty()) ||
 
630
         (!checkIP && !url_.isEmpty()) ) {
 
631
      rcUrl = urlRect_;
 
632
      return true;
 
633
    }
 
634
 
 
635
  }
 
636
 
 
637
  QPoint urlStartPoint;
 
638
  QPoint urlEndPoint;
 
639
  urlStartPoint_ = QPoint();
 
640
  urlEndPoint_ = QPoint();
 
641
  urlRect_ = QRect(0, 0, -1, -1);
 
642
  if (!checkIP) {
 
643
    url_.clear();
 
644
  } else {
 
645
    ip_.clear();
 
646
  }
 
647
 
 
648
  QString urlText;
 
649
  //phase 1: find all consecutive legal chars
 
650
  QPair<int, int> range;
 
651
  urlText = expandUrl(pt, range);
 
652
  if (range.first < 0 || range.first >= range.second) {
 
653
    return false;
 
654
  }
 
655
  
 
656
 
 
657
  QRect urlRect = QRect(range.first, pt.y(), range.second - range.first, 1);
 
658
  urlStartPoint = QPoint(range.first, pt.y());
 
659
  urlEndPoint = QPoint(range.second, pt.y());
 
660
 
 
661
  if (range.second == termBuffer_->getNumColumns()) {
 
662
    for (int i = pt.y() + 1; i < termBuffer_->getNumLines(); ++i) {
 
663
      QString lineText = expandUrl(QPoint(0, i), range);
 
664
      if (range.first == 0) {
 
665
        urlText += lineText;
 
666
        urlEndPoint.setY(urlEndPoint.y() + 1);
 
667
        urlEndPoint.setX(range.second);
 
668
        if (range.second == termBuffer_->getNumColumns()) {
 
669
          continue;
 
670
        }
 
671
      }
 
672
      break;
 
673
    }
 
674
  }
 
675
 
 
676
  //phase 2: find protocol prefix for url
 
677
  //if none, prefix to add is set to "mailto:" if '@' is found
 
678
  //otherwise, the prefix is "http://" by default.
 
679
  QString prefixToAdd;
 
680
  int protocolIndex;
 
681
  for (protocolIndex = 0; protocolIndex < ProtocolSupported; ++protocolIndex) {
 
682
    int begin = urlText.indexOf(protocolPrefix[protocolIndex],
 
683
                                Qt::CaseInsensitive);
 
684
    if (begin != -1 && begin <= at) {
 
685
      prefixToAdd = protocolPrefix[protocolIndex];
 
686
      urlText = urlText.mid(begin + protocolPrefix[protocolIndex].length());
 
687
      urlStartPoint.setX(urlStartPoint.x() + begin);
 
688
      break;
 
689
    }
 
690
  }
 
691
  if (protocolIndex == ProtocolSupported) {
 
692
    int begin = urlText.indexOf("://");
 
693
    if (begin != -1) {
 
694
      return false;
 
695
    }
 
696
    if (urlText.indexOf('@') != -1) {
 
697
      prefixToAdd = protocolPrefix[Mailto];
 
698
    } else {
 
699
      prefixToAdd = protocolPrefix[Http];
 
700
    }
 
701
  }
 
702
 
 
703
  //no point or duplicated points
 
704
  if (urlText.indexOf("..") != -1 || urlText.indexOf('.') == -1) {
 
705
    return false;
 
706
  }
 
707
 
 
708
  //phase 3: (for check ip) if there is a ':' before ip, there must be a '@'
 
709
  int host_begin = qMax(urlText.lastIndexOf('@') + 1, 0);
 
710
  int host_end = urlText.indexOf(':', host_begin);
 
711
  if (host_end == -1) {
 
712
    host_end = urlText.indexOf('/', host_begin);
 
713
  }
 
714
  if (host_end == -1) {
 
715
    host_end = urlText.length();
 
716
  }
 
717
  if (host_begin >= host_end) {
 
718
    return false;
 
719
  }
 
720
  if (checkIP && urlText[host_end - 1] == '*') {
 
721
    urlText[host_end - 1] = '1';
 
722
  }
 
723
 
 
724
  for (int index = 0; index < urlText.length() && urlText.at(index) != '/';
 
725
       index++) {
 
726
    QChar cur(urlText.at(index));
 
727
    if (!cur.isLetterOrNumber() && !QString("-_~:@.").contains(cur)) {
 
728
      return false;
 
729
    }
 
730
  }
 
731
 
 
732
  QString newIP;
 
733
  newIP = urlText.mid(host_begin, host_end - host_begin);
 
734
  QStringList ipv4 = newIP.split(QLatin1String("."));
 
735
  bool isIPv4 = true;
 
736
  if (ipv4.count() != 4){
 
737
    isIPv4 = false;
 
738
  }
 
739
  foreach(QString domain, ipv4) {
 
740
    bool ok;
 
741
    int num = domain.toInt(&ok);
 
742
    //won't tolerant spaces.
 
743
    if (!ok || num < 0 || num > 255 || domain.length() > 3) {
 
744
      isIPv4 = false;
 
745
      break;
 
746
    }
 
747
  }
 
748
 
 
749
  if (!checkIP){
 
750
    QString lastName = ipv4.back();
 
751
 
 
752
    int lastCharIndex = lastName.lastIndexOf(QRegExp("[a-zA-Z]"));
 
753
    if (lastCharIndex == -1) {
 
754
      if (!isIPv4) {
 
755
        return false;
 
756
      } else if (urlText == newIP) {
 
757
        return false;
 
758
      }
 
759
    } else {
 
760
      const QString *begin = endOfUrl;
 
761
      const QString *end = endOfUrl + sizeof(endOfUrl) / sizeof(QString *);
 
762
      if (qFind(begin, end, lastName) == end) {
 
763
        return false;
 
764
      }
 
765
    }
 
766
    url_ = prefixToAdd + urlText;
 
767
  } else {
 
768
    if (!isIPv4) {
 
769
      return false;
 
770
    }
 
771
    ip_ = newIP;
 
772
  }
 
773
 
 
774
  urlRect_ = urlRect;
 
775
  rcUrl = urlRect;
 
776
  urlStartPoint_ = urlStartPoint;
 
777
  urlEndPoint_ = urlEndPoint;
 
778
  return true;
 
779
}
 
780
 
 
781
QString FQTermSession::getUrl() {
 
782
  return url_;
 
783
}
 
784
 
 
785
QString FQTermSession::getIP() {
 
786
  return ip_;
 
787
}
 
788
 
 
789
bool FQTermSession::isPageComplete() {
 
790
  return termBuffer_->getCaretRow() == (termBuffer_->getNumRows() - 1)
 
791
          && termBuffer_->getCaretColumn() == (termBuffer_->getNumColumns() - 1);
 
792
}
 
793
 
 
794
bool FQTermSession::isAntiIdle() {
 
795
  return isAntiIdle_;
 
796
}
 
797
 
 
798
void FQTermSession::setAntiIdle(bool antiIdle) {
 
799
  isAntiIdle_ = antiIdle;
 
800
 
 
801
  // disabled
 
802
  if (!isAntiIdle_ && idleTimer_->isActive()) {
 
803
    idleTimer_->stop();
 
804
  }
 
805
 
 
806
  // enabled
 
807
  if (isAntiIdle_) {
 
808
    if (idleTimer_->isActive()) {
 
809
      idleTimer_->stop();
 
810
    }
 
811
    idleTimer_->start(param_.maxIdleSeconds_ *1000);
 
812
  }
 
813
}
 
814
 
 
815
void FQTermSession::autoReplyMessage() {
 
816
  if (autoReplyTimer_->isActive()) {
 
817
    autoReplyTimer_->stop();
 
818
  }
 
819
  if (pageState_ != Message) {
 
820
    return;
 
821
  }
 
822
 
 
823
  QByteArray cstrTmp = param_.replyKeyCombination_.toLocal8Bit();
 
824
  QByteArray cstr = parseString(cstrTmp.isEmpty() ? QByteArray("^Z"): cstrTmp);
 
825
  //cstr += m_param.m_strAutoReply.toLocal8Bit();
 
826
  if (param_.serverEncodingID_ == 0) {
 
827
    cstr += U2G(param_.autoReplyMessage_);
 
828
  } else {
 
829
    cstr += U2B(param_.autoReplyMessage_);
 
830
  }
 
831
 
 
832
  cstr += '\n';
 
833
  telnet_->write(cstr, cstr.length());
 
834
 
 
835
  emit messageAutoReplied();
 
836
}
 
837
 
 
838
QByteArray FQTermSession::parseString(const QByteArray &cstr, int *len) {
 
839
  QByteArray parsed = "";
 
840
 
 
841
  if (len != 0) {
 
842
    *len = 0;
 
843
  }
 
844
 
 
845
  for (uint i = 0; (long)i < cstr.length(); i++) {
 
846
    if (cstr.at(i) == '^') {
 
847
      i++;
 
848
      if ((long)i < cstr.length()) {
 
849
        parsed += FQTERM_CTRL(cstr.at(i));
 
850
        if (len != 0) {
 
851
          *len =  *len + 1;
 
852
        }
 
853
      }
 
854
    } else if (cstr.at(i) == '\\') {
 
855
        i++;
 
856
        if ((long)i < cstr.length()) {
 
857
          if (cstr.at(i) == 'n') {
 
858
            parsed += CHAR_CR;
 
859
          } else if (cstr.at(i) == 'r') {
 
860
            parsed += CHAR_LF;
 
861
          } else if (cstr.at(i) == 't') {
 
862
            parsed += CHAR_TAB;
 
863
          }
 
864
          if (len != 0) {
 
865
            *len =  *len + 1;
 
866
          }
 
867
        }
 
868
      } else {
 
869
        parsed += cstr.at(i);
 
870
        if (len != 0) {
 
871
          *len =  *len + 1;
 
872
        }
 
873
      }
 
874
  }
 
875
 
 
876
  return parsed;
 
877
}
 
878
 
 
879
void FQTermSession::reconnect() {
 
880
  if (!isConnected_) {
 
881
    telnet_->connectHost(param_.hostAddress_, param_.port_);
 
882
  }
 
883
}
 
884
 
 
885
void FQTermSession::reconnectProcess() {
 
886
  static int retry = 0;
 
887
  if (retry < param_.retryTimes_ || param_.retryTimes_ == -1) {
 
888
    if (param_.reconnectInterval_ <= 0) {
 
889
      reconnect();
 
890
    } else {
 
891
      reconnectTimer_->start(param_.reconnectInterval_ *1000);
 
892
    }
 
893
    retry++;
 
894
  }
 
895
}
 
896
 
 
897
void FQTermSession::setMouseMode(bool on) {
 
898
  isMouseX11_ = on;
 
899
}
 
900
 
 
901
void FQTermSession::doAutoLogin() {
 
902
  if (!param_.preLoginCommand_.isEmpty()) {
 
903
    QByteArray temp = parseString(param_.preLoginCommand_.toLatin1());
 
904
    telnet_->write((const char*)(temp), temp.length());
 
905
  }
 
906
  if (!param_.userName_.isEmpty()) {
 
907
    QByteArray temp = param_.userName_.toLocal8Bit();
 
908
    telnet_->write((const char*)(temp), temp.length());
 
909
    char ch = CHAR_CR;
 
910
    telnet_->write(&ch, 1);
 
911
  }
 
912
  if (!param_.password_.isEmpty()) {
 
913
    QByteArray temp = param_.password_.toLocal8Bit();
 
914
    telnet_->write((const char*)(temp), temp.length());
 
915
    char ch = CHAR_CR;
 
916
    telnet_->write(&ch, 1);
 
917
  }
 
918
 
 
919
  // smth ignore continous input, so sleep 1 sec :)
 
920
#if defined(_OS_WIN32_) || defined(Q_OS_WIN32)
 
921
  Sleep(1);
 
922
#else
 
923
  sleep(1);
 
924
#endif
 
925
 
 
926
  if (!param_.postLoginCommand_.isEmpty()) {
 
927
    QByteArray temp = parseString(param_.postLoginCommand_.toLatin1());
 
928
    telnet_->write((const char*)(temp), temp.length());
 
929
  }
 
930
  isLogining_ = false;
 
931
}
 
932
 
 
933
//read slot
 
934
void FQTermSession::readReady(int size, int raw_size) {
 
935
  FQ_ASSERT(size > 0 || raw_size > 0);  // maybe raw_size is greater than 0.
 
936
 
 
937
  raw_data_.resize(raw_size);
 
938
  telnet_->read_raw(&raw_data_[0], raw_size);
 
939
 
 
940
  // read raw buffer
 
941
  int zmodem_consumed;
 
942
  zmodem_->ZmodemRcv((uchar*)&raw_data_[0], raw_data_.size(), &(zmodem_->info),
 
943
                     zmodem_consumed);
 
944
 
 
945
  if (zmodem_->transferstate == notransfer) {
 
946
    //decode
 
947
    if (size > 0) {
 
948
      int last_size = telnet_data_.size();
 
949
      telnet_data_.resize(last_size + size);
 
950
      telnet_->read(&telnet_data_[0] + last_size, size);
 
951
 
 
952
      int processed = decoder_->decode(&telnet_data_[0], telnet_data_.size());
 
953
      telnet_data_.erase(telnet_data_.begin(), telnet_data_.begin() + processed);
 
954
    }
 
955
 
 
956
    if (isLogining_) {
 
957
      //FIXME: why these codes check those non-sense?
 
958
      int n = termBuffer_->getCaretRow();
 
959
      for (int y = n - 5; y < n + 5; y++) {
 
960
        y = qMax(0, y);
 
961
        const FQTermTextLine *pTextLine = termBuffer_->getTextLineInTerm(y);
 
962
        if (pTextLine == NULL) {
 
963
          continue;
 
964
        }
 
965
 
 
966
        // QString str = pTextLine->getText();
 
967
        QString str;
 
968
        pTextLine->getAllPlainText(str);
 
969
 
 
970
        if (str.indexOf("guest") != -1 /*&& str.indexOf("new") != -1*/) {
 
971
          doAutoLogin();
 
972
          break;
 
973
        }
 
974
      }
 
975
    }
 
976
    // page complete when caret at the right corner
 
977
    // this works for most but not for all
 
978
    const FQTermTextLine *pTextLine =
 
979
        termBuffer_->getTextLineInTerm(termBuffer_->getNumRows() - 1);
 
980
 
 
981
    //QString strText = stripWhitespace(pTextLine->getText());
 
982
    // TODO_UTF16: fixme! performance issue!
 
983
    QString strText;
 
984
    pTextLine->getAllPlainText(strText);
 
985
 
 
986
    // TODO_UTF16: shall we disable trim?
 
987
    strText = strText.trimmed();
 
988
 
 
989
    if (termBuffer_->getCaretRow() == termBuffer_->getNumRows() - 1
 
990
        && termBuffer_->getCaretColumn() >= strText.length() - 1) {
 
991
      waitCondition_.wakeAll();
 
992
    }
 
993
 
 
994
    //QToolTip::remove(this, screen_->mapToRect(m_rcUrl));
 
995
 
 
996
    // message received
 
997
    // 03/19/2003. the caret posion removed as a message judgement
 
998
    // because smth.org changed
 
999
    if (decoder_->bellReceive()) {
 
1000
      emit startAlert();
 
1001
      emit bellReceived();
 
1002
 
 
1003
      if (isAutoReply()) {
 
1004
#ifdef HAVE_PYTHON
 
1005
        if (!pythonCallback("autoReply", Py_BuildValue("(l)", this))) {
 
1006
#endif
 
1007
          // TODO: save messages
 
1008
          if (isIdling_) {
 
1009
            autoReplyMessage();
 
1010
          } else {
 
1011
            autoReplyTimer_->start(param_.maxIdleSeconds_ *1000 / 2);
 
1012
          }
 
1013
#ifdef HAVE_PYTHON
 
1014
        }
 
1015
#endif
 
1016
      }
 
1017
    }
 
1018
 
 
1019
    // set page state
 
1020
    detectPageState();
 
1021
 
 
1022
    emit sessionUpdated();
 
1023
 
 
1024
#ifdef HAVE_PYTHON
 
1025
    // python
 
1026
    pythonCallback("dataEvent", Py_BuildValue("(l)", this));
 
1027
#endif
 
1028
  }
 
1029
 
 
1030
  if (zmodem_->transferstate == transferstop) {
 
1031
    zmodem_->transferstate = notransfer;
 
1032
  }
 
1033
}
 
1034
 
 
1035
QByteArray FQTermSession::stripWhitespace(const QByteArray &cstr) {
 
1036
  QString cstrText = QString::fromLatin1(cstr);
 
1037
 
 
1038
#if (QT_VERSION>=300)
 
1039
  int pos = cstrText.lastIndexOf(QRegExp("[\\S]"));
 
1040
#else
 
1041
  int pos = cstrText.lastIndexOf(QRegExp("[^\\s]"));
 
1042
#endif
 
1043
 
 
1044
  if (pos == -1) {
 
1045
    cstrText = "";
 
1046
  } else {
 
1047
    cstrText.truncate(pos + 1);
 
1048
  }
 
1049
 
 
1050
  return cstrText.toLatin1();
 
1051
}
 
1052
 
 
1053
/* 0-left 1-middle 2-right 3-relsase 4/5-wheel
 
1054
 *
 
1055
 */
 
1056
//void FQTermWindow::sendMouseState( int num,
 
1057
//    Qt::ButtonState btnstate, Qt::ButtonState keystate, const QPoint& pt )
 
1058
void FQTermSession::sendMouseState(int num, Qt::KeyboardModifier btnstate,
 
1059
                                   Qt::KeyboardModifier keystate, const QPoint &pt) {
 
1060
  /*
 
1061
    if(!m_bMouseX11)
 
1062
    return;
 
1063
 
 
1064
    QPoint ptc = screen_->mapToChar(pt);
 
1065
 
 
1066
    if(btnstate&Qt::LeftButton)
 
1067
    num = num==0?0:num;
 
1068
    else if(btnstate&Qt::MidButton)
 
1069
    num = num==0?1:num;
 
1070
    else if(btnstate&Qt::RightButton)
 
1071
    num = num==0?2:num;
 
1072
 
 
1073
    int state = 0;
 
1074
    if(keystate&Qt::ShiftModifier)
 
1075
    state |= 0x04;
 
1076
    if(keystate&Qt::MetaModifier)
 
1077
    state |= 0x08;
 
1078
    if(keystate&Qt::ControlModifier)
 
1079
    state |= 0x10;
 
1080
 
 
1081
    // normal buttons are passed as 0x20 + button,
 
1082
    // mouse wheel (buttons 4,5) as 0x5c + button
 
1083
    if(num>3) num += 0x3c;
 
1084
 
 
1085
    char mouse[10];
 
1086
    sprintf(mouse, "\033[M%c%c%c",
 
1087
    num+state+0x20,
 
1088
    ptc.x()+1+0x20,
 
1089
    ptc.y()+1+0x20);
 
1090
    telnet_->write( mouse, strlen(mouse) );
 
1091
  */
 
1092
}
 
1093
 
 
1094
void FQTermSession::cancelZmodem() {
 
1095
  zmodem_->zmodemCancel();
 
1096
}
 
1097
 
 
1098
void FQTermSession::disconnect() {
 
1099
  telnet_->close();
 
1100
  finalizeConnection();
 
1101
}
 
1102
 
 
1103
void FQTermSession::finalizeConnection() {
 
1104
  if (isConnected_) {
 
1105
    QString strMsg = "";
 
1106
    strMsg += "\n\n\n\r\n\r";
 
1107
    strMsg += "\x1b[17C\x1b[0m===========================================\n\r";
 
1108
    strMsg +=
 
1109
        "\x1b[17C Connection Closed, Press \x1b[1m\x1b[31;40mEnter\x1b[m\x1b[0m To Connect\n\r";
 
1110
    strMsg += "\x1b[17C===========================================\n";
 
1111
    decoder_->decode(strMsg.toLatin1(), strMsg.length());
 
1112
  }
 
1113
  isConnected_ = false;
 
1114
 
 
1115
  if (autoReplyTimer_->isActive()) {
 
1116
    autoReplyTimer_->stop();
 
1117
  }
 
1118
 
 
1119
  if (idleTimer_->isActive()) {
 
1120
    idleTimer_->stop();
 
1121
  }
 
1122
 
 
1123
  emit connectionClosed();
 
1124
}
 
1125
 
 
1126
// telnet state slot
 
1127
void FQTermSession::changeTelnetState(int state) {
 
1128
  switch (state) {
 
1129
    case TSRESOLVING:
 
1130
      break;
 
1131
    case TSHOSTFOUND:
 
1132
      break;
 
1133
    case TSHOSTNOTFOUND:
 
1134
      finalizeConnection();
 
1135
      break;
 
1136
    case TSCONNECTING:
 
1137
      break;
 
1138
    case TSHOSTCONNECTED:
 
1139
      isConnected_ = true;
 
1140
      if (param_.isAutoLogin_) {
 
1141
        isLogining_ = true;
 
1142
      }
 
1143
      break;
 
1144
    case TSPROXYCONNECTED:
 
1145
      break;
 
1146
    case TSPROXYAUTH:
 
1147
      break;
 
1148
    case TSPROXYFAIL:
 
1149
      disconnect();
 
1150
      break;
 
1151
    case TSREFUSED:
 
1152
      finalizeConnection();
 
1153
      break;
 
1154
    case TSREADERROR:
 
1155
      disconnect();
 
1156
      break;
 
1157
    case TSCLOSED:
 
1158
      finalizeConnection();
 
1159
      if (param_.isAutoReconnect_ && isAutoReconnect_) {
 
1160
        reconnectProcess();
 
1161
      }
 
1162
      break;
 
1163
    case TSCLOSEFINISH:
 
1164
      finalizeConnection();
 
1165
      break;
 
1166
    case TSCONNECTVIAPROXY:
 
1167
      break;
 
1168
    case TSEGETHOSTBYNAME:
 
1169
      finalizeConnection();
 
1170
      break;
 
1171
    case TSEINIWINSOCK:
 
1172
      finalizeConnection();
 
1173
      break;
 
1174
    case TSERROR:
 
1175
      disconnect();
 
1176
      break;
 
1177
    case TSPROXYERROR:
 
1178
      disconnect();
 
1179
      break;
 
1180
    case TSWRITED:
 
1181
      // restart the idle timer
 
1182
      if (idleTimer_->isActive()) {
 
1183
        idleTimer_->stop();
 
1184
      }
 
1185
      if (isAntiIdle_) {
 
1186
        idleTimer_->start(param_.maxIdleSeconds_ *1000);
 
1187
      }
 
1188
      isIdling_ = false;
 
1189
      break;
 
1190
    default:
 
1191
      break;
 
1192
  }
 
1193
 
 
1194
  emit telnetStateChanged(state);
 
1195
}
 
1196
 
 
1197
void FQTermSession::handleInput(const QString &text) {
 
1198
  if (text.length() > 0) {
 
1199
    QByteArray cstrTmp = unicode2bbs(text);
 
1200
    telnet_->write(cstrTmp, cstrTmp.length());
 
1201
  }
 
1202
}
 
1203
 
 
1204
QByteArray FQTermSession::unicode2bbs(const QString &text) {
 
1205
  QByteArray strTmp;
 
1206
 
 
1207
  if (serverEncodingID_ == 0) {
 
1208
    strTmp = U2G(text);
 
1209
    if (param_.serverEncodingID_ == 1) {
 
1210
      char *str = encodingConverter_.G2B(strTmp, strTmp.length());
 
1211
      strTmp = str;
 
1212
      delete [] str;
 
1213
    }
 
1214
  } else {
 
1215
    strTmp = U2B(text);
 
1216
    if (param_.serverEncodingID_ == 0) {
 
1217
      char *str = encodingConverter_.B2G(strTmp, strTmp.length());
 
1218
      strTmp = str;
 
1219
      delete [] str;
 
1220
    }
 
1221
  }
 
1222
 
 
1223
  return strTmp;
 
1224
}
 
1225
 
 
1226
#ifdef HAVE_PYTHON
 
1227
bool FQTermSession::pythonCallback(const QString &func, PyObject *pArgs) {
 
1228
  if (!isPythonScriptLoaded_) {
 
1229
    Py_DECREF(pArgs);
 
1230
    return false;
 
1231
  };
 
1232
 
 
1233
  bool done = false;
 
1234
  // get the global lock
 
1235
  PyEval_AcquireLock();
 
1236
  // get a reference to the PyInterpreterState
 
1237
 
 
1238
  //Python thread references
 
1239
  extern PyThreadState *mainThreadState;
 
1240
 
 
1241
  PyInterpreterState *mainInterpreterState = mainThreadState->interp;
 
1242
  // create a thread state object for this thread
 
1243
  PyThreadState *myThreadState = PyThreadState_New(mainInterpreterState);
 
1244
  PyThreadState_Swap(myThreadState);
 
1245
 
 
1246
  PyObject *pF = PyString_FromString(func.toLatin1());
 
1247
  PyObject *pFunc = PyDict_GetItem(pythonDict_, pF);
 
1248
  Py_DECREF(pF);
 
1249
 
 
1250
  if (pFunc && PyCallable_Check(pFunc)) {
 
1251
    PyObject *pValue = PyObject_CallObject(pFunc, pArgs);
 
1252
    Py_DECREF(pArgs);
 
1253
    if (pValue != NULL) {
 
1254
      done = true;
 
1255
      Py_DECREF(pValue);
 
1256
    } else {
 
1257
      // TODO: fixme.
 
1258
      // QMessageBox::warning(this, "Python script error", getException());
 
1259
    }
 
1260
  } else {
 
1261
    PyErr_Print();
 
1262
    FQ_TRACE("session", 0) << "Cannot find python callback function: "
 
1263
                           << func;
 
1264
  }
 
1265
 
 
1266
  // swap my thread state out of the interpreter
 
1267
  PyThreadState_Swap(NULL);
 
1268
  // clear out any cruft from thread state object
 
1269
  PyThreadState_Clear(myThreadState);
 
1270
  // delete my thread state object
 
1271
  PyThreadState_Delete(myThreadState);
 
1272
  // release the lock
 
1273
  PyEval_ReleaseLock();
 
1274
 
 
1275
  if (func == "autoReply") {
 
1276
    // TODO: fixme
 
1277
    // paveViewMessage_->display("You have messages", PageViewMessage::Info, 0);
 
1278
  }
 
1279
 
 
1280
  return done;
 
1281
}
 
1282
#endif //HAVE_PYTHON
 
1283
 
 
1284
void FQTermSession::onIdle() {
 
1285
  // do as autoreply when it is enabled
 
1286
  if (autoReplyTimer_->isActive() && isAutoReply_) {
 
1287
    autoReplyMessage();
 
1288
    stopAlert();
 
1289
    return ;
 
1290
  }
 
1291
 
 
1292
  isIdling_ = true;
 
1293
  // system script can handle that
 
1294
#ifdef HAVE_PYTHON
 
1295
  if (pythonCallback("antiIdle", Py_BuildValue("(l)", this))) {
 
1296
    return ;
 
1297
  }
 
1298
#endif
 
1299
  // the default function
 
1300
  int length;
 
1301
  QByteArray cstr = parseString(param_.antiIdleMessage_.toLocal8Bit(), &length);
 
1302
  telnet_->write(cstr, length);
 
1303
}
 
1304
 
 
1305
void FQTermSession::onAutoReply() {
 
1306
  // if AutoReply still enabled, then autoreply
 
1307
  if (isAutoReply_) {
 
1308
    autoReplyMessage();
 
1309
  } else {
 
1310
    // else just stop the timer
 
1311
    autoReplyTimer_->stop();
 
1312
  }
 
1313
 
 
1314
  stopAlert();
 
1315
}
 
1316
bool FQTermSession::isAutoReply() {
 
1317
  return isAutoReply_;
 
1318
}
 
1319
 
 
1320
void FQTermSession::setAutoReply(bool on) {
 
1321
  isAutoReply_ = on;
 
1322
  if (!isAutoReply_ && autoReplyTimer_->isActive()) {
 
1323
    autoReplyTimer_->stop();
 
1324
  }
 
1325
}
 
1326
 
 
1327
int FQTermSession::write(const char *data, int len) {
 
1328
  return telnet_->write(data, len);
 
1329
}
 
1330
 
 
1331
int FQTermSession::writeStr(const char *str) {
 
1332
  return write(str, strlen(str));
 
1333
}
 
1334
 
 
1335
void FQTermSession::setProxy(int type, bool needAuth,
 
1336
                             const QString &hostName, quint16 portNumber,
 
1337
                             const QString &userName, const QString &password) {
 
1338
  telnet_->setProxy(type, needAuth, hostName, portNumber, userName, password);
 
1339
}
 
1340
 
 
1341
void FQTermSession::connectHost(const QString &hostName, quint16 portNumber) {
 
1342
  telnet_->connectHost(hostName, portNumber);
 
1343
}
 
1344
 
 
1345
void FQTermSession::close() {
 
1346
  telnet_->close();
 
1347
  if (reconnectTimer_->isActive()) {
 
1348
    reconnectTimer_->stop();
 
1349
  }
 
1350
  finalizeConnection();
 
1351
}
 
1352
 
 
1353
void FQTermSession::clearLineChanged(int index) {
 
1354
  termBuffer_->clearLineChanged(index);
 
1355
}
 
1356
 
 
1357
void FQTermSession::setLineAllChanged(int index) {
 
1358
  termBuffer_->setLineAllChanged(index);
 
1359
}
 
1360
 
 
1361
void FQTermSession::setTermSize(int col, int row) {
 
1362
  termBuffer_->setTermSize(col, row);
 
1363
}
 
1364
 
 
1365
const FQTermBuffer *FQTermSession::getBuffer() const {
 
1366
  return termBuffer_;
 
1367
}
 
1368
 
 
1369
void FQTermSession::setSelect(const QPoint &pt1, const QPoint &pt2) {
 
1370
  termBuffer_->setSelect(pt1, pt2);
 
1371
}
 
1372
 
 
1373
void FQTermSession::clearSelect() {
 
1374
  termBuffer_->clearSelect();
 
1375
}
 
1376
 
 
1377
void FQTermSession::leaveIdle() {
 
1378
  if (autoReplyTimer_->isActive()) {
 
1379
    autoReplyTimer_->stop();
 
1380
  }
 
1381
 
 
1382
  if (idleTimer_->isActive()) {
 
1383
    idleTimer_->stop();
 
1384
  }
 
1385
 
 
1386
  if (isAntiIdle_) {
 
1387
    idleTimer_->start(param_.maxIdleSeconds_ * 1000);
 
1388
  }
 
1389
}
 
1390
 
 
1391
void FQTermSession::copyArticle() {
 
1392
  if (!acThread_->isRunning()) {
 
1393
    acThread_->start();
 
1394
  }
 
1395
}
 
1396
 
 
1397
void FQTermSession::getLineColorInfo(const FQTermTextLine * line,
 
1398
                                     LineColorInfo * colorInfo)
 
1399
{
 
1400
  colorInfo->backgroundColorIndex.clear();
 
1401
  colorInfo->foregroundColorIndex.clear();
 
1402
  colorInfo->hasBackgroundColor = false;
 
1403
  colorInfo->uniBackgroundColor = true;
 
1404
  colorInfo->uniForegroundColor = true;
 
1405
  colorInfo->hasForegroundColor = false;
 
1406
 
 
1407
  if (line->getWidth() == 0) {
 
1408
    return;
 
1409
  }
 
1410
 
 
1411
  const unsigned char *color = line->getColors();
 
1412
  unsigned char background = GETBG(color[0]);
 
1413
  unsigned char foreground = GETFG(color[0]);
 
1414
  colorInfo->backgroundColorIndex.append(background);
 
1415
  colorInfo->foregroundColorIndex.append(foreground);
 
1416
  //for (int i = 0; i < color.length() / 2; i++) {
 
1417
  // TODO_UTF16: why use color.length()/2 formerly?
 
1418
  for (int i = 0; i < (int)line->getWidth(); i++) {
 
1419
    if (GETBG(color[i]) != background) {
 
1420
      colorInfo->uniBackgroundColor = false;
 
1421
      background = GETBG(color[i]);
 
1422
      colorInfo->backgroundColorIndex.append(background);
 
1423
    }
 
1424
    if (GETBG(color[i]) != GETBG(NO_COLOR)) {
 
1425
      colorInfo->hasBackgroundColor = true;
 
1426
    }
 
1427
    if (GETFG(color[i]) != foreground) {
 
1428
      colorInfo->uniForegroundColor = false;
 
1429
      foreground = GETFG(color[i]);
 
1430
      colorInfo->foregroundColorIndex.append(foreground);
 
1431
    }
 
1432
    if (GETFG(color[i]) != GETFG(NO_COLOR)) {
 
1433
      colorInfo->hasForegroundColor = true;
 
1434
    }
 
1435
  }
 
1436
}
 
1437
 
 
1438
ArticleCopyThread::ArticleCopyThread(
 
1439
    FQTermSession &bbs, QWaitCondition &waitCondition)
 
1440
    : session_(bbs),
 
1441
      waitCondition_(waitCondition),
 
1442
      mutex_(new QMutex()) {
 
1443
}
 
1444
 
 
1445
ArticleCopyThread::~ArticleCopyThread() {
 
1446
  delete mutex_;
 
1447
}
 
1448
 
 
1449
static void removeTrailSpace(QString &line) {
 
1450
  for (int last_non_space = line.size() - 1;
 
1451
       last_non_space >= 0; --last_non_space) {
 
1452
    QChar a = line.at(last_non_space);
 
1453
    if (!a.isSpace()) {
 
1454
      line.resize(last_non_space + 1);
 
1455
      break;
 
1456
    }
 
1457
 
 
1458
    if (last_non_space == 0) {
 
1459
      line.resize(0);
 
1460
    }
 
1461
  }
 
1462
}
 
1463
 
 
1464
///////////////////////////////////////
 
1465
//analyze last line when copy article
 
1466
static std::pair<int, int> ParseLastLine(QString str) {
 
1467
  int startLine = -1;
 
1468
  int endLine = -1;
 
1469
  int infoStart = str.indexOf('(', str.indexOf('(') + 1);
 
1470
  int infoEnd = str.indexOf(')', infoStart);
 
1471
  int infoSplit = str.indexOf('-', infoStart);
 
1472
  if (infoStart == -1 || infoEnd == -1 || infoSplit == -1) {
 
1473
    return std::make_pair(-1, -1);
 
1474
  }
 
1475
  bool ok = true;
 
1476
  startLine = str.mid(infoStart + 1, infoSplit - infoStart - 1).toInt(&ok);
 
1477
  if (!ok) {
 
1478
    return std::make_pair(-1, -1);
 
1479
  }
 
1480
  endLine = str.mid(infoSplit + 1, infoEnd - infoSplit - 1).toInt(&ok);
 
1481
  if (!ok) {
 
1482
    return std::make_pair(-1, -1);
 
1483
  }
 
1484
  return std::make_pair(startLine, endLine);
 
1485
}
 
1486
///////////////////////////////////////
 
1487
 
 
1488
 
 
1489
void ArticleCopyThread::run() {
 
1490
  mutex_->lock();
 
1491
 
 
1492
  typedef std::vector<QString> Page;
 
1493
  const FQTermBuffer *buffer = session_.getBuffer();;
 
1494
  Page page;
 
1495
  bool MultiPage = false;
 
1496
 
 
1497
  QString firstPageLastLine;
 
1498
  buffer->getTextLineInTerm(buffer->getNumRows() - 1)->getAllPlainText(firstPageLastLine);
 
1499
  if (firstPageLastLine.indexOf("%") != -1) {
 
1500
    MultiPage = true;
 
1501
    session_.write("e", 1);
 
1502
    if (!waitCondition_.wait(mutex_, 10000)) {
 
1503
      emit articleCopied(DAE_TIMEOUT, "");
 
1504
      return;
 
1505
    }
 
1506
    QString LastPageLastLine;
 
1507
    buffer->getTextLineInTerm(buffer->getNumRows() - 1)->getAllPlainText(LastPageLastLine);
 
1508
    std::pair<int, int> range = ParseLastLine(LastPageLastLine);
 
1509
    if (range.first == -1 || range.second == -1) {
 
1510
      return;
 
1511
    }
 
1512
    page.resize(range.second);
 
1513
    for (int i = range.first; i <= range.second; ++i) {
 
1514
      QString strTemp;
 
1515
      buffer->getTextLineInTerm(i - range.first)->getAllPlainText(strTemp);
 
1516
      page[i - 1] = strTemp;
 
1517
    }
 
1518
    session_.write("s", 1);
 
1519
    if (!waitCondition_.wait(mutex_, 10000)) {
 
1520
      emit articleCopied(DAE_TIMEOUT, "");
 
1521
      return;
 
1522
    }
 
1523
  }
 
1524
  else {
 
1525
    for (int i = 0; i < buffer->getNumRows() - 1; ++i) {
 
1526
      QString strTemp;
 
1527
      buffer->getTextLineInTerm(i)->getAllPlainText(strTemp);
 
1528
      page.push_back(strTemp);
 
1529
    }
 
1530
  }
 
1531
 
 
1532
  while (MultiPage) {
 
1533
    // the end of article
 
1534
    int lineIndex = buffer->getNumRows() - 1;
 
1535
    //QByteArray lastLine = buffer->getLineInScreen(lineIndex)->getText();
 
1536
    QString lastLine;
 
1537
    buffer->getTextLineInTerm(lineIndex)->getAllPlainText(lastLine);
 
1538
 
 
1539
    std::pair<int, int> range = ParseLastLine(lastLine);
 
1540
    if (range.first == -1 || range.second == -1) {
 
1541
      page.push_back(lastLine);
 
1542
      break;
 
1543
    }
 
1544
 
 
1545
    // copy a page of lines exclude the last line.
 
1546
    for (int i = range.first; i <= range.second; ++i) {
 
1547
      QString strTemp;
 
1548
      buffer->getTextLineInTerm(i - range.first)->getAllPlainText(strTemp);
 
1549
      page[i - 1] = strTemp;
 
1550
    }
 
1551
 
 
1552
 
 
1553
    // wait for next page.
 
1554
    session_.write(" ", 1);
 
1555
    if (!waitCondition_.wait(mutex_, 10000)) {
 
1556
      emit articleCopied(DAE_TIMEOUT, "");
 
1557
      break;
 
1558
    }
 
1559
  }
 
1560
 
 
1561
 
 
1562
 
 
1563
  QString articleText;
 
1564
 
 
1565
  for (Page::iterator line = page.begin(); line != page.end(); ++line) {
 
1566
    removeTrailSpace(*line);
 
1567
    articleText += (*line);
 
1568
    articleText += (OS_NEW_LINE);
 
1569
  }
 
1570
 
 
1571
  //qApp->postEvent(pWin, new QCustomEvent(DAE_FINISH));
 
1572
  emit articleCopied(DAE_FINISH, articleText);
 
1573
  mutex_->unlock();
 
1574
}
 
1575
 
 
1576
}  // namespace FQTerm
 
1577
 
 
1578
#include "fqterm_session.moc"