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

1 by Harald Sitter
Import upstream version 0.2.0~beta1
1
/***************************************************************************
1.1.49 by Scott Kitterman
Import upstream version 0.9~beta1
2
 *   Copyright (C) 2005-2013 by the Quassel Project                        *
1 by Harald Sitter
Import upstream version 0.2.0~beta1
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.,                                       *
1.1.49 by Scott Kitterman
Import upstream version 0.9~beta1
18
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
1 by Harald Sitter
Import upstream version 0.2.0~beta1
19
 ***************************************************************************/
20
21
#include "ircchannel.h"
22
23
#include "network.h"
24
#include "ircuser.h"
25
#include "util.h"
26
27
#include <QMapIterator>
28
#include <QHashIterator>
29
#include <QTextCodec>
30
31
#include <QDebug>
32
1.1.23 by Scott Kitterman
Import upstream version 0.5.0~rc1
33
INIT_SYNCABLE_OBJECT(IrcChannel)
1.1.1 by Harald Sitter
Import upstream version 0.2.0~rc1
34
IrcChannel::IrcChannel(const QString &channelname, Network *network)
1.1.49 by Scott Kitterman
Import upstream version 0.9~beta1
35
    : SyncableObject(network),
1 by Harald Sitter
Import upstream version 0.2.0~beta1
36
    _initialized(false),
37
    _name(channelname),
38
    _topic(QString()),
1.1.52 by Scott Kitterman
Import upstream version 0.9.1
39
    _encrypted(false),
1.1.40 by Scott Kitterman
Import upstream version 0.7~beta1
40
    _network(network),
1 by Harald Sitter
Import upstream version 0.2.0~beta1
41
    _codecForEncoding(0),
42
    _codecForDecoding(0)
