1 /***************************************************************************
2 * Copyright (C) 2005-08 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 // ====================
48 // ====================
49 bool IrcChannel::isKnownUser(IrcUser *ircuser) const {
51 qWarning() << "Channel" << name() << "received IrcUser Nullpointer!";
55 if(!_userModes.contains(ircuser)) {
56 qWarning() << "Channel" << name() << "received data for unknown User" << ircuser->nick();
63 bool IrcChannel::isValidChannelUserMode(const QString &mode) const {
66 qWarning() << "Channel" << name() << "received Channel User Mode which is longer then 1 Char:" << mode;
72 QString IrcChannel::userModes(IrcUser *ircuser) const {
73 if(_userModes.contains(ircuser))
74 return _userModes[ircuser];
79 QString IrcChannel::userModes(const QString &nick) const {
80 return userModes(network->ircUser(nick));
83 void IrcChannel::setCodecForEncoding(const QString &name) {
84 setCodecForEncoding(QTextCodec::codecForName(name.toAscii()));
87 void IrcChannel::setCodecForEncoding(QTextCodec *codec) {
88 _codecForEncoding = codec;
91 void IrcChannel::setCodecForDecoding(const QString &name) {
92 setCodecForDecoding(QTextCodec::codecForName(name.toAscii()));
95 void IrcChannel::setCodecForDecoding(QTextCodec *codec) {
96 _codecForDecoding = codec;
99 QString IrcChannel::decodeString(const QByteArray &text) const {
100 if(!codecForDecoding()) return network->decodeString(text);
101 return ::decodeString(text, _codecForDecoding);
104 QByteArray IrcChannel::encodeString(const QString &string) const {
105 if(codecForEncoding()) {
106 return _codecForEncoding->fromUnicode(string);
108 return network->encodeString(string);
111 // ====================
113 // ====================
114 void IrcChannel::setTopic(const QString &topic) {
116 emit topicSet(topic);
119 void IrcChannel::setPassword(const QString &password) {
120 _password = password;
121 emit passwordSet(password);
124 void IrcChannel::joinIrcUsers(const QList<IrcUser *> &users, const QStringList &modes) {
128 if(users.count() != modes.count()) {
129 qWarning() << "IrcChannel::addUsers(): number of nicks does not match number of modes!";
133 QStringList newNicks;
134 QStringList newModes;
135 QList<IrcUser *> newUsers;
138 for(int i = 0; i < users.count(); i++) {
140 if(!ircuser || _userModes.contains(ircuser)) {
141 addUserMode(ircuser, modes[i]);
145 _userModes[ircuser] = modes[i];
146 ircuser->joinChannel(this);
147 //qDebug() << "JOIN" << name() << ircuser->nick() << ircUsers().count();
148 connect(ircuser, SIGNAL(nickSet(QString)), this, SLOT(ircUserNickSet(QString)));
149 connect(ircuser, SIGNAL(destroyed()), this, SLOT(ircUserDestroyed()));
150 // if you wonder why there is no counterpart to ircUserJoined:
151 // the joines are propagted by the ircuser. the signal ircUserJoined is only for convenience
153 newNicks << ircuser->nick();
154 newModes << modes[i];
158 if(newNicks.isEmpty())
161 emit ircUsersJoined(newUsers);
162 emit ircUsersJoined(newNicks, newModes);
165 void IrcChannel::joinIrcUsers(const QStringList &nicks, const QStringList &modes) {
166 QList<IrcUser *> users;
167 foreach(QString nick, nicks)
168 users << network->newIrcUser(nick);
169 joinIrcUsers(users, modes);
172 void IrcChannel::joinIrcUsers(IrcUser *ircuser) {
173 QList <IrcUser *> users;
177 joinIrcUsers(users, modes);
180 void IrcChannel::joinIrcUsers(const QString &nick) {
181 joinIrcUsers(network->newIrcUser(nick));
184 void IrcChannel::part(IrcUser *ircuser) {
185 if(isKnownUser(ircuser)) {
186 _userModes.remove(ircuser);
187 ircuser->partChannel(this);
188 //qDebug() << "PART" << name() << ircuser->nick() << ircUsers().count();
189 // if you wonder why there is no counterpart to ircUserParted:
190 // the joines are propagted by the ircuser. the signal ircUserParted is only for convenience
191 disconnect(ircuser, 0, this, 0);
192 emit ircUserParted(ircuser);
193 if(network->isMe(ircuser))
198 void IrcChannel::part(const QString &nick) {
199 part(network->ircUser(nick));
203 void IrcChannel::setUserModes(IrcUser *ircuser, const QString &modes) {
204 if(isKnownUser(ircuser)) {
205 _userModes[ircuser] = modes;
206 emit userModesSet(ircuser->nick(), modes);
207 emit ircUserModesSet(ircuser, modes);
211 void IrcChannel::setUserModes(const QString &nick, const QString &modes) {
212 setUserModes(network->ircUser(nick), modes);
216 void IrcChannel::addUserMode(IrcUser *ircuser, const QString &mode) {
217 if(!isKnownUser(ircuser) || !isValidChannelUserMode(mode))
220 if(!_userModes[ircuser].contains(mode)) {
221 _userModes[ircuser] += mode;
222 emit userModeAdded(ircuser->nick(), mode);
223 emit ircUserModeAdded(ircuser, mode);
228 void IrcChannel::addUserMode(const QString &nick, const QString &mode) {
229 addUserMode(network->ircUser(nick), mode);
233 void IrcChannel::removeUserMode(IrcUser *ircuser, const QString &mode) {
234 if(!isKnownUser(ircuser) || !isValidChannelUserMode(mode))
237 if(_userModes[ircuser].contains(mode)) {
238 _userModes[ircuser].remove(mode);
239 emit userModeRemoved(ircuser->nick(), mode);
240 emit ircUserModeRemoved(ircuser, mode);
244 void IrcChannel::removeUserMode(const QString &nick, const QString &mode) {
245 removeUserMode(network->ircUser(nick), mode);
248 // INIT SET USER MODES
249 QVariantMap IrcChannel::initUserModes() const {
250 QVariantMap usermodes;
251 QHash<IrcUser *, QString>::const_iterator iter = _userModes.constBegin();
252 while(iter != _userModes.constEnd()) {
253 usermodes[iter.key()->nick()] = iter.value();
259 void IrcChannel::initSetUserModes(const QVariantMap &usermodes) {
260 QList<IrcUser *> users;
262 QVariantMap::const_iterator iter = usermodes.constBegin();
263 while(iter != usermodes.constEnd()) {
264 users << network->newIrcUser(iter.key());
265 modes << iter.value().toString();
268 joinIrcUsers(users, modes);
271 QVariantMap IrcChannel::initChanModes() const {
272 QVariantMap channelModes;
275 QHash<QChar, QStringList>::const_iterator A_iter = _A_channelModes.constBegin();
276 while(A_iter != _A_channelModes.constEnd()) {
277 A_modes[A_iter.key()] = A_iter.value();
280 channelModes["A"] = A_modes;
283 QHash<QChar, QString>::const_iterator B_iter = _B_channelModes.constBegin();
284 while(B_iter != _B_channelModes.constEnd()) {
285 B_modes[B_iter.key()] = B_iter.value();
288 channelModes["B"] = B_modes;
291 QHash<QChar, QString>::const_iterator C_iter = _C_channelModes.constBegin();
292 while(C_iter != _C_channelModes.constEnd()) {
293 C_modes[C_iter.key()] = C_iter.value();
296 channelModes["C"] = C_modes;
299 QSet<QChar>::const_iterator D_iter = _D_channelModes.constBegin();
300 while(D_iter != _D_channelModes.constEnd()) {
304 channelModes["D"] = D_modes;
309 void IrcChannel::initSetChanModes(const QVariantMap &channelModes) {
310 QVariantMap::const_iterator iter = channelModes["A"].toMap().constBegin();
311 QVariantMap::const_iterator iterEnd = channelModes["A"].toMap().constEnd();
312 while(iter != iterEnd) {
313 _A_channelModes[iter.key()[0]] = iter.value().toStringList();
317 iter = channelModes["B"].toMap().constBegin();
318 iterEnd = channelModes["B"].toMap().constEnd();
319 while(iter != iterEnd) {
320 _B_channelModes[iter.key()[0]] = iter.value().toString();
324 iter = channelModes["C"].toMap().constBegin();
325 iterEnd = channelModes["C"].toMap().constEnd();
326 while(iter != iterEnd) {
327 _C_channelModes[iter.key()[0]] = iter.value().toString();
331 QString D_modes = channelModes["D"].toString();
332 for(int i = 0; i < D_modes.count(); i++) {
333 _D_channelModes << D_modes[i];
338 void IrcChannel::ircUserDestroyed() {
339 IrcUser *ircUser = static_cast<IrcUser *>(sender());
341 _userModes.remove(ircUser);
342 // no further propagation.
343 // this leads only to fuck ups.
346 void IrcChannel::ircUserNickSet(QString nick) {
347 IrcUser *ircUser = qobject_cast<IrcUser *>(sender());
349 emit ircUserNickSet(ircUser, nick);
352 /*******************************************************************************
356 * o CHANMODES=A,B,C,D
358 * The CHANMODES token specifies the modes that may be set on a channel.
359 * These modes are split into four categories, as follows:
361 * o Type A: Modes that add or remove an address to or from a list.
362 * These modes always take a parameter when sent by the server to a
363 * client; when sent by a client, they may be specified without a
364 * parameter, which requests the server to display the current
365 * contents of the corresponding list on the channel to the client.
366 * o Type B: Modes that change a setting on the channel. These modes
367 * always take a parameter.
368 * o Type C: Modes that change a setting on the channel. These modes
369 * take a parameter only when set; the parameter is absent when the
370 * mode is removed both in the client's and server's MODE command.
371 * o Type D: Modes that change a setting on the channel. These modes
372 * never take a parameter.
374 * If the server sends any additional types after these 4, the client
375 * MUST ignore them; this is intended to allow future extension of this
378 * The IRC server MUST NOT list modes in CHANMODES which are also
379 * present in the PREFIX parameter; however, for completeness, modes
380 * described in PREFIX may be treated as type B modes.
382 ******************************************************************************/
385 /*******************************************************************************
387 * A --> add/remove from List
388 * B --> set value or remove
389 * C --> set value or remove
392 * B and C behave very similar... we store the data in different datastructes
393 * for future compatibility
394 ******************************************************************************/
396 // NOTE: the behavior of addChannelMode and removeChannelMode depends on the type of mode
397 // see list above for chanmode types
398 void IrcChannel::addChannelMode(const QChar &mode, const QString &value) {
399 Network::ChannelModeType modeType = network->channelModeType(mode);
402 case Network::NOT_A_CHANMODE:
404 case Network::A_CHANMODE:
405 if(!_A_channelModes.contains(mode))
406 _A_channelModes[mode] = QStringList(value);
407 else if(!_A_channelModes[mode].contains(value))
408 _A_channelModes[mode] << value;
411 case Network::B_CHANMODE:
412 _B_channelModes[mode] = value;
415 case Network::C_CHANMODE:
416 _C_channelModes[mode] = value;
419 case Network::D_CHANMODE:
420 _D_channelModes << mode;
423 emit channelModeAdded(mode, value);
426 void IrcChannel::removeChannelMode(const QChar &mode, const QString &value) {
427 Network::ChannelModeType modeType = network->channelModeType(mode);
430 case Network::NOT_A_CHANMODE:
432 case Network::A_CHANMODE:
433 if(_A_channelModes.contains(mode))
434 _A_channelModes[mode].removeAll(value);
437 case Network::B_CHANMODE:
438 _B_channelModes.remove(mode);
441 case Network::C_CHANMODE:
442 _C_channelModes.remove(mode);
445 case Network::D_CHANMODE:
446 _D_channelModes.remove(mode);
449 emit channelModeRemoved(mode, value);
452 bool IrcChannel::hasMode(const QChar &mode) const {
453 Network::ChannelModeType modeType = network->channelModeType(mode);
456 case Network::NOT_A_CHANMODE:
458 case Network::A_CHANMODE:
459 return _A_channelModes.contains(mode);
460 case Network::B_CHANMODE:
461 return _B_channelModes.contains(mode);
462 case Network::C_CHANMODE:
463 return _C_channelModes.contains(mode);
464 case Network::D_CHANMODE:
465 return _D_channelModes.contains(mode);
471 QString IrcChannel::modeValue(const QChar &mode) const {
472 Network::ChannelModeType modeType = network->channelModeType(mode);
475 case Network::B_CHANMODE:
476 if(_B_channelModes.contains(mode))
477 return _B_channelModes[mode];
480 case Network::C_CHANMODE:
481 if(_C_channelModes.contains(mode))
482 return _C_channelModes[mode];
491 QStringList IrcChannel::modeValueList(const QChar &mode) const {
492 Network::ChannelModeType modeType = network->channelModeType(mode);
495 case Network::A_CHANMODE:
496 if(_A_channelModes.contains(mode))
497 return _A_channelModes[mode];
499 return QStringList();
503 QString IrcChannel::channelModeString() const {
507 QSet<QChar>::const_iterator D_iter = _D_channelModes.constBegin();
508 while(D_iter != _D_channelModes.constEnd()) {
509 modeString += *D_iter;
513 QHash<QChar, QString>::const_iterator BC_iter = _C_channelModes.constBegin();
514 while(BC_iter != _C_channelModes.constEnd()) {
515 modeString += BC_iter.key();
516 params << BC_iter.value();
520 BC_iter = _B_channelModes.constBegin();
521 while(BC_iter != _B_channelModes.constEnd()) {
522 modeString += BC_iter.key();
523 params << BC_iter.value();
526 if(modeString.isEmpty())
529 return QString("+%1 %2").arg(modeString).arg(params.join(" "));