~ubuntu-branches/ubuntu/saucy/quassel/saucy

« back to all changes in this revision

Viewing changes to src/core/ctcphandler.cpp

  • Committer: Package Import Robot
  • Author(s): Scott Kitterman
  • Date: 2012-02-14 18:38:55 UTC
  • mfrom: (1.1.46)
  • Revision ID: package-import@ubuntu.com-20120214183855-ak8af7n6qweqy3f0
Tags: 0.8~beta1-0ubuntu1
* New upstream beta release
  - Update quasselcore man page for new oidentd option 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/***************************************************************************
2
 
 *   Copyright (C) 2005-10 by the Quassel Project                          *
3
 
 *   devel@quassel-irc.org                                                 *
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) version 3.                                           *
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
 
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19
 
 ***************************************************************************/
20
 
#include "ctcphandler.h"
21
 
 
22
 
#include "message.h"
23
 
#include "network.h"
24
 
#include "quassel.h"
25
 
#include "util.h"
26
 
#include "coreignorelistmanager.h"
27
 
 
28
 
CtcpHandler::CtcpHandler(CoreNetwork *parent)
29
 
  : CoreBasicHandler(parent),
30
 
    XDELIM("\001"),
31
 
    _ignoreListManager(parent->ignoreListManager())
32
 
{
33
 
 
34
 
  QByteArray MQUOTE = QByteArray("\020");
35
 
  ctcpMDequoteHash[MQUOTE + '0'] = QByteArray(1, '\000');
36
 
  ctcpMDequoteHash[MQUOTE + 'n'] = QByteArray(1, '\n');
37
 
  ctcpMDequoteHash[MQUOTE + 'r'] = QByteArray(1, '\r');
38
 
  ctcpMDequoteHash[MQUOTE + MQUOTE] = MQUOTE;
39
 
 
40
 
  QByteArray XQUOTE = QByteArray("\134");
41
 
  ctcpXDelimDequoteHash[XQUOTE + XQUOTE] = XQUOTE;
42
 
  ctcpXDelimDequoteHash[XQUOTE + QByteArray("a")] = XDELIM;
43
 
}
44
 
 
45
 
QByteArray CtcpHandler::lowLevelQuote(const QByteArray &message) {
46
 
  QByteArray quotedMessage = message;
47
 
 
48
 
  QHash<QByteArray, QByteArray> quoteHash = ctcpMDequoteHash;
49
 
  QByteArray MQUOTE = QByteArray("\020");
50
 
  quoteHash.remove(MQUOTE + MQUOTE);
51
 
  quotedMessage.replace(MQUOTE, MQUOTE + MQUOTE);
52
 
 
53
 
  QHash<QByteArray, QByteArray>::const_iterator quoteIter = quoteHash.constBegin();
54
 
  while(quoteIter != quoteHash.constEnd()) {
55
 
    quotedMessage.replace(quoteIter.value(), quoteIter.key());
56
 
    quoteIter++;
57
 
  }
58
 
  return quotedMessage;
59
 
}
60
 
 
61
 
QByteArray CtcpHandler::lowLevelDequote(const QByteArray &message) {
62
 
  QByteArray dequotedMessage;
63
 
  QByteArray messagepart;
64
 
  QHash<QByteArray, QByteArray>::iterator ctcpquote;
65
 
 
66
 
  // copy dequote Message
67
 
  for(int i = 0; i < message.size(); i++) {
68
 
    messagepart = message.mid(i,1);
69
 
    if(i+1 < message.size()) {
70
 
      for(ctcpquote = ctcpMDequoteHash.begin(); ctcpquote != ctcpMDequoteHash.end(); ++ctcpquote) {
71
 
        if(message.mid(i,2) == ctcpquote.key()) {
72
 
          messagepart = ctcpquote.value();
73
 
          i++;
74
 
          break;
75
 
        }
76
 
      }
77
 
    }
78
 
    dequotedMessage += messagepart;
79
 
  }
80
 
  return dequotedMessage;
81
 
}
82
 
 
83
 
QByteArray CtcpHandler::xdelimQuote(const QByteArray &message) {
84
 
  QByteArray quotedMessage = message;
85
 
  QHash<QByteArray, QByteArray>::const_iterator quoteIter = ctcpXDelimDequoteHash.constBegin();
86
 
  while(quoteIter != ctcpXDelimDequoteHash.constEnd()) {
87
 
    quotedMessage.replace(quoteIter.value(), quoteIter.key());
88
 
    quoteIter++;
89
 
  }
90
 
  return quotedMessage;
91
 
}
92
 
 
93
 