43
{
1.1.49 by Scott Kitterman
Import upstream version 0.9~beta1
44
    setObjectName(QString::number(network->networkId().toInt()) + "/" +  channelname);
45
}
46
47
48
IrcChannel::~IrcChannel()
49
{
50
}
51
1.1.4 by Scott Kitterman
Import upstream version 0.4.0~git090110
52
1 by Harald Sitter
Import upstream version 0.2.0~beta1
53
// ====================
54
//  PUBLIC:
55
// ====================
1.1.49 by Scott Kitterman
Import upstream version 0.9~beta1
56
bool IrcChannel::isKnownUser(IrcUser *ircuser) const
57
{
58
    if (ircuser == 0) {
59
        qWarning() << "Channel" << name() << "received IrcUser Nullpointer!";
60
        return false;
61
    }
62
63
    if (!_userModes.contains(ircuser)) {
64
        qWarning() << "Channel" << name() << "received data for unknown User" << ircuser->nick();
65
        return false;
66
    }
67
68
    return true;
69
}
70
71
72
bool IrcChannel::isValidChannelUserMode(const QString &mode) const
73
{
74
    bool isvalid = true;
75
    if (mode.size() > 1) {
76
        qWarning() << "Channel" << name() << "received Channel User Mode which is longer then 1 Char:" << mode;
77
        isvalid = false;
78
    }
79
    return isvalid;
80
}
81
82
83
QString IrcChannel::userModes(IrcUser *ircuser) const
84
{
85
    if (_userModes.contains(ircuser))
86
        return _userModes[ircuser];
87
    else
88
        return QString();
89
}
90
91
92
QString IrcChannel::userModes(const QString &nick) const
93
{
94
    return userModes(network()->ircUser(nick));
95
}
96
97
98
void IrcChannel::setCodecForEncoding(const QString &name)
99
{
100
    setCodecForEncoding(QTextCodec::codecForName(name.toAscii()));
101
}
102
103
104
void IrcChannel::setCodecForEncoding(QTextCodec *codec)
105
{
106
    _codecForEncoding = codec;
107
}
108
109
110
void IrcChannel::setCodecForDecoding(const QString &name)
111
{
112
    setCodecForDecoding(QTextCodec::codecForName(name.toAscii()));
113
}
114
115
116
void IrcChannel::setCodecForDecoding(QTextCodec *codec)
117
{
118
    _codecForDecoding = codec;
119
}
120
121
122
QString IrcChannel::decodeString(const QByteArray &text) const
123
{
124
    if (!codecForDecoding()) return network()->decodeString(text);
125
    return ::decodeString(text, _codecForDecoding);
126
}
127
128
129
QByteArray IrcChannel::encodeString(const QString &string) const
130
{
131
    if (codecForEncoding()) {
132
        return _codecForEncoding->fromUnicode(string);
133
    }
134
    return network()->encodeString(string);
135
}
136
1 by Harald Sitter
Import upstream version 0.2.0~beta1
137
138
// ====================
139
//  PUBLIC SLOTS:
140
// ====================
1.1.49 by Scott Kitterman
Import upstream version 0.9~beta1
141
void IrcChannel::setTopic(const QString &topic)
142
{
143
    _topic = topic;
144
    SYNC(ARG(topic))
145
    emit topicSet(topic);
146
}
147
148
149
void IrcChannel::setPassword(const QString &password)
150
{
151
    _password = password;
152
    SYNC(ARG(password))
153
}
154
1.1.52 by Scott Kitterman
Import upstream version 0.9.1
155
void IrcChannel::setEncrypted(bool encrypted)
156
{
157
    _encrypted = encrypted;
158
    SYNC(ARG(encrypted))
159
    emit encryptedSet(encrypted);
160
}
161
1.1.49 by Scott Kitterman
Import upstream version 0.9~beta1
162
163
void IrcChannel::joinIrcUsers(const QList<IrcUser *> &users, const QStringList &modes)
164
{
165
    if (users.isEmpty())
166
        return;
167
168
    if (users.count() != modes.count()) {
169
        qWarning() << "IrcChannel::addUsers(): number of nicks does not match number of modes!";
170
        return;
171
    }
172
173
    QStringList newNicks;
174
    QStringList newModes;
175
    QList<IrcUser *> newUsers;
176
177
    IrcUser *ircuser;
178
    for (int i = 0; i < users.count(); i++) {
179
        ircuser = users[i];
180
        if (!ircuser || _userModes.contains(ircuser)) {
181
            addUserMode(ircuser, modes[i]);
182
            continue;
183
        }
184
185
        _userModes[ircuser] = modes[i];
186
        ircuser->joinChannel(this);
187
        connect(ircuser, SIGNAL(nickSet(QString)), this, SLOT(ircUserNickSet(QString)));
188
189
        // connect(ircuser, SIGNAL(destroyed()), this, SLOT(ircUserDestroyed()));
190
        // if you wonder why there is no counterpart to ircUserJoined:
191
        // the joines are propagted by the ircuser. the signal ircUserJoined is only for convenience
192
193
        newNicks << ircuser->nick();
194
        newModes << modes[i];
195
        newUsers << ircuser;
196
    }
197
198
    if (newNicks.isEmpty())
199
        return;
200
201
    SYNC_OTHER(joinIrcUsers, ARG(newNicks), ARG(newModes));
202
    emit ircUsersJoined(newUsers);
203
}
204
205
206
void IrcChannel::joinIrcUsers(const QStringList &nicks, const QStringList &modes)
207
{
208
    QList<IrcUser *> users;
209
    foreach(QString nick, nicks)
1.1.40 by Scott Kitterman
Import upstream version 0.7~beta1
210
    users << network()->newIrcUser(nick);
1.1.49 by Scott Kitterman
Import upstream version 0.9~beta1
211
    joinIrcUsers(users, modes);
212
}
213
214
215
void IrcChannel::joinIrcUser(IrcUser *ircuser)
216
{
217
    QList<IrcUser *> users;
218
    users << ircuser;
219
    QStringList modes;
220
    modes << QString();
221
    joinIrcUsers(users, modes);
222
}
223
224
225
void IrcChannel::part(IrcUser *ircuser)
226
{
227
    if (isKnownUser(ircuser)) {
228
        _userModes.remove(ircuser);
229
        ircuser->partChannel(this);
230
        // if you wonder why there is no counterpart to ircUserParted:
231
        // the joines are propagted by the ircuser. the signal ircUserParted is only for convenience
232
        disconnect(ircuser, 0, this, 0);
233
        emit ircUserParted(ircuser);
234
235
        if (network()->isMe(ircuser) || _userModes.isEmpty()) {
236
            // in either case we're no longer in the channel
237
            //  -> clean up the channel and destroy it
238
            QList<IrcUser *> users = _userModes.keys();
239
            _userModes.clear();
240
            foreach(IrcUser *user, users) {
241
                disconnect(user, 0, this, 0);
242
                user->partChannel(this);
243
            }
244
            emit parted();
245
            network()->removeIrcChannel(this);
246
        }
1.1.4 by Scott Kitterman
Import upstream version 0.4.0~git090110
247
    }
1.1.49 by Scott Kitterman
Import upstream version 0.9~beta1
248
}
249
250
251
void IrcChannel::part(const QString &nick)
252
{
253
    part(network()->ircUser(nick));
254
}
255
1 by Harald Sitter
Import upstream version 0.2.0~beta1
256
257
// SET USER MODE
1.1.49 by Scott Kitterman
Import upstream version 0.9~beta1
258
void IrcChannel::setUserModes(IrcUser *ircuser, const QString &modes)
259
{
260
    if (isKnownUser(ircuser)) {
261
        _userModes[ircuser] = modes;
262
        QString nick = ircuser->nick();
263
        SYNC_OTHER(setUserModes, ARG(nick), ARG(modes))
264
        emit ircUserModesSet(ircuser, modes);
265
    }
266
}
267
268
269
void IrcChannel::setUserModes(const QString &nick, const QString &modes)
270
{
271
    setUserModes(network()->ircUser(nick), modes);
272
}
273
1 by Harald Sitter
Import upstream version 0.2.0~beta1
274
275
// ADD USER MODE
1.1.49 by Scott Kitterman
Import upstream version 0.9~beta1
276
void IrcChannel::addUserMode(IrcUser *ircuser, const QString &mode)
277
{
278
    if (!isKnownUser(ircuser) || !isValidChannelUserMode(mode))
279
        return;
280
281
    if (!_userModes[ircuser].contains(mode)) {
282
        _userModes[ircuser] += mode;
283
        QString nick = ircuser->nick();
284
        SYNC_OTHER(addUserMode, ARG(nick), ARG(mode))
285
        emit ircUserModeAdded(ircuser, mode);
286
    }
287
}
288
289
290
void IrcChannel::addUserMode(const QString &nick, const QString &mode)
291
{
292
    addUserMode(network()->ircUser(nick), mode);
293
}
294
1 by Harald Sitter
Import upstream version 0.2.0~beta1
295
296
// REMOVE USER MODE
1.1.49 by Scott Kitterman
Import upstream version 0.9~beta1
297
void IrcChannel::removeUserMode(IrcUser *ircuser, const QString &mode)
298
{
299
    if (!isKnownUser(ircuser) || !isValidChannelUserMode(mode))
300
        return;
301
302
    if (_userModes[ircuser].contains(mode)) {
303
        _userModes[ircuser].remove(mode);
304
        QString nick = ircuser->nick();
305
        SYNC_OTHER(removeUserMode, ARG(nick), ARG(mode));
306
        emit ircUserModeRemoved(ircuser, mode);
307
    }
308
}
309
310
311
void IrcChannel::removeUserMode(const QString &nick, const QString &mode)
312
{
313
    removeUserMode(network()->ircUser(nick), mode);
314
}
315
1 by Harald Sitter
Import upstream version 0.2.0~beta1
316
317
// INIT SET USER MODES
1.1.49 by Scott Kitterman
Import upstream version 0.9~beta1
318
QVariantMap IrcChannel::initUserModes() const
319
{
320
    QVariantMap usermodes;
321
    QHash<IrcUser *, QString>::const_iterator iter = _userModes.constBegin();
322
    while (iter != _userModes.constEnd()) {
323
        usermodes[iter.key()->nick()] = iter.value();
324
        iter++;
325
    }
326
    return usermodes;
327
}
328
329
330
void IrcChannel::initSetUserModes(const QVariantMap &usermodes)
331
{
332
    QList<IrcUser *> users;
333
    QStringList modes;
334
    QVariantMap::const_iterator iter = usermodes.constBegin();
335
    while (iter != usermodes.constEnd()) {
336
        users << network()->newIrcUser(iter.key());
337
        modes << iter.value().toString();
338
        iter++;
339
    }
340
    joinIrcUsers(users, modes);
341
}
342
343
344
QVariantMap IrcChannel::initChanModes() const
345
{
346
    QVariantMap channelModes;
347
348
    QVariantMap A_modes;
349
    QHash<QChar, QStringList>::const_iterator A_iter = _A_channelModes.constBegin();
350
    while (A_iter != _A_channelModes.constEnd()) {
351
        A_modes[A_iter.key()] = A_iter.value();
352
        A_iter++;
353
    }
354
    channelModes["A"] = A_modes;
355
356
    QVariantMap B_modes;
357
    QHash<QChar, QString>::const_iterator B_iter = _B_channelModes.constBegin();
358
    while (B_iter != _B_channelModes.constEnd()) {
359
        B_modes[B_iter.key()] = B_iter.value();
360
        B_iter++;
361
    }
362
    channelModes["B"] = B_modes;
363
364
    QVariantMap C_modes;
365
    QHash<QChar, QString>::const_iterator C_iter = _C_channelModes.constBegin();
366
    while (C_iter != _C_channelModes.constEnd()) {
367
        C_modes[C_iter.key()] = C_iter.value();
368
        C_iter++;
369
    }
370
    channelModes["C"] = C_modes;
371
372
    QString D_modes;
373
    QSet<QChar>::const_iterator D_iter = _D_channelModes.constBegin();
374
    while (D_iter != _D_channelModes.constEnd()) {
375
        D_modes += *D_iter;
376
        D_iter++;
377
    }
378
    channelModes["D"] = D_modes;
379
380
    return channelModes;
381
}
382
383
384
void IrcChannel::initSetChanModes(const QVariantMap &channelModes)
385
{
386
    QVariantMap::const_iterator iter = channelModes["A"].toMap().constBegin();
387
    QVariantMap::const_iterator iterEnd = channelModes["A"].toMap().constEnd();
388
    while (iter != iterEnd) {
389
        _A_channelModes[iter.key()[0]] = iter.value().toStringList();
390
        iter++;
391
    }
392
393
    iter = channelModes["B"].toMap().constBegin();
394
    iterEnd = channelModes["B"].toMap().constEnd();
395
    while (iter != iterEnd) {
396
        _B_channelModes[iter.key()[0]] = iter.value().toString();
397
        iter++;
398
    }
399
400
    iter = channelModes["C"].toMap().constBegin();
401
    iterEnd = channelModes["C"].toMap().constEnd();
402
    while (iter != iterEnd) {
403
        _C_channelModes[iter.key()[0]] = iter.value().toString();
404
        iter++;
405
    }
406
407
    QString D_modes = channelModes["D"].toString();
408
    for (int i = 0; i < D_modes.count(); i++) {
409
        _D_channelModes << D_modes[i];
410
    }
411
}
412
413
414
void IrcChannel::ircUserDestroyed()
415
{
416
    IrcUser *ircUser = static_cast<IrcUser *>(sender());
417
    Q_ASSERT(ircUser);
418
    _userModes.remove(ircUser);
419
    // no further propagation.
420
    // this leads only to fuck ups.
421
}
422
423
424
void IrcChannel::ircUserNickSet(QString nick)
425
{
426
    IrcUser *ircUser = qobject_cast<IrcUser *>(sender());
427
    Q_ASSERT(ircUser);
428
    emit ircUserNickSet(ircUser, nick);
429
}
430
1 by Harald Sitter
Import upstream version 0.2.0~beta1
431
1.1.1 by Harald Sitter
Import upstream version 0.2.0~rc1
432
/*******************************************************************************
433
 *
434
 * 3.3 CHANMODES
1.1.40 by Scott Kitterman
Import upstream version 0.7~beta1
435
 *
1.1.1 by Harald Sitter
Import upstream version 0.2.0~rc1
436
 *    o  CHANMODES=A,B,C,D
1.1.40 by Scott Kitterman
Import upstream version 0.7~beta1
437
 *
1.1.1 by Harald Sitter
Import upstream version 0.2.0~rc1
438
 *    The CHANMODES token specifies the modes that may be set on a channel.
439
 *    These modes are split into four categories, as follows:
1.1.40 by Scott Kitterman
Import upstream version 0.7~beta1
440
 *
1.1.1 by Harald Sitter
Import upstream version 0.2.0~rc1
441
 *    o  Type A: Modes that add or remove an address to or from a list.
442
 *       These modes always take a parameter when sent by the server to a
443
 *       client; when sent by a client, they may be specified without a
444
 *       parameter, which requests the server to display the current
445
 *       contents of the corresponding list on the channel to the client.
446
 *    o  Type B: Modes that change a setting on the channel.  These modes
447
 *       always take a parameter.
448
 *    o  Type C: Modes that change a setting on the channel. These modes
449
 *       take a parameter only when set; the parameter is absent when the
450
 *       mode is removed both in the client's and server's MODE command.
451
 *    o  Type D: Modes that change a setting on the channel. These modes
452
 *       never take a parameter.
1.1.40 by Scott Kitterman
Import upstream version 0.7~beta1
453
 *
1.1.1 by Harald Sitter
Import upstream version 0.2.0~rc1
454
 *    If the server sends any additional types after these 4, the client
455
 *    MUST ignore them; this is intended to allow future extension of this
456
 *    token.
1.1.40 by Scott Kitterman
Import upstream version 0.7~beta1
457
 *
1.1.1 by Harald Sitter
Import upstream version 0.2.0~rc1
458
 *    The IRC server MUST NOT list modes in CHANMODES which are also
459
 *    present in the PREFIX parameter; however, for completeness, modes
460
 *    described in PREFIX may be treated as type B modes.
461
 *
462
 ******************************************************************************/
