1 /***************************************************************************
2 * Copyright (C) 2005-09 by the Quassel Project *
3 * devel@quassel-irc.org *
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. *
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. *
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 ***************************************************************************/
21 #include "ircchannel.h"
27 #include <QMapIterator>
28 #include <QHashIterator>
34 IrcChannel::IrcChannel(const QString &channelname, Network *network)
35 : SyncableObject(network),
43 setObjectName(QString::number(network->networkId().toInt()) + "/" + channelname);
46 IrcChannel::~IrcChannel() {
49 // ====================
51 // ====================
52 bool IrcChannel::isKnownUser(IrcUser *ircuser) const {
54 qWarning() << "Channel" << name() << "received IrcUser Nullpointer!";
58 if(!_userModes.contains(ircuser)) {
59 qWarning() << "Channel" << name() << "received data for unknown User" << ircuser->nick();
66 bool IrcChannel::isValidChannelUserMode(const QString &mode) const {
69 qWarning() << "Channel" << name() << "received Channel User Mode which is longer then 1 Char:" << mode;
75 QString IrcChannel::userModes(IrcUser *ircuser) const {
76 if(_userModes.contains(ircuser))
77 return _userModes[ircuser];
82 QString IrcChannel::userModes(const QString &nick) const {
83 return userModes(network->ircUser(nick));
86 void IrcChannel::setCodecForEncoding(const QString &name) {
87 setCodecForEncoding(QTextCodec::codecForName(name.toAscii()));
90 void IrcChannel::setCodecForEncoding(QTextCodec *codec) {
91 _codecForEncoding = codec;
94 void IrcChannel::setCodecForDecoding(const QString &name) {
95 setCodecForDecoding(QTextCodec::codecForName(name.toAscii()));
98 void IrcChannel::setCodecForDecoding(QTextCodec *codec) {
99 _codecForDecoding = codec;
102 QString IrcChannel::decodeString(const QByteArray &text) const {
103 if(!codecForDecoding()) return network->decodeString(text);
104 return ::decodeString(text, _codecForDecoding);
107 QByteArray IrcChannel::encodeString(const QString &string) const {
108 if(codecForEncoding()) {
109 return _codecForEncoding->fromUnicode(string);
111 return network->encodeString(string);
114 // ====================
116 // ====================
117 void IrcChannel::setTopic(const QString &topic) {
119 emit topicSet(topic);
122 void IrcChannel::setPassword(const QString &password) {
123 _password = password;
124 emit passwordSet(password);
127 void IrcChannel::joinIrcUsers(const QList<IrcUser *> &users, const QStringList &modes) {
131 if(users.count() != modes.count()) {
132 qWarning() << "IrcChannel::addUsers(): number of nicks does not match number of modes!";
136 QStringList newNicks;
137 QStringList newModes;
138 QList<IrcUser *> newUsers;
141 for(int i = 0; i < users.count(); i++) {
143 if(!ircuser || _userModes.contains(ircuser)) {
144 addUserMode(ircuser, modes[i]);
148 _userModes[ircuser] = modes[i];
149 ircuser->joinChannel(this);
150 connect(ircuser, SIGNAL(nickSet(QString)), this, SLOT(ircUserNickSet(QString)));
151 // connect(ircuser, SIGNAL(destroyed()), this, SLOT(ircUserDestroyed()));
152 // if you wonder why there is no counterpart to ircUserJoined:
153 // the joines are propagted by the ircuser. the signal ircUserJoined is only for convenience
155 newNicks << ircuser->nick();
156 newModes << modes[i];
160 if(newNicks.isEmpty())
163 emit ircUsersJoined(newUsers);
164 emit ircUsersJoined(newNicks, newModes);
167 void IrcChannel::joinIrcUsers(const QStringList &nicks, const QStringList &modes) {
168 QList<IrcUser *> users;
169 foreach(QString nick, nicks)
170 users << network->newIrcUser(nick);
171 joinIrcUsers(users, modes);
174 void IrcChannel::joinIrcUsers(IrcUser *ircuser) {
175 QList <IrcUser *> users;
179 joinIrcUsers(users, modes);
182 void IrcChannel::joinIrcUsers(const QString &nick) {
183 joinIrcUsers(network->newIrcUser(nick));
186 void IrcChannel::part(IrcUser *ircuser) {
187 if(isKnownUser(ircuser)) {
188 _userModes.remove(ircuser);
189 ircuser->partChannel(this);
190 // if you wonder why there is no counterpart to ircUserParted:
191 // the joines are propagted by the ircuser. the signal ircUserParted is only for convenience
192 disconnect(ircuser, 0, this, 0);
193 emit ircUserParted(ircuser);
195 if(network->isMe(ircuser) || _userModes.isEmpty()) {
196 // in either case we're no longer in the channel
197 // -> clean up the channel and destroy it
198 QList<IrcUser *> users = _userModes.keys();
200 foreach(IrcUser *user, users) {
201 disconnect(user, 0, this, 0);
202 user->partChannel(this);
205 network->removeIrcChannel(this);
210 void IrcChannel::part(const QString &nick) {
211 part(network->ircUser(nick));
215 void IrcChannel::setUserModes(IrcUser *ircuser, const QString &modes) {
216 if(isKnownUser(ircuser)) {
217 _userModes[ircuser] = modes;
218 emit userModesSet(ircuser->nick(), modes);
219 emit ircUserModesSet(ircuser, modes);
223 void IrcChannel::setUserModes(const QString &nick, const QString &modes) {
224 setUserModes(network->ircUser(nick), modes);
228 void IrcChannel::addUserMode(IrcUser *ircuser, const QString &mode) {
229 if(!isKnownUser(ircuser) || !isValidChannelUserMode(mode))
232 if(!_userModes[ircuser].contains(mode)) {
233 _userModes[ircuser] += mode;
234 emit userModeAdded(ircuser->nick(), mode);
235 emit ircUserModeAdded(ircuser, mode);
240 void IrcChannel::addUserMode(const QString &nick, const QString &mode) {
241 addUserMode(network->ircUser(nick), mode);
245 void IrcChannel::removeUserMode(IrcUser *ircuser, const QString &mode) {
246 if(!isKnownUser(ircuser) || !isValidChannelUserMode(mode))
249 if(_userModes[ircuser].contains(mode)) {
250 _userModes[ircuser].remove(mode);
251 emit userModeRemoved(ircuser->nick(), mode);
252 emit ircUserModeRemoved(ircuser, mode);
256 void IrcChannel::removeUserMode(const QString &nick, const QString &mode) {
257 removeUserMode(network->ircUser(nick), mode);
260 // INIT SET USER MODES
261 QVariantMap IrcChannel::initUserModes() const {
262 QVariantMap usermodes;
263 QHash<IrcUser *, QString>::const_iterator iter = _userModes.constBegin();
264 while(iter != _userModes.constEnd()) {
265 usermodes[iter.key()->nick()] = iter.value();
271 void IrcChannel::initSetUserModes(const QVariantMap &usermodes) {
272 QList<IrcUser *> users;
274 QVariantMap::const_iterator iter = usermodes.constBegin();
275 while(iter != usermodes.constEnd()) {
276 users << network->newIrcUser(iter.key());
277 modes << iter.value().toString();
280 joinIrcUsers(users, modes);
283 QVariantMap IrcChannel::initChanModes() const {
284 QVariantMap channelModes;
287 QHash<QChar, QStringList>::const_iterator A_iter = _A_channelModes.constBegin();
288 while(A_iter != _A_channelModes.constEnd()) {
289 A_modes[A_iter.key()] = A_iter.value();
292 channelModes["A"] = A_modes;
295 QHash<QChar, QString>::const_iterator B_iter = _B_channelModes.constBegin();
296 while(B_iter != _B_channelModes.constEnd()) {
297 B_modes[B_iter.key()] = B_iter.value();
300 channelModes["B"] = B_modes;
303 QHash<QChar, QString>::const_iterator C_iter = _C_channelModes.constBegin();
304 while(C_iter != _C_channelModes.constEnd()) {
305 C_modes[C_iter.key()] = C_iter.value();
308 channelModes["C"] = C_modes;
311 QSet<QChar>::const_iterator D_iter = _D_channelModes.constBegin();
312 while(D_iter != _D_channelModes.constEnd()) {
316 channelModes["D"] = D_modes;
321 void IrcChannel::initSetChanModes(const QVariantMap &channelModes) {
322 QVariantMap::const_iterator iter = channelModes["A"].toMap().constBegin();
323 QVariantMap::const_iterator iterEnd = channelModes["A"].toMap().constEnd();
324 while(iter != iterEnd) {
325 _A_channelModes[iter.key()[0]] = iter.value().toStringList();
329 iter = channelModes["B"].toMap().constBegin();
330 iterEnd = channelModes["B"].toMap().constEnd();
331 while(iter != iterEnd) {
332 _B_channelModes[iter.key()[0]] = iter.value().toString();
336 iter = channelModes["C"].toMap().constBegin();
337 iterEnd = channelModes["C"].toMap().constEnd();
338 while(iter != iterEnd) {
339 _C_channelModes[iter.key()[0]] = iter.value().toString();
343 QString D_modes = channelModes["D"].toString();
344 for(int i = 0; i < D_modes.count(); i++) {
345 _D_channelModes << D_modes[i];
350 void IrcChannel::ircUserDestroyed() {
351 IrcUser *ircUser = static_cast<IrcUser *>(sender());
353 _userModes.remove(ircUser);
354 // no further propagation.
355 // this leads only to fuck ups.
358 void IrcChannel::ircUserNickSet(QString nick) {
359 IrcUser *ircUser = qobject_cast<IrcUser *>(sender());
361 emit ircUserNickSet(ircUser, nick);
364 /*******************************************************************************
368 * o CHANMODES=A,B,C,D
370 * The CHANMODES token specifies the modes that may be set on a channel.
371 * These modes are split into four categories, as follows:
373 * o Type A: Modes that add or remove an address to or from a list.
374 * These modes always take a parameter when sent by the server to a
375 * client; when sent by a client, they may be specified without a
376 * parameter, which requests the server to display the current
377 * contents of the corresponding list on the channel to the client.
378 * o Type B: Modes that change a setting on the channel. These modes
379 * always take a parameter.
380 * o Type C: Modes that change a setting on the channel. These modes
381 * take a parameter only when set; the parameter is absent when the
382 * mode is removed both in the client's and server's MODE command.
383 * o Type D: Modes that change a setting on the channel. These modes
384 * never take a parameter.
386 * If the server sends any additional types after these 4, the client
387 * MUST ignore them; this is intended to allow future extension of this
390 * The IRC server MUST NOT list modes in CHANMODES which are also
391 * present in the PREFIX parameter; however, for completeness, modes
392 * described in PREFIX may be treated as type B modes.
394 ******************************************************************************/
397 /*******************************************************************************
399 * A --> add/remove from List
400 * B --> set value or remove
401 * C --> set value or remove
404 * B and C behave very similar... we store the data in different datastructes
405 * for future compatibility
406 ******************************************************************************/
408 // NOTE: the behavior of addChannelMode and removeChannelMode depends on the type of mode
409 // see list above for chanmode types
410 void IrcChannel::addChannelMode(const QChar &mode, const QString &value) {
411 Network::ChannelModeType modeType = network->channelModeType(mode);
414 case Network::NOT_A_CHANMODE:
416 case Network::A_CHANMODE:
417 if(!_A_channelModes.contains(mode))
418 _A_channelModes[mode] = QStringList(value);
419 else if(!_A_channelModes[mode].contains(value))
420 _A_channelModes[mode] << value;
423 case Network::B_CHANMODE:
424 _B_channelModes[mode] = value;
427 case Network::C_CHANMODE:
428 _C_channelModes[mode] = value;
431 case Network::D_CHANMODE:
432 _D_channelModes << mode;
435 emit channelModeAdded(mode, value);
438 void IrcChannel::removeChannelMode(const QChar &mode, const QString &value) {
439 Network::ChannelModeType modeType = network->channelModeType(mode);
442 case Network::NOT_A_CHANMODE:
444 case Network::A_CHANMODE:
445 if(_A_channelModes.contains(mode))
446 _A_channelModes[mode].removeAll(value);
449 case Network::B_CHANMODE:
450 _B_channelModes.remove(mode);
453 case Network::C_CHANMODE:
454 _C_channelModes.remove(mode);
457 case Network::D_CHANMODE:
458 _D_channelModes.remove(mode);
461 emit channelModeRemoved(mode, value);
464 bool IrcChannel::hasMode(const QChar &mode) const {
465 Network::ChannelModeType modeType = network->channelModeType(mode);
468 case Network::NOT_A_CHANMODE:
470 case Network::A_CHANMODE:
471 return _A_channelModes.contains(mode);
472 case Network::B_CHANMODE:
473 return _B_channelModes.contains(mode);
474 case Network::C_CHANMODE:
475 return _C_channelModes.contains(mode);
476 case Network::D_CHANMODE:
477 return _D_channelModes.contains(mode);
483 QString IrcChannel::modeValue(const QChar &mode) const {
484 Network::ChannelModeType modeType = network->channelModeType(mode);
487 case Network::B_CHANMODE:
488 if(_B_channelModes.contains(mode))
489 return _B_channelModes[mode];
492 case Network::C_CHANMODE:
493 if(_C_channelModes.contains(mode))
494 return _C_channelModes[mode];
503 QStringList IrcChannel::modeValueList(const QChar &mode) const {
504 Network::ChannelModeType modeType = network->channelModeType(mode);
507 case Network::A_CHANMODE:
508 if(_A_channelModes.contains(mode))
509 return _A_channelModes[mode];
511 return QStringList();
515 QString IrcChannel::channelModeString() const {
519 QSet<QChar>::const_iterator D_iter = _D_channelModes.constBegin();
520 while(D_iter != _D_channelModes.constEnd()) {
521 modeString += *D_iter;
525 QHash<QChar, QString>::const_iterator BC_iter = _C_channelModes.constBegin();
526 while(BC_iter != _C_channelModes.constEnd()) {
527 modeString += BC_iter.key();
528 params << BC_iter.value();
532 BC_iter = _B_channelModes.constBegin();
533 while(BC_iter != _B_channelModes.constEnd()) {
534 modeString += BC_iter.key();
535 params << BC_iter.value();
538 if(modeString.isEmpty())
541 return QString("+%1 %2").arg(modeString).arg(params.join(" "));