QByteArray CtcpHandler::xdelimDequote(const QByteArray &message) {
94
 
  QByteArray dequotedMessage;
95
 
  QByteArray messagepart;
96
 
  QHash<QByteArray, QByteArray>::iterator xdelimquote;
97
 
 
98
 
  for(int i = 0; i < message.size(); i++) {
99
 
    messagepart = message.mid(i,1);
100
 
    if(i+1 < message.size()) {
101
 
      for(xdelimquote = ctcpXDelimDequoteHash.begin(); xdelimquote != ctcpXDelimDequoteHash.end(); ++xdelimquote) {
102
 
        if(message.mid(i,2) == xdelimquote.key()) {
103
 
          messagepart = xdelimquote.value();
104
 
          i++;
105
 
          break;
106
 
        }
107
 
      }
108
 
    }
109
 
    dequotedMessage += messagepart;
110
 
  }
111
 
  return dequotedMessage;
112
 
}
113
 
 
114
 
void CtcpHandler::parse(Message::Type messageType, const QString &prefix, const QString &target, const QByteArray &message) {
115
 
  QByteArray ctcp;
116
 
 
117
 
  //lowlevel message dequote
118
 
  QByteArray dequotedMessage = lowLevelDequote(message);
119
 
 
120
 
  CtcpType ctcptype = messageType == Message::Notice
121
 
    ? CtcpReply
122
 
    : CtcpQuery;
123
 
 
124
 
  Message::Flags flags = (messageType == Message::Notice && !network()->isChannelName(target))
125
 
    ? Message::Redirected
126
 
    : Message::None;
127
 
 
128
 
  // extract tagged / extended data
129
 
  int xdelimPos = -1;
130
 
  int xdelimEndPos = -1;
131
 
  int spacePos = -1;
132
 
  QList<QByteArray> replies;
133
 
  while((xdelimPos = dequotedMessage.indexOf(XDELIM)) != -1) {
134
 
    if(xdelimPos > 0)
135
 
      displayMsg(messageType, target, userDecode(target, dequotedMessage.left(xdelimPos)), prefix, flags);
136
 
 
137
 
    xdelimEndPos = dequotedMessage.indexOf(XDELIM, xdelimPos + 1);
138
 
    if(xdelimEndPos == -1) {
139
 
      // no matching end delimiter found... treat rest of the message as ctcp
140
 
      xdelimEndPos = dequotedMessage.count();
141
 
    }
142
 
    ctcp = xdelimDequote(dequotedMessage.mid(xdelimPos + 1, xdelimEndPos - xdelimPos - 1));
143
 
    dequotedMessage = dequotedMessage.mid(xdelimEndPos + 1);
144
 
 
145
 
    //dispatch the ctcp command
146
 
    QString ctcpcmd = userDecode(target, ctcp.left(spacePos));
147
 
    QString ctcpparam = userDecode(target, ctcp.mid(spacePos + 1));
148
 
 
149
 
    spacePos = ctcp.indexOf(' ');
150
 
    if(spacePos != -1) {
151
 
      ctcpcmd = userDecode(target, ctcp.left(spacePos));
152
 
      ctcpparam = userDecode(target, ctcp.mid(spacePos + 1));
153
 
    } else {
154
 
      ctcpcmd = userDecode(target, ctcp);
155
 
      ctcpparam = QString();
156
 
    }
157
 
 
158
 
    if(ctcpcmd.toUpper() == QLatin1String("ACTION") || !_ignoreListManager->ctcpMatch(prefix, network()->networkName(), ctcpcmd.toUpper())) {
159
 
      QString reply_;
160
 
      handle(ctcpcmd, Q_ARG(CtcpType, ctcptype), Q_ARG(QString, prefix), Q_ARG(QString, target), Q_ARG(QString, ctcpparam), Q_ARG(QString, reply_));
161
 
      if(ctcptype == CtcpQuery && !reply_.isNull()) {
162
 
        replies << lowLevelQuote(pack(serverEncode(ctcpcmd), userEncode(nickFromMask(prefix), reply_)));
163
 
      }
164
 
    }
165
 
  }
166
 
  if(ctcptype == CtcpQuery && !replies.isEmpty()) {
167
 
    packedReply(nickFromMask(prefix), replies);
168
 
  }
169
 
 
170
 
  if(!dequotedMessage.isEmpty())
171
 
    displayMsg(messageType, target, userDecode(target, dequotedMessage), prefix, flags);
172
 
}
173
 
 
174
 
QByteArray CtcpHandler::pack(const QByteArray &ctcpTag, const QByteArray &message) {
175
 
  if(message.isEmpty())
176
 
    return XDELIM + ctcpTag + XDELIM;
177
 
 
178
 
  return XDELIM + ctcpTag + ' ' + xdelimQuote(message) + XDELIM;
179
 
}
180
 
 
181
 
void CtcpHandler::query(const QString &bufname, const QString &ctcpTag, const QString &message) {
182
 
  QList<QByteArray> params;
183
 
  params << serverEncode(bufname) << lowLevelQuote(pack(serverEncode(ctcpTag), userEncode(bufname, message)));
184
 
  emit putCmd("PRIVMSG", params);
185
 
}
186
 
 
187
 
