#include "client.h"
 #include "identity.h"
-#include "ircuser.h"
-#include "ircchannel.h"
 #include "network.h"
 #include "networkmodel.h"
 #include "quassel.h"
 
 
 void QueryBufferItem::attachIrcUser(IrcUser *ircUser) {
   _ircUser = ircUser;
-  connect(_ircUser, SIGNAL(destroyed()), this, SLOT(ircUserDestroyed()));
+  connect(_ircUser, SIGNAL(quited()), this, SLOT(ircUserQuited()));
   connect(_ircUser, SIGNAL(awaySet(bool)), this, SIGNAL(dataChanged()));
   emit dataChanged();
 }
 
-void QueryBufferItem::ircUserDestroyed() {
+void QueryBufferItem::ircUserQuited() {
   _ircUser = 0;
   emit dataChanged();
 }
          this, SLOT(join(QList<IrcUser *>)));
   connect(ircChannel, SIGNAL(ircUserParted(IrcUser *)),
          this, SLOT(part(IrcUser *)));
-  connect(ircChannel, SIGNAL(destroyed()),
-         this, SLOT(ircChannelDestroyed()));
+  connect(ircChannel, SIGNAL(parted()),
+         this, SLOT(ircChannelParted()));
   connect(ircChannel, SIGNAL(ircUserModesSet(IrcUser *, QString)),
          this, SLOT(userModeChanged(IrcUser *)));
   connect(ircChannel, SIGNAL(ircUserModeAdded(IrcUser *, QString)),
   emit dataChanged();
 }
 
-void ChannelBufferItem::ircChannelDestroyed() {
+void ChannelBufferItem::ircChannelParted() {
   Q_CHECK_PTR(_ircChannel);
   disconnect(_ircChannel, 0, this, 0);
   _ircChannel = 0;
     _ircUser(ircUser)
 {
   setObjectName(ircUser->nick());
-  connect(ircUser, SIGNAL(destroyed()), this, SLOT(ircUserDestroyed()));
+  connect(ircUser, SIGNAL(quited()), this, SLOT(ircUserQuited()));
   connect(ircUser, SIGNAL(nickSet(QString)), this, SIGNAL(dataChanged()));
   connect(ircUser, SIGNAL(awaySet(bool)), this, SIGNAL(dataChanged()));
 }
   return QString("<p> %1 </p>").arg(toolTip.join("<br />"));
 }
 
-// void IrcUserItem::ircUserDestroyed() {
-//   parent()->removeChild(this);
-//   if(parent()->childCount() == 0)
-//     parent()->parent()->removeChild(parent());
-// }
-
 /*****************************************
  * NetworkModel
  *****************************************/
 
 
 public slots:
   void attachIrcUser(IrcUser *ircUser);
-  void ircUserDestroyed();
+  void ircUserQuited();
 
 private:
   IrcUser *_ircUser;
   void userModeChanged(IrcUser *ircUser);
 
 private slots:
-  void ircChannelDestroyed();
+  void ircChannelParted();
 
 private:
   IrcChannel *_ircChannel;
   virtual QString toolTip(int column) const;
 
 private slots:
-  inline void ircUserDestroyed() { parent()->removeChild(this); }
+  inline void ircUserQuited() { parent()->removeChild(this); }
 
 private:
   QPointer<IrcUser> _ircUser;
 
   setObjectName(QString::number(network->networkId().toInt()) + "/" +  channelname);
 }
 
+IrcChannel::~IrcChannel() {
+}
+
 // ====================
 //  PUBLIC:
 // ====================
 
     _userModes[ircuser] = modes[i];
     ircuser->joinChannel(this);
-    //qDebug() << "JOIN" << name() << ircuser->nick() << ircUsers().count();
     connect(ircuser, SIGNAL(nickSet(QString)), this, SLOT(ircUserNickSet(QString)));
