~ubuntu-branches/ubuntu/raring/quassel/raring-proposed

« back to all changes in this revision

Viewing changes to src/core/networkconnection.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Harald Sitter
  • Date: 2008-06-27 19:21:30 UTC
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20080627192130-kjsrutd8w40x5okn
Tags: upstream-0.2.0~rc1
ImportĀ upstreamĀ versionĀ 0.2.0~rc1

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
#include "userinputhandler.h"
37
37
#include "ctcphandler.h"
38
38
 
39
 
NetworkConnection::NetworkConnection(Network *network, CoreSession *session) : QObject(network),
 
39
NetworkConnection::NetworkConnection(Network *network, CoreSession *session)
 
40
  : QObject(network),
40
41
    _connectionState(Network::Disconnected),
41
42
    _network(network),
42
43
    _coreSession(session),
43
44
    _ircServerHandler(new IrcServerHandler(this)),
44
45
    _userInputHandler(new UserInputHandler(this)),
45
46
    _ctcpHandler(new CtcpHandler(this)),
46
 
    _autoReconnectCount(0)
 
47
    _autoReconnectCount(0),
 
48
    _quitRequested(false),
 
49
 
 
50
    _previousConnectionAttemptFailed(false),
 
51
    _lastUsedServerlistIndex(0),
 
52
 
 
53
    // TODO make autowho configurable (possibly per-network)
 
54
    _autoWhoEnabled(true),
 
55
    _autoWhoInterval(90),
 
56
    _autoWhoNickLimit(0), // unlimited
 
57
    _autoWhoDelay(3),
 
58
 
 
59
    // TokenBucket to avaid sending too much at once
 
60
    _messagesPerSecond(1),
 
61
    _burstSize(5),
 
62
    _tokenBucket(5) // init with a full bucket
47
63
{
48
64
  _autoReconnectTimer.setSingleShot(true);
49
 
 
50
 
  _previousConnectionAttemptFailed = false;
51
 
  _lastUsedServerlistIndex = 0;
52
 
 
53
 
  // TODO make autowho configurable (possibly per-network)
54
 
  _autoWhoEnabled = true;
55
 
  _autoWhoInterval = 90;
56
 
  _autoWhoNickLimit = 0; // unlimited
57
 
  _autoWhoDelay = 3;
58
 
 
 
65
  _socketCloseTimer.setSingleShot(true);
 
66
  connect(&_socketCloseTimer, SIGNAL(timeout()), this, SLOT(socketCloseTimeout()));
 
67
  
59
68
  _autoWhoTimer.setInterval(_autoWhoDelay * 1000);
60
 
  _autoWhoTimer.setSingleShot(false);
61
69
  _autoWhoCycleTimer.setInterval(_autoWhoInterval * 1000);
62
 
  _autoWhoCycleTimer.setSingleShot(false);
63
 
 
64
 
  // TokenBucket to avaid sending too much at once
65
 
  _messagesPerSecond = 1;
66
 
  _burstSize = 5;
67
 
  _tokenBucket = 5; // init with a full bucket
68
 
 
 
70
  
69
71
  _tokenBucketTimer.start(_messagesPerSecond * 1000);
70
 
  _tokenBucketTimer.setSingleShot(false);
71
72
 
72
73
  QHash<QString, QString> channels = coreSession()->persistentChannels(networkId());
73
74
  foreach(QString chan, channels.keys()) {
104
105
NetworkConnection::~NetworkConnection() {
105
106
  if(connectionState() != Network::Disconnected && connectionState() != Network::Reconnecting)
106
107
    disconnectFromIrc(false); // clean up, but this does not count as requested disconnect!
 
108
  disconnect(&socket, 0, this, 0); // this keeps the socket from triggering events during clean up
107
109
  delete _ircServerHandler;
108
110
  delete _userInputHandler;
109
111
  delete _ctcpHandler;
252
254
  if(socket.state() < QAbstractSocket::ConnectedState) {
253
255
    setConnectionState(Network::Disconnected);
254
256
    socketDisconnected();
255
 
  } else socket.disconnectFromHost();
256
 
 
257
 
  if(requested) {
258
 
    emit quitRequested(networkId());
 
257
  } else {
 
258
    _socketCloseTimer.start(10000); // the irc server has 10 seconds to close the socket
259
259
  }
 
260
 
 
261
  // this flag triggers quitRequested() once the socket is closed
 
262
  // it is needed to determine whether or not the connection needs to be
 
263
  // in the automatic session restore.
 
264
  _quitRequested = requested;
260
265
}
261
266
 
262
267
void NetworkConnection::socketHasData() {
360
365
  setConnectionState(state);
361
366
}
362
367
 
 
368
void NetworkConnection::socketCloseTimeout() {
 
369
  socket.disconnectFromHost();
 
370
}
 
371
 
363
372
void NetworkConnection::socketDisconnected() {
364
373
  _autoWhoCycleTimer.stop();
365
374
  _autoWhoTimer.stop();
366
375
  _autoWhoQueue.clear();
367
376
  _autoWhoInProgress.clear();
368
377
 
 
378
  _socketCloseTimer.stop();
 
379
  
369
380
  network()->setConnected(false);
370
381
  emit disconnected(networkId());
371
382
  if(_autoReconnectCount != 0) {
372
383
    setConnectionState(Network::Reconnecting);
373
384
    if(_autoReconnectCount == network()->autoReconnectRetries()) doAutoReconnect(); // first try is immediate
374
385
    else _autoReconnectTimer.start();
 
386
  } else if(_quitRequested) {
 
387
    emit quitRequested(networkId());
375
388
  }
376
389
}
377
390
 
413
426
  }
414
427
}
415
428
 
