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