-    connect(ircuser, SIGNAL(destroyed()), this, SLOT(ircUserDestroyed()));
+    // connect(ircuser, SIGNAL(destroyed()), this, SLOT(ircUserDestroyed()));
     // if you wonder why there is no counterpart to ircUserJoined:
     // the joines are propagted by the ircuser. the signal ircUserJoined is only for convenience
 
   if(isKnownUser(ircuser)) {
     _userModes.remove(ircuser);
     ircuser->partChannel(this);
-    //qDebug() << "PART" << name() << ircuser->nick() << ircUsers().count();
     // if you wonder why there is no counterpart to ircUserParted:
     // the joines are propagted by the ircuser. the signal ircUserParted is only for convenience
     disconnect(ircuser, 0, this, 0);
     emit ircUserParted(ircuser);
-    if(network->isMe(ircuser))
-       deleteLater();
+    
+    if(network->isMe(ircuser)) {
+      // we left -> clean up the channel and destroy it
+      QList<IrcUser *> users = _userModes.keys();
+      _userModes.clear();
+      foreach(IrcUser *user, users) {
+       disconnect(user, 0, this, 0);
+       user->partChannel(this);
+      }
+      emit parted();
+      network->removeIrcChannel(this);
+    }
   }
 }
 
 
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
-#ifndef _IRCCHANNEL_H_
-#define _IRCCHANNEL_H_
+#ifndef IRCCHANNEL_H
+#define IRCCHANNEL_H
 
 #include <QHash>
 #include <QSet>
 
 public:
   IrcChannel(const QString &channelname, Network *network);
+  ~IrcChannel();
 
   bool isKnownUser(IrcUser *ircuser) const;
   bool isValidChannelUserMode(const QString &mode) const;
   void ircUserModeRemoved(IrcUser *ircuser, QString mode);
   void ircUserModesSet(IrcUser *ircuser, QString modes);
 
+  void parted(); // convenience signal emitted before channels destruction
+
 private slots:
    void ircUserDestroyed();
    void ircUserNickSet(QString nick);
 
   if(!_channels.contains(channel)) {
     _channels.insert(channel);
     channel->joinIrcUsers(this);
-    connect(channel, SIGNAL(destroyed()), this, SLOT(channelDestroyed()));
+    // connect(channel, SIGNAL(destroyed()), this, SLOT(channelDestroyed()));
   }
 }
 
     channel->part(this);
     emit channelParted(channel->name());
     if(_channels.isEmpty() && !network()->isMe(this))
-      deleteLater();
+      quit();
   }
 }
 
   }
 }
 
+void IrcUser::quit() {
+  QList<IrcChannel *> channels = _channels.toList();
+  _channels.clear();
+  foreach(IrcChannel *channel, channels) {
+    disconnect(channel, 0, this, 0);
+    channel->part(this);
+  }
+  network()->removeIrcUser(this);
+  emit quited();
+}
+
 void IrcUser::channelDestroyed() {
   // private slot!
   IrcChannel *channel = static_cast<IrcChannel*>(sender());
   if(_channels.contains(channel)) {
     _channels.remove(channel);
-    if(_channels.isEmpty())
-      deleteLater();
+    if(_channels.isEmpty() && !network()->isMe(this))
+      quit();
   }
 }
 
 
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
 
-#ifndef _IRCUSER_H_
-#define _IRCUSER_H_
+#ifndef IRCUSER_H
+#define IRCUSER_H
 
 #include <QSet>
 #include <QString>
   void joinChannel(const QString &channelname);
   void partChannel(IrcChannel *channel);
   void partChannel(const QString &channelname);
+  void quit();
 
   void addUserModes(const QString &modes);
   void removeUserModes(const QString &modes);
 
   // void channelJoined(QString channel);
   void channelParted(QString channel);
+  void quited();
 
   void userModesAdded(QString modes);
   void userModesRemoved(QString modes);
 
       qWarning() << "unable to synchronize new IrcUser" << hostmask << "forgot to call Network::setProxy(SignalProxy *)?";
 
     connect(ircuser, SIGNAL(nickSet(QString)), this, SLOT(ircUserNickChanged(QString)));
