ircclient.cpp
1 //------------------------------------------------------------------------------
2 // ircclient.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (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 Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301, USA.
19 //
20 //------------------------------------------------------------------------------
21 // Copyright (C) 2010 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "ircclient.h"
24 #include "log.h"
25 #include "lookuphost.h"
26 
27 IRCClient::IRCClient()
28 {
29  this->bIsInHostLookupMode = false;
30 
31  recvTimer.setSingleShot(true);
32  setFakeRecvLag(0);
33 
34  QObject::connect(&socket, SIGNAL(readyRead()), this, SLOT(receiveSocketDataDelayed()));
35  QObject::connect(&recvTimer, SIGNAL(timeout()), this, SLOT(receiveSocketData()));
36 }
37 
38 IRCClient::~IRCClient()
39 {
40  disconnect();
41 }
42 
43 void IRCClient::connect(const QString& address, unsigned short port)
44 {
45  emit infoMessage(tr("IRC: attempting host lookup: %1").arg(address));
46 
47  this->bIsInHostLookupMode = true;
48  this->port = port;
49  this->hostName = address;
50 
51  LookupHost::lookupHost(address, this, SLOT( hostLookupFinished(const QHostInfo&) ) );
52 }
53 
54 void IRCClient::connectSocketSignals(SocketSignalsAdapter* pAdapter)
55 {
56  pAdapter->pSocket = &socket;
57  pAdapter->connect(&socket, SIGNAL( connected() ), SLOT( connected() ));
58  pAdapter->connect(&socket, SIGNAL( disconnected() ), SLOT( disconnected() ));
59  pAdapter->connect(&socket, SIGNAL( error(QAbstractSocket::SocketError) ), SLOT( errorReceived(QAbstractSocket::SocketError) ));
60  pAdapter->connect(this, SIGNAL( hostLookupError(QHostInfo::HostInfoError) ), SLOT( hostLookupError(QHostInfo::HostInfoError) ));
61  pAdapter->connect(this, SIGNAL( infoMessage(const QString&) ), SLOT( infoMessage(const QString&) ));
62 }
63 
64 void IRCClient::disconnect()
65 {
66  if (isConnected())
67  {
68  socket.close();
69  }
70 }
71 
72 void IRCClient::hostLookupFinished(const QHostInfo& hostInfo)
73 {
74  this->bIsInHostLookupMode = false;
75 
76  if (hostInfo.error() != QHostInfo::NoError)
77  {
78  emit hostLookupError(hostInfo.error());
79  }
80  else
81  {
82  const QHostAddress* pIp = this->pickAddress(hostInfo.addresses());
83 
84  if (pIp == NULL)
85  {
86  emit hostLookupError(QHostInfo::HostNotFound);
87  }
88  else
89  {
90  emit infoMessage(tr("IRC: Connecting: %1:%2 [IP: %3]").arg(this->hostName).arg(this->port).arg(pIp->toString()));
91  socket.connectToHost(*pIp, port);
92  }
93  }
94 }
95 
96 bool IRCClient::isConnected() const
97 {
98  return socket.state() == QTcpSocket::ConnectedState && !this->bIsInHostLookupMode;
99 }
100 
101 const QHostAddress* IRCClient::pickAddress(const QList<QHostAddress>& addressesList)
102 {
103  const QHostAddress* pIPv6 = NULL;;
104 
105  foreach (const QHostAddress& addr, addressesList)
106  {
107  if (addr.protocol() != QAbstractSocket::IPv4Protocol)
108  {
109  if (addr.protocol() == QAbstractSocket::IPv6Protocol
110  && pIPv6 == NULL)
111  {
112  pIPv6 = &addr;
113  }
114  }
115  else
116  {
117  return &addr;
118  }
119  }
120 
121  // If we didn't return yet we must return the IPv6 addreses.
122  // If it is not null that is...
123  return pIPv6;
124 }
125 
126 void IRCClient::receiveSocketData()
127 {
128  while (socket.canReadLine())
129  {
130  QByteArray socketData = socket.readLine();
131  QString responseLine = QString::fromUtf8(socketData.constData(), socketData.size());
132  emit ircServerResponse(responseLine);
133  }
134 }
135 
136 void IRCClient::receiveSocketDataDelayed()
137 {
138  if (!recvTimer.isActive())
139  {
140  recvTimer.start();
141  }
142 }
143 
144 bool IRCClient::sendMessage(const QString& message)
145 {
146  if (!isConnected())
147  {
148  return false;
149  }
150 
151  QByteArray messageContent = message.toUtf8();
152  messageContent.append("\r\n");
153 
154  qint64 numBytesWritten = socket.write(messageContent);
155  socket.flush();
156 
157  return numBytesWritten == messageContent.size();
158 }
159 
160 void IRCClient::setFakeRecvLag(int lagMs)
161 {
162  recvTimer.setInterval(lagMs);
163 }
void infoMessage(const QString &message)
These are the messages that IRCClient class sends to inform the upper layers of progress.