diff -urN -X psidiff.ignore sources/options/default.xml work/options/default.xml
--- sources/options/default.xml	2009-04-24 21:53:28.000000000 +0400
+++ work/options/default.xml	2009-04-24 03:41:38.000000000 +0400
@@ -420,9 +420,13 @@
 				<scroll-up type="QKeySequence" comment="Scroll up">Shift+PgUp</scroll-up>
 				<scroll-down type="QKeySequence" comment="Scroll down">Shift+PgDown</scroll-down>
 				<close type="QVariantList" comment="Close the current window/tab">
-					<item type="QKeySequence">Esc</item>
+					<item type="QKeySequence">Ctrl+Q</item>
 					<item type="QKeySequence">Ctrl+W</item>
 				</close>
+				<hide type="QVariantList" comment="Hide the current window/tab">
+					<item type="QKeySequence">ESC</item>
+					<item type="QKeySequence">Alt+H</item>
+				</hide>
 				<history type="QKeySequence" comment="Open the message history">Ctrl+H</history>
 				<user-info type="QKeySequence" comment="Show the user info of the contact">Ctrl+I</user-info>
 			</common>
diff -urN -X psidiff.ignore sources/src/chatdlg.cpp work/src/chatdlg.cpp
--- sources/src/chatdlg.cpp	2009-04-24 21:53:28.000000000 +0400
+++ work/src/chatdlg.cpp	2009-04-24 03:41:38.000000000 +0400
@@ -182,6 +182,10 @@
 	addAction(act_close_);
 	connect(act_close_, SIGNAL(activated()), SLOT(close()));
 
+	act_hide_ = new QAction(this);
+	addAction(act_hide_);
+	connect(act_hide_, SIGNAL(activated()), SLOT(hideTab()));
+
 	act_scrollup_ = new QAction(this);
 	addAction(act_scrollup_);
 	connect(act_scrollup_, SIGNAL(activated()), SLOT(scrollUp()));
@@ -199,6 +203,7 @@
 
 	if(!isTabbed()) {
 		act_close_->setShortcuts(ShortcutManager::instance()->shortcuts("common.close"));
+		act_hide_->setShortcuts(ShortcutManager::instance()->shortcuts("common.hide"));
 	} else {
 		act_close_->QAction::setShortcuts (QList<QKeySequence>());
 	}
diff -urN -X psidiff.ignore sources/src/chatdlg.h work/src/chatdlg.h
--- sources/src/chatdlg.h	2009-04-24 21:53:28.000000000 +0400
+++ work/src/chatdlg.h	2009-04-24 03:41:38.000000000 +0400
@@ -191,6 +191,7 @@
 	QAction* act_scrollup_;
 	QAction* act_scrolldown_;
 	QAction* act_close_;
+	QAction* act_hide_;
 
 	int pending_;
 	bool keepOpen_;
diff -urN -X psidiff.ignore sources/src/contactview.cpp work/src/contactview.cpp
--- sources/src/contactview.cpp	2009-04-24 21:53:28.000000000 +0400
+++ work/src/contactview.cpp	2009-04-24 03:41:38.000000000 +0400
@@ -60,6 +60,8 @@
 #include "textutil.h"
 #include "bookmarkmanagedlg.h"
 #include "bookmarkmanager.h"