-    connect(ircuser, SIGNAL(destroyed()), this, SLOT(ircUserDestroyed()));
-    if(!ircuser->isInitialized())
-      connect(ircuser, SIGNAL(initDone()), this, SLOT(ircUserInitDone()));
 
     _ircUsers[nick] = ircuser;
 
     emit ircUserAdded(hostmask);
     emit ircUserAdded(ircuser);
-    if(ircuser->isInitialized())
-      emit ircUserInitDone(ircuser);
   }
 
   return _ircUsers[nick];
 }
 
-void Network::ircUserDestroyed() {
-  IrcUser *ircUser = static_cast<IrcUser *>(sender());
-  if(!ircUser)
-    return;
-
-  QHash<QString, IrcUser *>::iterator ircUserIter = _ircUsers.begin();
-  while(ircUserIter != _ircUsers.end()) {
-    if(ircUser == *ircUserIter) {
-      ircUserIter = _ircUsers.erase(ircUserIter);
-      break;
-    }
-    ircUserIter++;
-  }
+IrcUser *Network::ircUser(QString nickname) const {
+  nickname = nickname.toLower();
+  if(_ircUsers.contains(nickname))
+    return _ircUsers[nickname];
+  else
+    return 0;
 }
 
 void Network::removeIrcUser(IrcUser *ircuser) {
 
   _ircUsers.remove(nick);
   disconnect(ircuser, 0, this, 0);
-  emit ircUserRemoved(nick);
-  emit ircUserRemoved(ircuser);
   ircuser->deleteLater();
 }
 
-void Network::removeIrcUser(const QString &nick) {
-  IrcUser *ircuser;
-  if((ircuser = ircUser(nick)) != 0)
-    removeIrcUser(ircuser);
+void Network::removeIrcChannel(IrcChannel *channel) {
+  QString chanName = _ircChannels.key(channel);
+  if(chanName.isNull())
+    return;
+
+  _ircChannels.remove(chanName);
+  disconnect(channel, 0, this, 0);
+  channel->deleteLater();
 }
 
 void Network::removeChansAndUsers() {
   QList<IrcUser *> users = ircUsers();
-  foreach(IrcUser *user, users) {
-    removeIrcUser(user);
-  }
+  _ircUsers.clear();
   QList<IrcChannel *> channels = ircChannels();
+  _ircChannels.clear();
+  
   foreach(IrcChannel *channel, channels) {
-    removeIrcChannel(channel);
+    disconnect(channel, 0, this, 0);
   }
-}
-
-IrcUser *Network::ircUser(QString nickname) const {
-  nickname = nickname.toLower();
-  if(_ircUsers.contains(nickname))
-    return _ircUsers[nickname];
-  else
-    return 0;
+  foreach(IrcUser *user, users) {
+    disconnect(user, 0, this, 0);
+    user->quit();
+  }
+  qDeleteAll(users);
+  qDeleteAll(channels);
 }
 
 IrcChannel *Network::newIrcChannel(const QString &channelname, const QVariantMap &initData) {
     else
       qWarning() << "unable to synchronize new IrcChannel" << channelname << "forgot to call Network::setProxy(SignalProxy *)?";
 
-    connect(channel, SIGNAL(destroyed()), this, SLOT(channelDestroyed()));
-    if(!channel->isInitialized())
-      connect(channel, SIGNAL(initDone()), this, SLOT(ircChannelInitDone()));
-
     _ircChannels[channelname.toLower()] = channel;
 
     emit ircChannelAdded(channelname);
     emit ircChannelAdded(channel);
-    if(channel->isInitialized())
-      emit ircChannelInitDone(channel);
   }
   return _ircChannels[channelname.toLower()];
 }
     setMyNick(newnick);
 }
 