463
464
/*******************************************************************************
465
 * Short Version:
466
 * A --> add/remove from List
467
 * B --> set value or remove
468
 * C --> set value or remove
469
 * D --> on/off
470
 *
471
 * B and C behave very similar... we store the data in different datastructes
472
 * for future compatibility
473
 ******************************************************************************/
474
475
// NOTE: the behavior of addChannelMode and removeChannelMode depends on the type of mode
476
// see list above for chanmode types
1.1.49 by Scott Kitterman
Import upstream version 0.9~beta1
477
void IrcChannel::addChannelMode(const QChar &mode, const QString &value)
478
{
479
    Network::ChannelModeType modeType = network()->channelModeType(mode);
480
481
    switch (modeType) {
482
    case Network::NOT_A_CHANMODE:
483
        return;
484
    case Network::A_CHANMODE:
485
        if (!_A_channelModes.contains(mode))
486
            _A_channelModes[mode] = QStringList(value);
487
        else if (!_A_channelModes[mode].contains(value))
488
            _A_channelModes[mode] << value;
489
        break;
490
491
    case Network::B_CHANMODE:
492
        _B_channelModes[mode] = value;
493
        break;
494
495
    case Network::C_CHANMODE:
496
        _C_channelModes[mode] = value;
497
        break;
498
499
    case Network::D_CHANMODE:
500
        _D_channelModes << mode;
501
        break;
502
    }
503
    SYNC(ARG(mode), ARG(value))
504
}
505
506
507
void IrcChannel::removeChannelMode(const QChar &mode, const QString &value)
508
{
509
    Network::ChannelModeType modeType = network()->channelModeType(mode);
510
511
    switch (modeType) {
512
    case Network::NOT_A_CHANMODE:
513
        return;
514
    case Network::A_CHANMODE:
515
        if (_A_channelModes.contains(mode))
516
            _A_channelModes[mode].removeAll(value);
517
        break;
518
519
    case Network::B_CHANMODE:
520
        _B_channelModes.remove(mode);
521
        break;
522
523
    case Network::C_CHANMODE:
524
        _C_channelModes.remove(mode);
525
        break;
526
527
    case Network::D_CHANMODE:
528
        _D_channelModes.remove(mode);
529
        break;
530
    }
531
    SYNC(ARG(mode), ARG(value))
532
}
533
534
535
bool IrcChannel::hasMode(const QChar &mode) const
536
{
537
    Network::ChannelModeType modeType = network()->channelModeType(mode);
538
539
    switch (modeType) {
540
    case Network::NOT_A_CHANMODE:
541
        return false;
542
    case Network::A_CHANMODE:
543
        return _A_channelModes.contains(mode);
544
    case Network::B_CHANMODE:
545
        return _B_channelModes.contains(mode);
546
    case Network::C_CHANMODE:
547
        return _C_channelModes.contains(mode);
548
    case Network::D_CHANMODE:
549
        return _D_channelModes.contains(mode);
550
    default:
551
        return false;
552
    }
553
}
554
555
556
QString IrcChannel::modeValue(const QChar &mode) const
557
{
558
    Network::ChannelModeType modeType = network()->channelModeType(mode);
559
560
    switch (modeType) {
561
    case Network::B_CHANMODE:
562
        if (_B_channelModes.contains(mode))
563
            return _B_channelModes[mode];
564
        else
565
            return QString();
566
    case Network::C_CHANMODE:
567
        if (_C_channelModes.contains(mode))
568
            return _C_channelModes[mode];
569
        else
570
            return QString();
571
    default:
572
        return QString();
573
    }
574
}
575
576
577
QStringList IrcChannel::modeValueList(const QChar &mode) const
578
{
579
    Network::ChannelModeType modeType = network()->channelModeType(mode);
580
581
    switch (modeType) {
582
    case Network::A_CHANMODE:
583
        if (_A_channelModes.contains(mode))
584
            return _A_channelModes[mode];
585
    default:
586
        return QStringList();
587
    }
588
}
589
590
591
QString IrcChannel::channelModeString() const
592
{
593
    QStringList params;
594
    QString modeString;
595
596
    QSet<QChar>::const_iterator D_iter = _D_channelModes.constBegin();
597
    while (D_iter != _D_channelModes.constEnd()) {
598
        modeString += *D_iter;
599
        D_iter++;
600
    }
601
602
    QHash<QChar, QString>::const_iterator BC_iter = _C_channelModes.constBegin();
603
    while (BC_iter != _C_channelModes.constEnd()) {
604
        modeString += BC_iter.key();
605
        params << BC_iter.value();
606
        BC_iter++;
607
    }
608
609
    BC_iter = _B_channelModes.constBegin();
610
    while (BC_iter != _B_channelModes.constEnd()) {
611
        modeString += BC_iter.key();
612
        params << BC_iter.value();
613
        BC_iter++;
614
    }
615
    if (modeString.isEmpty())
616
        return modeString;
617
    else
618
        return QString("+%1 %2").arg(modeString).arg(params.join(" "));
1.1.1 by Harald Sitter
Import upstream version 0.2.0~rc1
619
}