+#include "groupchatdlg.h"
+#include "tabdlg.h"
 
 static inline int rankStatus(int status) 
 {
@@ -258,6 +260,8 @@
 		gname = tr("Agents/Transports");
 	else if(type == ContactViewItem::gPrivate)
 		gname = tr("Private Messages");
+	else if(type == ContactViewItem::gMucs)
+		gname = tr("Conferences");
 
 	if(d->cvi)
 		item = new ContactViewItem(gname, type, this, d->cvi);
@@ -499,6 +503,9 @@
 
 	if(u.isPrivate())
 		ensureContactItem(e, ensureGroup(ContactViewItem::gPrivate));
+	else if (u.isMuc()) {
+		ensureContactItem(e, ensureGroup(ContactViewItem::gMucs));
+	}
 	else if(!u.inList())
 		ensureContactItem(e, ensureGroup(ContactViewItem::gNotInList));
 	else if(u.isTransport()) {
@@ -543,7 +550,8 @@
 
 		if(g->groupType() == ContactViewItem::gNotInList && u.inList())
 			del = true;
-		else if(g->groupType() != ContactViewItem::gNotInList && g->groupType() != ContactViewItem::gPrivate && !u.inList())
+		else if(g->groupType() != ContactViewItem::gNotInList && g->groupType() != ContactViewItem::gPrivate
+				&& g->groupType() != ContactViewItem::gMucs && !u.inList())
 			del = true;
 		else if(g->groupType() == ContactViewItem::gAgents && !u.isTransport())
 			del = true;
@@ -1063,6 +1071,11 @@
 		QString gname = i->groupName();
 		Q3PopupMenu pm;
 
+		if (i->groupType() == ContactViewItem::gMucs) {
+			pm.insertItem(IconsetFactory::icon("psiplus/action_muc_hide").icon(), tr("Hide all.."), 100);
+			pm.insertItem(IconsetFactory::icon("psiplus/action_muc_show").icon(), tr("Show all.."), 101);
+			pm.insertItem(IconsetFactory::icon("psiplus/action_muc_leave").icon(), tr("Leave all.."), 102);
+		} else {
 		if (PsiOptions::instance()->getOption("options.ui.message.enabled").toBool())
 			pm.insertItem(IconsetFactory::icon("psi/sendMessage").icon(), tr("Send message to group"), 0);
 		if(!PsiOptions::instance()->getOption("options.ui.contactlist.lockdown-roster").toBool()) {
@@ -1080,6 +1093,7 @@
 			pm.insertItem(IconsetFactory::icon("psi/remove").icon(), tr("Remove group"), 2);
 			pm.insertItem(IconsetFactory::icon("psi/remove").icon(), tr("Remove group and contacts"), 3);
 		}
+		}
 
 		if(i->groupType() == ContactViewItem::gAgents) {
 			pm.insertSeparator();
@@ -1133,6 +1147,27 @@
 			if(i->groupType() == ContactViewItem::gAgents)
 				d->cv->setShowAgents(false);
 		}
+		else if (x == 100) {
+			foreach (QString gc, psiAccount()->groupchats()) {
+				Jid mj(gc);
+				GCMainDlg *gcDlg = psiAccount()->findDialog<GCMainDlg*>(mj.bare());
+                        	if (gcDlg && !gcDlg->isTabHidden()) gcDlg->hideTab();
+			}
+		}
+		else if (x == 101) {
+			foreach (QString gc, psiAccount()->groupchats()) {
+				Jid mj(gc);
+				GCMainDlg *gcDlg = psiAccount()->findDialog<GCMainDlg*>(mj.bare());
+                        	if (gcDlg && gcDlg->isTabHidden()) gcDlg->showTab();
+			}
+		}
+		else if (x == 102) {
+			foreach (QString gc, psiAccount()->groupchats()) {
+				Jid mj(gc);
+				GCMainDlg *gcDlg = psiAccount()->findDialog<GCMainDlg*>(mj.bare());
+                        	if (gcDlg) gcDlg->close();
+			}
+		}
 	}
 	else if(i->type() == ContactViewItem::Contact) {
 		bool self = false;
@@ -1156,10 +1191,16 @@
 		bool isPrivate = e ? e->u.isPrivate(): false;
 		bool isAgent = e ? e->u.isTransport() : false;
 		bool avail = e ? e->u.isAvailable() : false;
+		bool isMuc = e ? e->u.isMuc() : false;
 		QString groupNameCache = ((ContactViewItem *)static_cast<Q3ListViewItem *>(i)->parent())->groupName();
 
 		Q3PopupMenu pm;
+		int base_sendto = 0, base_hidden = 0, base_gc = 0, base_group = 0;
+		const UserResourceList &rl = u->userResourceList();
+		QStringList hc; //hidden chat
+		QStringList groupchats;
 
+		if (!isMuc) {
 		if(!self && !inList && !isPrivate && !PsiOptions::instance()->getOption("options.ui.contactlist.lockdown-roster").toBool()) {
 			pm.insertItem(IconsetFactory::icon("psi/addContact").icon(), tr("Add/Authorize to contact list"), 10);
 			if(!online)
@@ -1178,9 +1219,7 @@
 
 		//pm.insertItem(QIconSet(PsiIconset::instance()->url), tr("Send &URL"), 2);
 
-		const UserResourceList &rl = u->userResourceList();
-
-		int base_sendto = 32;
+			base_sendto = 32;
 		int at_sendto = 0;
 		ResourceMenu *s2m  = new ResourceMenu(&pm);
 		ResourceMenu *c2m  = new ResourceMenu(&pm);
@@ -1234,9 +1273,8 @@
 			pm.setItemEnabled(25, !rl.isEmpty());
 		}
 
-		int base_hidden = base_sendto + at_sendto;
+			base_hidden = base_sendto + at_sendto;
 		int at_hidden = 0;
-		QStringList hc;
 		if(!isPrivate && PsiOptions::instance()->getOption("options.ui.menu.contact.active-chats").toBool()) {
 			hc = d->pa->hiddenChats(u->jid());
 			ResourceMenu *cm = new ResourceMenu(&pm);
@@ -1281,9 +1319,8 @@
 		}
 
 		// invites
-		int base_gc = base_hidden + at_hidden;
+			base_gc = base_hidden + at_hidden;
 		int at_gc = 0;
-		QStringList groupchats;
 		if(!isPrivate && !isAgent) {
 			Q3PopupMenu *gm = new Q3PopupMenu(&pm);
 			groupchats = d->pa->groupchats();
@@ -1301,7 +1338,7 @@
 		if(inList || !isAgent)
 			pm.insertSeparator();
 
-		int base_group = base_gc + at_gc;
+			base_group = base_gc + at_gc;
 
 		if(!self) {
 			if(inList) {
@@ -1412,6 +1449,15 @@
 		if(!isPrivate) {
 			d->cv->qa_hist->addTo(&pm);
 		}
+		}
+
+		if (isMuc && !isPrivate) {
+			GCMainDlg *gc = psiAccount()->findDialog<GCMainDlg*>(u->jid().bare());
+			if(gc && !gc->isTabHidden())
+				pm.insertItem(IconsetFactory::icon("psiplus/action_muc_hide").icon(), tr("Hide"), 26);
+			else pm.insertItem(IconsetFactory::icon("psiplus/action_muc_show").icon(), tr("Show"), 27);
+			pm.insertItem(IconsetFactory::icon("psiplus/action_muc_leave").icon(), tr("Leave"), 28); //FIXME change icon
+		}
 
 		QString name = u->jid().full();
 		QString show = JIDUtil::nickOrJid(u->name(), u->jid().full());
@@ -1537,6 +1583,18 @@
 			if(online)
 				actionVoice(u->jid());
 		}
+		else if (x == 26) {
+			GCMainDlg *gc = psiAccount()->findDialog<GCMainDlg*>(u->jid().bare());
+			if (gc && !gc->isTabHidden()) gc->hideTab();
+		}
+		else if (x == 27) {
+			GCMainDlg *gc = psiAccount()->findDialog<GCMainDlg*>(u->jid().bare());
+			if (gc && gc->isTabHidden()) gc->showTab();
+		}
+		else if (x == 28) {
+			GCMainDlg *gc = psiAccount()->findDialog<GCMainDlg*>(u->jid().bare());
+        		if (gc) gc->close();
+		}
 		else if(x >= base_sendto && x < base_hidden) {
 			int n = x - base_sendto;
 #ifndef WHITEBOARDING
@@ -1727,15 +1785,18 @@
 		if(name != show)
 			name += QString(" (%1)").arg(e->u.name());
 
-		int n = 0;
+		int n = 1;
 		int gt = i->parentGroupType();
-		if(gt != ContactViewItem::gNotInList && gt != ContactViewItem::gPrivate) {
+
+		if(gt == ContactViewItem::gMucs) {
+			GCMainDlg *gc = psiAccount()->findDialog<GCMainDlg*>(e->u.jid().full());
+			if (gc) gc->close();
+		} else if(gt != ContactViewItem::gNotInList && gt != ContactViewItem::gPrivate) {
 			n = QMessageBox::information(d->cv, tr("Remove"),
 			tr("Are you sure you want to remove <b>%1</b> from your contact list?").arg(name),
 			tr("&Yes"), tr("&No"));
 		}
-		else
-			n = 0;
+		else n = 0;
 
 		if(n == 0) {
 			Jid j = e->u.jid();
@@ -3350,12 +3411,13 @@
 
 int ContactViewItem::rankGroup(int groupType) const
 {
-	static int rankgroups[5] = {
+	static int rankgroups[6] = {
 		gGeneral,
 		gUser,
 		gPrivate,
 		gAgents,
 		gNotInList,
+		gMucs
 	};
 
 	int n;
@@ -3483,6 +3545,14 @@
 			s = "<nobr>" + TextUtil::plain2rich(s) + "</nobr>";
 		}
 
+			if(d->u->pending() != 0 || d->u->privPending() != 0)
+			{
+				int pPending = d->u->privPending();
+				QString messCounter = QString::number(d->u->pending()) + 
+						(pPending != 0 ? "/" + QString::number(pPending) : "");
+				s += QString(" [%1]").arg(messCounter);
+			}
+
 		// Add the status message if wanted 
 		if (!forceNoStatusMsg && static_cast<ContactView*>(Q3ListViewItem::listView())->isShowStatusMsg()) {
 			QString statusMsg;
diff -urN -X psidiff.ignore sources/src/contactview.h work/src/contactview.h
--- sources/src/contactview.h	2009-04-24 21:53:28.000000000 +0400
+++ work/src/contactview.h	2009-04-24 03:41:38.000000000 +0400
@@ -341,7 +341,7 @@
 	Q_OBJECT
 public:
 	enum { Profile, Group, Contact };
-	enum { gGeneral, gNotInList, gAgents, gPrivate, gUser };
+	enum { gGeneral, gNotInList, gAgents, gPrivate, gUser, gMucs };
 
 	ContactViewItem(const QString &profileName, ContactProfile *, ContactView *parent);
 	ContactViewItem(const QString &groupName, int groupType, ContactProfile *, ContactView *parent);
diff -urN -X psidiff.ignore sources/src/groupchatdlg.cpp work/src/groupchatdlg.cpp
--- sources/src/groupchatdlg.cpp	2009-04-24 21:53:28.000000000 +0400
+++ work/src/groupchatdlg.cpp	2009-04-24 04:01:08.000000000 +0400
@@ -81,6 +81,8 @@
 #include "mcmdmanager.h"
 #include "lastactivitytask.h"
 #include "psirichtext.h"
+#include "tabdlg.h"
+#include "contactview.h"
 
 #include "mcmdsimplesite.h"
 
@@ -211,7 +213,7 @@
 #endif
 	QAction *act_send, *act_scrollup, *act_scrolldown, *act_close;
 
-	QAction *act_mini_cmd, *act_nick;
+	QAction *act_mini_cmd, *act_nick, *act_hide;
 
 	MCmdSimpleSite mCmdSite;
 	MCmdManager mCmdManager;
@@ -219,7 +221,7 @@
 	QString nickSeparator; // equals ":"
 
 	QMenu *pm_settings;
-	int pending;
+	int pending, privPending;
 	bool connecting;
 
 	QStringList hist;
@@ -680,6 +682,7 @@
 	options_ = PsiOptions::instance();
 
 	d->pending = 0;
+	d->privPending = 0;
 	d->connecting = false;
 
 	d->histAt = 0;
@@ -764,6 +767,9 @@
 	d->act_close = new QAction(this);
 	addAction(d->act_close);
 	connect(d->act_close,SIGNAL(triggered()), SLOT(close()));
+	d->act_hide = new QAction(this);
+	addAction(d->act_hide);
+	connect(d->act_hide,SIGNAL(triggered()), SLOT(hideTab()));
 	d->act_scrollup = new QAction(this);
 	addAction(d->act_scrollup);
 	connect(d->act_scrollup,SIGNAL(triggered()), SLOT(scrollUp()));
@@ -847,6 +853,7 @@
 	} else {
 		d->act_close->QAction::setShortcuts (QList<QKeySequence>());
 	}
+	d->act_hide->setShortcuts(ShortcutManager::instance()->shortcuts("common.hide"));
 	d->act_scrollup->setShortcuts(ShortcutManager::instance()->shortcuts("common.scroll-up"));
 	d->act_scrolldown->setShortcuts(ShortcutManager::instance()->shortcuts("common.scroll-down"));
 	d->act_mini_cmd->setShortcuts(ShortcutManager::instance()->shortcuts("chat.quick-command"));
@@ -884,8 +891,24 @@
 
 	if(d->pending > 0) {
 		d->pending = 0;
-		invalidateTab();
+		UserListItem* uli = account()->find(jid());
+		if(uli != NULL) {
+			uli->setPending(d->pending);
+			account()->contactProfile()->updateEntry(*uli);
+			invalidateTab();
+		}
+	}
+
+	if(d->privPending > 0) {
+		d->privPending = 0;
+		UserListItem* uli = account()->find(jid());
+		if(uli != NULL) {
+			uli->setPrivPending(d->privPending);
+			account()->contactProfile()->updateEntry(*uli);
+			invalidateTab();
+		}
 	}
+
 	doFlash(false);
 
 	ui_.mle->chatEdit()->setFocus();
@@ -1422,8 +1445,7 @@
 	if (!s.capsNode().isEmpty()) {
 		Jid caps_jid(s.mucItem().jid().isEmpty() || !d->nonAnonymous ? Jid(jid()).withResource(nick) : s.mucItem().jid());
 		account()->capsManager()->updateCaps(caps_jid,s.capsNode(),s.capsVersion(),s.capsExt());
-	}
-
+	}    
 }
 
 void GCMainDlg::message(const Message &_m)
@@ -1432,6 +1454,7 @@
 	QString from = m.from().resource();
 	bool alert = false;
 
+
 	if (m.getMUCStatuses().contains(100)) {
 		d->nonAnonymous = true;
 	}
@@ -1466,8 +1489,17 @@
 		return;
 
 	// code to determine if the speaker was addressing this client in chat
-	if(m.body().contains(d->self))
+	if(m.body().contains(d->self)) {
+		if(!isActiveTab() && (from != d->self)) {
+			++d->privPending;
+			UserListItem* uli = account()->find(jid());
+			if(uli != NULL) {
+				uli->setPrivPending(d->privPending);
+				account()->contactProfile()->updateEntry(*uli);
+			}
+		}
 		alert = true;
+	}
 
 	if (m.body().left(d->self.length()) == d->self)
 		d->lastReferrer = m.from().resource();
@@ -1475,7 +1507,15 @@
 	if(PsiOptions::instance()->getOption("options.ui.muc.use-highlighting").toBool()) {
 		QStringList highlightWords = PsiOptions::instance()->getOption("options.ui.muc.highlight-words").toStringList();
 		foreach (QString word, highlightWords) {
-			if(m.body().contains((word), Qt::CaseInsensitive)) {
+			if(m.body().contains((word), Qt::CaseInsensitive) && !alert) {
+				if(!isActiveTab() && (from != d->self)) {
+					++d->privPending;
+					UserListItem* uli = account()->find(jid());
+					if(uli != NULL) {
+						uli->setPrivPending(d->privPending);
+						account()->contactProfile()->updateEntry(*uli);
+					}
+				}
 				alert = true;
 			}
 		}
@@ -1661,7 +1701,12 @@
 	// if we're not active, notify the user by changing the title
 	if(!isActiveTab() && (who != d->self)) {
 		++d->pending;
-		invalidateTab();
+		UserListItem* uli = account()->find(jid());
+		if (uli != NULL) {
+			uli->setPending(d->pending);
+			account()->contactProfile()->updateEntry(*uli);
+			invalidateTab();
+		}
 	}
 
 	//if someone directed their comments to us, notify the user
diff -urN -X psidiff.ignore sources/src/mucjoindlg.cpp work/src/mucjoindlg.cpp
--- sources/src/mucjoindlg.cpp	2009-04-24 03:27:48.000000000 +0400
+++ work/src/mucjoindlg.cpp	2009-04-24 03:41:38.000000000 +0400
@@ -29,6 +29,7 @@
 #include "mucjoindlg.h"
 #include "psicontactlist.h"
 #include "groupchatdlg.h"
+#include "tabdlg.h"
 
 MUCJoinDlg::MUCJoinDlg(PsiCon* psi, PsiAccount* pa)
 	: QDialog(0)
@@ -158,9 +159,12 @@
 
 	GCMainDlg *gc = account_->findDialog<GCMainDlg*>(j.bare());
 	if (gc) {
+		if(gc->isTabHidden())
+			gc->showTab();
 		gc->bringToFront();
 		if (gc->isInactive()) {
 			gc->reactivate();
+			qWarning("INACTIVE!");
 		}
 		joined();
 		return;
diff -urN -X psidiff.ignore sources/src/psiaccount.cpp work/src/psiaccount.cpp
--- sources/src/psiaccount.cpp	2009-04-24 21:53:28.000000000 +0400
+++ work/src/psiaccount.cpp	2009-04-24 04:07:03.000000000 +0400
@@ -3042,6 +3042,7 @@
 		connect(this, SIGNAL(updateContact(const Jid &, bool)), c, SLOT(updateContact(const Jid &, bool)));
 	}
 	else {
+		if(c && c->isTabHidden()) c->showTab();
 		// on X11, do a special reparent to open on the right desktop
 #ifdef Q_WS_X11
 		/* KIS added an exception for tabs here. We do *not* want chats flying
@@ -3227,7 +3228,15 @@
 
 	if(d->eventQueue->count(u->jid()) > 0)
 		openNextEvent(*u, UserAction);
-	else {
+    else if(u->isMuc())
+	{
+		GCMainDlg *gc = findDialog<GCMainDlg*>(j.bare());
+		if (gc)
+		{
+			if(gc->isTabHidden()) gc->showTab();
+			else gc->bringToFront();
+		}
+	} else {
 		if(PsiOptions::instance()->getOption("options.messages.default-outgoing-message-type").toString() == "message")
 			actionSendMessage(u->jid());
 		else
@@ -4136,6 +4145,8 @@
 	u->setInList(false);
 	u->setAvatarFactory(avatarFactory());
 	u->setName(nick);
+	u->setMuc(groupchats().contains(jid.full()));
+
 
 	// is it a private groupchat?
 	Jid j = u->jid();
@@ -4151,6 +4162,16 @@
 		u->userResourceList().append(ur);
 	}
 
+	if(u->isMuc()) {
+		d->cp->removeEntry(jid);
+		d->userList.removeAllByJid(jid);
+		// make a resource so the contact appears online
+		UserResource ur;
+		ur.setName("Muc"); //FIXME mucs should be online without resource
+		ur.setStatus(status());
+		u->userResourceList().append(ur);
+	}
+
 	// treat it like a push  [pushinfo]
 	//VCard info;
 	//if(readUserInfo(item->jid, &info) && !info.field[vNickname].isEmpty())
@@ -4430,8 +4451,15 @@
 			break;
 		}
 	}
-	if(!found)
+	if(!found) {
+		QString name = j.node();
+		foreach(ConferenceBookmark c, d->bookmarkManager->conferences())
+		{
+			if(c.jid().full() == j.bare()) name = c.name();
+		}
 		d->groupchats += str;
+		addUserListItem(j.bare(), name);
+	}
 
 	GCMainDlg *w = new GCMainDlg(this, j, d->tabManager);
 	w->setPassword(d->client->groupChatPassword(j.node(),j.domain()));
@@ -4467,6 +4495,12 @@
 {
 	d->groupchats.remove(room + '@' + host);
 	d->client->groupChatLeave(host, room);
+	Jid j(room + '@' + host);
+	UserListItem *u = find(j);
+	if (u) {
+		d->cp->removeEntry(j);
+		d->userList.remove(u);
+	}
 }
 
 GCContact *PsiAccount::findGCContact(const Jid &j)
@@ -4546,10 +4580,22 @@
 	Resource r;
 	r.setName(j.resource());
 	r.setStatus(s);
+
+
 	if(s.isAvailable())
 		client_resourceAvailable(j, r);
 	else
 		client_resourceUnavailable(j, j.resource());
+	
+
+	if(j.resource() == w->nick()) {
+		r.setName("MUC");
+		UserListItem *u = find(Jid(j.bare()));
+		if(u != NULL) {
+			u->userResourceList().replace(0, r);
+			cpUpdate(*u);
+		}
+	}
 }
 
 void PsiAccount::client_groupChatError(const Jid &j, int code, const QString &str)
diff -urN -X psidiff.ignore sources/src/psicon.cpp work/src/psicon.cpp
--- sources/src/psicon.cpp	2009-04-24 21:53:28.000000000 +0400
+++ work/src/psicon.cpp	2009-04-24 03:41:38.000000000 +0400
@@ -1357,8 +1357,7 @@
 
 		// as the event could be deleted just above, we're using cached account and from values
 		account->openChat(from, activationType);
-	}
-	else {
+	} else {
 		// search for an already opened eventdlg
 		EventDlg *w = e->account()->findDialog<EventDlg*>(u->jid());
 
diff -urN -X psidiff.ignore sources/src/tabs/tabbablewidget.cpp work/src/tabs/tabbablewidget.cpp
--- sources/src/tabs/tabbablewidget.cpp	2009-04-24 21:53:28.000000000 +0400
+++ work/src/tabs/tabbablewidget.cpp	2009-04-24 03:41:38.000000000 +0400
@@ -217,3 +217,18 @@
         tabDlg->setTabIcon(this, icon);
     }
 }
+
+bool TabbableWidget::isTabHidden() {
+	if(isTabbed()) return getManagingTabDlg()->isTabHidden(this);
+	else return isHidden();
+}
+
+void TabbableWidget::hideTab() {
+	if(isTabbed()) getManagingTabDlg()->hideTab(this);
+	else hide();
+}
+
+void TabbableWidget::showTab() {
+	if(isTabbed()) return getManagingTabDlg()->showTab(this);
+	else show();
+}
diff -urN -X psidiff.ignore sources/src/tabs/tabbablewidget.h work/src/tabs/tabbablewidget.h
--- sources/src/tabs/tabbablewidget.h	2009-04-24 21:53:28.000000000 +0400
+++ work/src/tabs/tabbablewidget.h	2009-04-24 03:41:38.000000000 +0400
@@ -64,6 +64,8 @@
 	virtual QString desiredCaption() const = 0;
        void setTabIcon(const QIcon &);
 
+	bool isTabHidden();
+	void showTab();
 signals:
 	void invalidateTabInfo();
 	void updateFlashState();
@@ -74,7 +76,7 @@
 	virtual void activated();
 	void bringToFront();
 	virtual void ensureTabbedCorrectly();
-
+	void hideTab();
 protected:
 	virtual void setJid(const Jid&);
 	PsiAccount* account() const;
diff -urN -X psidiff.ignore sources/src/tabs/tabdlg.cpp work/src/tabs/tabdlg.cpp
--- sources/src/tabs/tabdlg.cpp	2009-04-24 21:53:28.000000000 +0400
+++ work/src/tabs/tabdlg.cpp	2009-04-24 03:41:38.000000000 +0400
@@ -222,6 +222,7 @@
 
 	if (tab != -1) {
 		QAction *d = 0;
+		QAction *h = tabMenu_->addAction(tr("Hide Tab"));
 		if(userManagement_) {
 			d = tabMenu_->addAction(tr("Detach Tab"));
 		}
@@ -249,6 +250,8 @@
 		}
 		else if (act == d) {
 			detachTab(getTab(tab));
+		} else if(act == h) {
+			hideTab(getTab(tab));
 		}
 		else {
 			TabDlg* target = sentTos[act];
@@ -261,6 +264,8 @@
 void TabDlg::tab_aboutToShowMenu(QMenu *menu)
 {
 	menu->addSeparator();
+	menu->addAction(tr("Hide Current Tab"), this, SLOT(hideCurrentTab()));
+	menu->addAction(tr("Hide All Tabs"), this, SLOT(hideAllTab()));
 	menu->addAction(tr("Detach Current Tab"), this, SLOT(detachCurrentTab()));
 	menu->addAction(tr("Close Current Tab"), this, SLOT(closeCurrentTab()));
 
@@ -372,11 +377,27 @@
 	setUpdatesEnabled(true);
 }
 
+void TabDlg::showTab(TabbableWidget* tab)
+{
+	if(isHidden()) show();
+	tabWidget_->addTab(tab, captionForTab(tab), tab->icon());
+}
+
+bool TabDlg::isTabHidden(TabbableWidget* tab)
+{
+	return managesTab(tab) && (tabWidget_->getIndex(tab) == -1);
+}
+
 void TabDlg::detachCurrentTab()
 {
 	detachTab(static_cast<TabbableWidget*>(tabWidget_->currentPage()));
 }
 
+void TabDlg::hideCurrentTab()
+{
+	hideTab(static_cast<TabbableWidget*>(tabWidget_->currentPage()));
+}
+
 void TabDlg::mouseDoubleClickTab(QWidget* widget)
 {
 	if(userManagement_)
@@ -392,6 +413,18 @@
 	sendTabTo(tab, newTab);
 }
 
+void TabDlg::hideTab(TabbableWidget* tab)
+{
+	tabWidget_->removePage(tab);
+	if(tabWidget_->count() == 0) hide();
+}
+
+void TabDlg::hideAllTab()
+{
+	for(int i=tabWidget_->count(); i>=0; i--)
+		hideTab(static_cast<TabbableWidget*>(tabWidget_->widget(i)));
+}
+
 /**
  * Call this when you want a tab to be removed immediately with no readiness checks
  * or reparenting, hiding etc (Such as on tab destruction).
@@ -444,6 +477,7 @@
 {
 	if (tabWidget_->count() > 0)
 		return;
+	if (tabs_.count() > 0) { hide(); return; }
 	deleteLater();
 }
 
@@ -497,7 +531,7 @@
 		}
 	}
 	foreach(TabbableWidget* tab, tabs_) {
-		closeTab(tab);
+		if (!isTabHidden(tab)) closeTab(tab);
 	}
 }
 
diff -urN -X psidiff.ignore sources/src/tabs/tabdlg.h work/src/tabs/tabdlg.h
--- sources/src/tabs/tabdlg.h	2009-04-24 21:53:28.000000000 +0400
+++ work/src/tabs/tabdlg.h	2009-04-24 03:41:38.000000000 +0400
@@ -84,6 +84,8 @@ public:
 	void setTabBarShownForSingles(bool enabled); // default enabled
 	void setSimplifiedCaptionEnabled(bool enabled); // default disabled
         void setTabIcon(QWidget *,const QIcon &);
+	void showTab(TabbableWidget*);
+	bool isTabHidden(TabbableWidget*);
 
 protected:
 	void setShortcuts();
@@ -117,7 +119,9 @@ public slots:
 	void optionsUpdate();
 	void detachTab(TabbableWidget*);
 	void sendTabTo(TabbableWidget*, TabDlg *);
-
+        void hideTab(TabbableWidget*);
+	void hideCurrentTab();
+	void hideAllTab();
 signals:
 	void resized(QSize size);
 	
diff -urN -X psidiff.ignore sources/src/userlist.cpp work/src/userlist.cpp
--- sources/src/userlist.cpp	2009-04-24 21:53:28.000000000 +0400
+++ work/src/userlist.cpp	2009-04-24 03:41:38.000000000 +0400
@@ -294,9 +294,12 @@
 UserListItem::UserListItem(bool self)
 {
 	v_inList = false;
+	v_isMuc = false;
 	v_self = self;
 	v_private = false;
 	v_avatarFactory = NULL;
+	v_pending = 0;
+	v_privPending = 0;
 	lastmsgtype = -1;
 }
 
@@ -339,6 +342,27 @@
 	return v_tune;
 }
 
+void UserListItem::setPending(int p)
+{
+	v_pending = p;
+}
+
+int UserListItem::pending() const
+{
+	return v_pending;
+}
+
+void UserListItem::setPrivPending(int p)
+{
+	v_privPending = p;
+}
+
+int UserListItem::privPending() const
+{
+	return v_privPending;
+}
+
+
 void UserListItem::setGeoLocation(const GeoLocation& geoLocation)
 {
 	v_geoLocation = geoLocation;
@@ -380,6 +404,11 @@
 	return v_isTransport;
 }
 
+bool UserListItem::isMuc() const
+{
+	return v_isMuc;
+}
+
 bool UserListItem::isAvailable() const
 {
 	return !v_url.isEmpty();
@@ -440,6 +469,11 @@
 	v_t = t;
 }
 
+void UserListItem::setMuc(bool b)
+{
+	v_isMuc = b;
+}
+
 void UserListItem::setPresenceError(const QString &e)
 {
 	v_perr = e;
@@ -762,3 +796,11 @@
 	return 0;
 }
 
+void UserList::removeAllByJid(const XMPP::Jid &j)
+{
+	foreach(UserListItem *i, *this) {
+		if(i->jid().compare(j))
+			remove(i);
+	}
+}
+
diff -urN -X psidiff.ignore sources/src/userlist.h work/src/userlist.h
--- sources/src/userlist.h	2009-04-24 21:53:28.000000000 +0400
+++ work/src/userlist.h	2009-04-24 03:41:38.000000000 +0400
@@ -112,6 +112,7 @@
 
 	bool inList() const;
 	bool isTransport() const;
+	bool isMuc() const;
 	bool isAvailable() const;
 	bool isHidden() const;
 	bool isAway() const;
@@ -130,12 +131,17 @@
 	void setJid(const XMPP::Jid &);
 	void setInList(bool);
 	void setLastAvailable(const QDateTime &);
+	void setMuc(bool);
 	void setPresenceError(const QString &);
 	void setPrivate(bool);
 	void setMood(const Mood&);
 	void setActivity(const Activity&);
 	void setTune(const QString&);
 	const QString& tune() const;
+	void setPending(int);
+	int pending() const;
+	void setPrivPending(int);
+	int privPending() const;
 	void setGeoLocation(const GeoLocation&);
 	const GeoLocation& geoLocation() const;
 	void setPhysicalLocation(const PhysicalLocation&);
@@ -159,7 +165,7 @@
 	QDateTime v_t;
 	UserResourceList v_url;
 	QString v_perr;
-	bool v_self, v_isTransport;
+	bool v_self, v_isTransport, v_isMuc;
 	bool v_private;
 	QStringList secList;
 	QString v_keyID;
@@ -167,6 +173,7 @@
 	Mood v_mood;
 	Activity v_activity;
 	QString v_tune;
+	int v_pending, v_privPending;
 	GeoLocation v_geoLocation;
 	PhysicalLocation v_physicalLocation;
 	AvatarFactory* v_avatarFactory;
@@ -181,6 +188,7 @@
 	~UserList();
 
 	UserListItem *find(const XMPP::Jid &);
+	void removeAllByJid(const XMPP::Jid &);
 };
 
 #endif
--- sources/src/eventdlg.cpp	2009-10-11 11:11:11.000000000 +0700
+++ work/src/eventdlg.cpp	2009-10-11 11:11:11.000000000 +0700
@@ -1428,6 +1428,8 @@
 	QKeySequence key = e->key() + ( e->modifiers() & ~Qt::KeypadModifier);
 	if(ShortcutManager::instance()->shortcuts("common.close").contains(key))
 		close();
+	else if(ShortcutManager::instance()->shortcuts("common.hide").contains(key))
+		hide();
 	else if(ShortcutManager::instance()->shortcuts("message.send").contains(key))
 		doSend();
 	else