void CtcpHandler::reply(const QString &bufname, const QString &ctcpTag, const QString &message) {
188
 
  QList<QByteArray> params;
189
 
  params << serverEncode(bufname) << lowLevelQuote(pack(serverEncode(ctcpTag), userEncode(bufname, message)));
190
 
  emit putCmd("NOTICE", params);
191
 
}
192
 
 
193
 
void CtcpHandler::packedReply(const QString &bufname, const QList<QByteArray> &replies) {
194
 
  QList<QByteArray> params;
195
 
 
196
 
  int answerSize = 0;
197
 
  for(int i = 0; i < replies.count(); i++) {
198
 
    answerSize += replies.at(i).size();
199
 
  }
200
 
 
201
 
  QByteArray quotedReply;
202
 
  quotedReply.reserve(answerSize);
203
 
  for(int i = 0; i < replies.count(); i++) {
204
 
    quotedReply.append(replies.at(i));
205
 
  }
206
 
 
207
 
  params << serverEncode(bufname) << quotedReply;
208
 
  emit putCmd("NOTICE", params);
209
 
}
210
 
 
211
 
//******************************/
212
 
// CTCP HANDLER
213
 
//******************************/
214
 
void CtcpHandler::handleAction(CtcpType ctcptype, const QString &prefix, const QString &target, const QString &param, QString &/*reply*/) {
215
 
  Q_UNUSED(ctcptype)
216
 
  emit displayMsg(Message::Action, typeByTarget(target), target, param, prefix);
217
 
}
218
 
 
219
 
void CtcpHandler::handleClientinfo(CtcpType ctcptype, const QString &prefix, const QString &target, const QString &param, QString &reply) {
220
 
  Q_UNUSED(target)
221
 
  if(ctcptype == CtcpQuery) {
222
 
    QStringList supportedHandlers;
223
 
    foreach(QString handler, providesHandlers()) {
224
 
      supportedHandlers << handler.toUpper();
225
 
    }
226
 
    reply = supportedHandlers.join(" ");
227
 
    emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP CLIENTINFO request from %1").arg(prefix));
228
 
  } else {
229
 
    // display clientinfo answer
230
 
    emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP CLIENTINFO answer from %1: %2")
231
 
                    .arg(nickFromMask(prefix)).arg(param));
232
 
  }
233
 
}
234
 
 
235
 
void CtcpHandler::handlePing(CtcpType ctcptype, const QString &prefix, const QString &target, const QString &param, QString &reply) {
236
 
  Q_UNUSED(target)
237
 
  if(ctcptype == CtcpQuery) {
238
 
    reply = param;
239
 
    emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP PING request from %1").arg(prefix));
240
 
  } else {
241
 
    // display ping answer
242
 
    uint now = QDateTime::currentDateTime().toTime_t();
243
 
    uint then = QDateTime().fromTime_t(param.toInt()).toTime_t();
244
 
    emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP PING answer from %1 with %2 seconds round trip time")
245
 
                    .arg(nickFromMask(prefix)).arg(now-then));
246
 
  }
247
 
}
248
 
 
249
 
void CtcpHandler::handleVersion(CtcpType ctcptype, const QString &prefix, const QString &target, const QString &param, QString &reply) {
250
 
  Q_UNUSED(target)
251
 
  if(ctcptype == CtcpQuery) {
252
 
    reply = QString("Quassel IRC %1 (built on %2) -- http://www.quassel-irc.org").arg(Quassel::buildInfo().plainVersionString).arg(Quassel::buildInfo().buildDate);
253
 
    emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP VERSION request by %1").arg(prefix));
254
 
  } else {
255
 
    // display Version answer
256
 
    emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP VERSION answer from %1: %2")
257
 
                    .arg(nickFromMask(prefix)).arg(param));
258
 
  }
259
 
}
260
 
 
261
 
void CtcpHandler::handleTime(CtcpType ctcptype, const QString &prefix, const QString &target, const QString &param, QString &reply) {
262
 
  Q_UNUSED(target)
263
 
  if(ctcptype == CtcpQuery) {
264
 
    reply = QDateTime::currentDateTime().toString();
265
 
    emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP TIME request by %1").arg(prefix));
266
 
  } else {
267
 
    emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP TIME answer from %1: %2")
268
 
                    .arg(nickFromMask(prefix)).arg(param));
269
 
  }
270
 
}
271
 
 
272
 
void CtcpHandler::defaultHandler(const QString &cmd, CtcpType ctcptype, const QString &prefix, const QString &target, const QString &param, QString &reply) {
273
 
  Q_UNUSED(ctcptype);
274
 
  Q_UNUSED(target);
275
 
  Q_UNUSED(reply);
276
 
  QString str = tr("Received unknown CTCP %1 by %2").arg(cmd).arg(prefix);
277
 
  if(!param.isEmpty())
278
 
    str.append(tr(" with arguments: %1").arg(param));
279
 
  emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", str);
280
 
}
281