Autogenerate version.gen - no more outdated versions!
[quassel.git] / src / common / ircchannel.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-08 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
21 #include "ircchannel.h"
22
23 #include "network.h"
24 //#include "nicktreemodel.h"
25 #include "signalproxy.h"
26 #include "ircuser.h"
27 #include "util.h"
28
29 #include <QMapIterator>
30 #include <QHashIterator>
31 #include <QTextCodec>
32
33 #include <QDebug>
34
35
36 IrcChannel::IrcChannel(const QString &channelname, Network *network) : SyncableObject(network),
37     _initialized(false),
38     _name(channelname),
39     _topic(QString()),
40     network(network),
41     _codecForEncoding(0),
42     _codecForDecoding(0)
43 {
44   setObjectName(QString::number(network->networkId().toInt()) + "/" +  channelname);
45 }
46
47 IrcChannel::~IrcChannel() {
48 }
49
50 // ====================
51 //  PUBLIC:
52 // ====================
53 bool IrcChannel::isKnownUser(IrcUser *ircuser) const {
54   if(ircuser == 0) {
55     qWarning() << "Channel" << name() << "received IrcUser Nullpointer!";
56     return false;
57   }
58   
59   if(!_userModes.contains(ircuser)) {
60     qWarning() << "Channel" << name() << "received data for unknown User" << ircuser->nick();
61     return false;
62   }
63
64   return true;
65 }
66
67 bool IrcChannel::isValidChannelUserMode(const QString &mode) const {
68   bool isvalid = true;
69   if(mode.size() > 1) {
70     qWarning() << "Channel" << name() << "received Channel User Mode which is longer then 1 Char:" << mode;
71     isvalid = false;
72   }
73   return isvalid;
74 }
75
76 QString IrcChannel::userModes(IrcUser *ircuser) const {
77   if(_userModes.contains(ircuser))
78     return _userModes[ircuser];
79   else
80     return QString();
81 }
82
83 QString IrcChannel::userModes(const QString &nick) const {
84   return userModes(network->ircUser(nick));
85 }
86
87 void IrcChannel::setCodecForEncoding(const QString &name) {
88   setCodecForEncoding(QTextCodec::codecForName(name.toAscii()));
89 }
90
91 void IrcChannel::setCodecForEncoding(QTextCodec *codec) {
92   _codecForEncoding = codec;
93 }
94
95 void IrcChannel::setCodecForDecoding(const QString &name) {
96   setCodecForDecoding(QTextCodec::codecForName(name.toAscii()));
97 }
98
99 void IrcChannel::setCodecForDecoding(QTextCodec *codec) {
100   _codecForDecoding = codec;
101 }
102
103 QString IrcChannel::decodeString(const QByteArray &text) const {
104   if(!codecForDecoding()) return network->decodeString(text);
105   return ::decodeString(text, _codecForDecoding);
106 }
107
108 QByteArray IrcChannel::encodeString(const QString &string) const {
109   if(codecForEncoding()) {
110     return _codecForEncoding->fromUnicode(string);
111   }
112   return network->encodeString(string);
113 }
114
115 // ====================
116 //  PUBLIC SLOTS:
117 // ====================
118 void IrcChannel::setTopic(const QString &topic) {
119   _topic = topic;
120   emit topicSet(topic);
121 }
122
123 void IrcChannel::setPassword(const QString &password) {
124   _password = password;
125   emit passwordSet(password);
126 }
127
128 void IrcChannel::joinIrcUsers(const QList<IrcUser *> &users, const QStringList &modes) {
129   if(users.isEmpty())
130     return;
131
132   if(users.count() != modes.count()) {
133     qWarning() << "IrcChannel::addUsers(): number of nicks does not match number of modes!";
134     return;
135   }
136
137   QStringList newNicks;
138   QStringList newModes;
139   QList<IrcUser *> newUsers;
140
141   IrcUser *ircuser;
142   for(int i = 0; i < users.count(); i++) {
143     ircuser = users[i];
144     if(!ircuser || _userModes.contains(ircuser))
145       continue;
146
147     _userModes[ircuser] = modes[i];
148     ircuser->joinChannel(this);
149     //qDebug() << "JOIN" << name() << ircuser->nick() << ircUsers().count();
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
154
155     newNicks << ircuser->nick();
156     newModes << modes[i];
157     newUsers << ircuser;
158   }
159
160   if(newNicks.isEmpty())
161     return;
162   
163   emit ircUsersJoined(newUsers);
164   emit ircUsersJoined(newNicks, newModes);
165 }
166
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);
172 }
173                       
174 void IrcChannel::joinIrcUsers(IrcUser *ircuser) {
175   QList <IrcUser *> users;
176   users << ircuser;
177   QStringList modes;
178   modes << QString();
179   joinIrcUsers(users, modes);
180 }
181
182 void IrcChannel::joinIrcUsers(const QString &nick) {
183   joinIrcUsers(network->newIrcUser(nick));
184 }
185
186 void IrcChannel::part(IrcUser *ircuser) {
187   if(isKnownUser(ircuser)) {
188     _userModes.remove(ircuser);
189     ircuser->partChannel(this);
190     //qDebug() << "PART" << name() << ircuser->nick() << ircUsers().count();
191     // if you wonder why there is no counterpart to ircUserParted:
192     // the joines are propagted by the ircuser. the signal ircUserParted is only for convenience
193     disconnect(ircuser, 0, this, 0);
194     emit ircUserParted(ircuser);
195     if(network->isMe(ircuser))
196        deleteLater();
197   }
198 }
199
200 void IrcChannel::part(const QString &nick) {
201   part(network->ircUser(nick));
202 }
203
204 // SET USER MODE
205 void IrcChannel::setUserModes(IrcUser *ircuser, const QString &modes) {
206   if(isKnownUser(ircuser)) {
207     _userModes[ircuser] = modes;
208     emit userModesSet(ircuser->nick(), modes);
209     emit ircUserModesSet(ircuser, modes);
210   }
211 }
212
213 void IrcChannel::setUserModes(const QString &nick, const QString &modes) {
214   setUserModes(network->ircUser(nick), modes);
215 }
216
217 // ADD USER MODE
218 void IrcChannel::addUserMode(IrcUser *ircuser, const QString &mode) {
219   if(!isKnownUser(ircuser) || !isValidChannelUserMode(mode))
220     return;
221
222   if(!_userModes[ircuser].contains(mode)) {
223     _userModes[ircuser] += mode;
224     emit userModeAdded(ircuser->nick(), mode);
225     emit ircUserModeAdded(ircuser, mode);
226   }
227
228 }
229
230 void IrcChannel::addUserMode(const QString &nick, const QString &mode) {
231   addUserMode(network->ircUser(nick), mode);
232 }
233
234 // REMOVE USER MODE
235 void IrcChannel::removeUserMode(IrcUser *ircuser, const QString &mode) {
236   if(!isKnownUser(ircuser) || !isValidChannelUserMode(mode))
237     return;
238
239   if(_userModes[ircuser].contains(mode)) {
240     _userModes[ircuser].remove(mode);
241     emit userModeRemoved(ircuser->nick(), mode);
242     emit ircUserModeRemoved(ircuser, mode);
243   }
244
245 }
246
247 void IrcChannel::removeUserMode(const QString &nick, const QString &mode) {
248   removeUserMode(network->ircUser(nick), mode);
249 }
250
251 // INIT SET USER MODES
252 QVariantMap IrcChannel::initUserModes() const {
253   QVariantMap usermodes;
254   QHash<IrcUser *, QString>::const_iterator iter = _userModes.constBegin();
255   while(iter != _userModes.constEnd()) {
256     usermodes[iter.key()->nick()] = iter.value();
257     iter++;
258   }
259   return usermodes;
260 }
261
262 void IrcChannel::initSetUserModes(const QVariantMap &usermodes) {
263   QList<IrcUser *> users;
264   QStringList modes;
265   QVariantMap::const_iterator iter = usermodes.constBegin();
266   while(iter != usermodes.constEnd()) {
267     users << network->newIrcUser(iter.key());
268     modes << iter.value().toString();
269     iter++;
270   }
271   joinIrcUsers(users, modes);
272 }
273
274 void IrcChannel::ircUserDestroyed() {
275   IrcUser *ircUser = static_cast<IrcUser *>(sender());
276   Q_ASSERT(ircUser);
277   _userModes.remove(ircUser);
278   // no further propagation.
279   // this leads only to fuck ups.
280 }
281
282 void IrcChannel::ircUserNickSet(QString nick) {
283   IrcUser *ircUser = qobject_cast<IrcUser *>(sender());
284   Q_ASSERT(ircUser);
285   emit ircUserNickSet(ircUser, nick);
286 }
287