416
 
void NetworkConnection::putCmd(const QString &cmd, const QVariantList &params, const QByteArray &prefix) {
 
429
// returns 0 if the message will not be chopped by the irc server or number of chopped bytes if message is too long
 
430
int NetworkConnection::lastParamOverrun(const QString &cmd, const QList<QByteArray> &params) {
 
431
  //the server will pass our message that trunkated to 512 bytes including CRLF with the following format:
 
432
  // ":prefix COMMAND param0 param1 :lastparam"
 
433
  // where prefix = "nickname!user@host"
 
434
  // that means that the last message can be as long as:
 
435
  // 512 - nicklen - userlen - hostlen - commandlen - sum(param[0]..param[n-1])) - 2 (for CRLF) - 4 (":!@" + 1space between prefix and command) - max(paramcount - 1, 0) (space for simple params) - 2 (space and colon for last param)
 
436
  IrcUser *me = network()->me();
 
437
  int maxLen = 480 - cmd.toAscii().count(); // educated guess in case we don't know us (yet?)
 
438
 
 
439
  if(me)
 
440
    maxLen = 512 - serverEncode(me->nick()).count() - serverEncode(me->user()).count() - serverEncode(me->host()).count() - cmd.toAscii().count() - 6;
 
441
 
 
442
  if(!params.isEmpty()) {
 
443
    for(int i = 0; i < params.count() - 1; i++) {
 
444
      maxLen -= (params[i].count() + 1);
 
445
    }
 
446
    maxLen -= 2; // " :" last param separator;
 
447
    
 
448
    if(params.last().count() > maxLen) {
 
449
      return params.last().count() - maxLen;
 
450
    } else {
 
451
      return 0;
 
452
    }
 
453
  } else {
 
454
    return 0;
 
455
  }
 
456
}
 
457
 
 
458
void NetworkConnection::putCmd(const QString &cmd, const QList<QByteArray> &params, const QByteArray &prefix) {
417
459
  QByteArray msg;
 
460
  if(cmd == "PRIVMSG" && params.count() > 1) {
 
461
    int overrun = lastParamOverrun(cmd, params);
 
462
    if(overrun) {
 
463
      QList<QByteArray> paramCopy1;
 
464
      QList<QByteArray> paramCopy2;
 
465
      for(int i = 0; i < params.count() - 1; i++) {
 
466
        paramCopy1 << params[i];
 
467
        paramCopy2 << params[i];
 
468
      }
 
469
 
 
470
      QByteArray lastPart = params.last();
 
471
      QByteArray splitter(" .,-");
 
472
      int maxSplitPos = params.last().count() - overrun;
 
473
      int splitPos = -1;
 
474
      for(int i = 0; i < splitter.size(); i++) {
 
475
        splitPos = qMax(splitPos, lastPart.lastIndexOf(splitter[i], maxSplitPos));
 
476
      }
 
477
 
 
478
      if(splitPos == -1) {
 
479
        splitPos = maxSplitPos;
 
480
      }
 
481
      
 
482
      paramCopy1 << lastPart.left(splitPos);
 
483
      paramCopy2 << lastPart.mid(splitPos);
 
484
      putCmd(cmd, paramCopy1, prefix);
 
485
      putCmd(cmd, paramCopy2, prefix);
 
486
      return;
 
487
    }
 
488
  }
 
489
     
418
490
  if(!prefix.isEmpty())
419
491
    msg += ":" + prefix + " ";
420
492
  msg += cmd.toUpper().toAscii();
421
493
 
422
494
  for(int i = 0; i < params.size() - 1; i++) {
423
 
    msg += " " + params[i].toByteArray();
 
495
    msg += " " + params[i];
424
496
  }
425
497
  if(!params.isEmpty())
426
 
    msg += " :" + params.last().toByteArray();
 
498
    msg += " :" + params.last();
427
499
 
428
500
  putRawLine(msg);
429
501
}