-void Network::ircUserInitDone() {
-  IrcUser *ircuser = static_cast<IrcUser *>(sender());
-  Q_ASSERT(ircuser);
-  connect(ircuser, SIGNAL(initDone()), this, SLOT(ircUserInitDone()));
-  emit ircUserInitDone(ircuser);
-}
-
-void Network::ircChannelInitDone() {
-  IrcChannel *ircChannel = static_cast<IrcChannel *>(sender());
-  Q_ASSERT(ircChannel);
-  disconnect(ircChannel, SIGNAL(initDone()), this, SLOT(ircChannelInitDone()));
-  emit ircChannelInitDone(ircChannel);
-}
-
-void Network::removeIrcChannel(IrcChannel *channel) {
-  QString chanName = _ircChannels.key(channel);
-  if(chanName.isNull())
-    return;
-
-  _ircChannels.remove(chanName);
-  disconnect(channel, 0, this, 0);
-  emit ircChannelRemoved(chanName);
-  emit ircChannelRemoved(channel);
-  channel->deleteLater();
-}
-
-void Network::removeIrcChannel(const QString &channel) {
-  IrcChannel *chan;
-  if((chan = ircChannel(channel)) != 0)
-    removeIrcChannel(chan);
-}
-
-void Network::channelDestroyed() {
-  IrcChannel *channel = static_cast<IrcChannel *>(sender());
-  Q_ASSERT(channel);
-  _ircChannels.remove(_ircChannels.key(channel));
-  emit ircChannelRemoved(channel);
-}
-
 void Network::emitConnectionError(const QString &errorMsg) {
   emit connectionError(errorMsg);
 }
 
 
   inline void addIrcUser(const QString &hostmask) { newIrcUser(hostmask); }
   inline void addIrcChannel(const QString &channel) { newIrcChannel(channel); }
-  void removeIrcUser(const QString &nick);
-  void removeIrcChannel(const QString &channel);
 
   //init geters
   QVariantMap initSupports() const;
   void emitConnectionError(const QString &);
 
 private slots:
-  void ircUserDestroyed();
-  void channelDestroyed();
   void removeIrcUser(IrcUser *ircuser);
   void removeIrcChannel(IrcChannel *ircChannel);
   void removeChansAndUsers();
-  void ircUserInitDone();
-  void ircChannelInitDone();
 
 signals:
   void aboutToBeDestroyed();
   void ircChannelAdded(const QString &channelname);
   void ircChannelAdded(IrcChannel *);
 
-  void ircUserRemoved(const QString &nick);
-  void ircChannelRemoved(const QString &channel);
-
-  // needed for client sync progress
-  void ircUserRemoved(QObject *);
-  void ircChannelRemoved(QObject *);
-
-  void ircUserInitDone(IrcUser *);
-  void ircChannelInitDone(IrcChannel *);
-
   void connectRequested(NetworkId id = 0) const;
   void disconnectRequested(NetworkId id = 0) const;
   void setNetworkInfoRequested(const NetworkInfo &) const;
   static QTextCodec *_defaultCodecForDecoding;
 
   bool _autoAwayActive; // when this is active handle305 and handle306 don't trigger any output
+
+  friend class IrcUser;
+  friend class IrcChannel;
 };
 
 //! Stores all editable information about a network (as opposed to runtime state).
 
   foreach(QString channel, ircuser->channels())
     emit displayMsg(Message::Quit, BufferInfo::ChannelBuffer, channel, msg, prefix);
 
-  network()->removeIrcUser(nickFromMask(prefix));
+  ircuser->quit();
 }
 
 void IrcServerHandler::handleTopic(const QString &prefix, const QList<QByteArray> ¶ms) {
 
 //! This is the fallback version number in case we can't autogenerate one
 baseVersion = "0.3.1";
 
-protocolVersion = 6;       //< Version of the client/core protocol
-coreNeedsProtocol   = 6;   //< Minimum protocol version the core needs
-clientNeedsProtocol = 6;   //< Minimum protocol version the client needs
+protocolVersion = 7;       //< Version of the client/core protocol
+coreNeedsProtocol   = 7;   //< Minimum protocol version the core needs
+clientNeedsProtocol = 7;   //< Minimum protocol version the client needs
 
 distCommittish = $Format:%H$
 distCommitDate = $Format:%at$