diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 56ec8c42623c0ed1d827abc5b815f9ff112391f8..d7424cf05a90329c3075277e0bde564dca8b7616 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -403,7 +403,8 @@ LLNotification::LLNotification(const LLNotification::Params& p) :
 	mPriority(p.priority),
 	mCancelled(false),
 	mIgnored(false),
-	mResponderObj(NULL)
+	mResponderObj(NULL),
+	mIsReusable(false)
 {
 	if (p.functor.name.isChosen())
 	{
@@ -432,7 +433,8 @@ LLNotification::LLNotification(const LLSD& sd) :
 	mRespondedTo(false),
 	mCancelled(false),
 	mIgnored(false),
-	mResponderObj(NULL)
+	mResponderObj(NULL),
+	mIsReusable(false)
 { 
 	mId.generate();
 	mSubstitutions = sd["substitutions"];
@@ -459,6 +461,7 @@ LLSD LLNotification::asLLSD()
 	output["expiry"] = mExpiresAt;
 	output["priority"] = (S32)mPriority;
 	output["responseFunctor"] = mResponseFunctorName;
+	output["reusable"] = mIsReusable;
 	return output;
 }
 
@@ -488,6 +491,7 @@ void LLNotification::updateFrom(LLNotificationPtr other)
 	mRespondedTo = other->mRespondedTo;
 	mResponse = other->mResponse;
 	mTemporaryResponder = other->mTemporaryResponder;
+	mIsReusable = other->isReusable();
 
 	update();
 }
@@ -573,9 +577,7 @@ void LLNotification::respond(const LLSD& response)
 	// and then call it
 	functor(asLLSD(), response);
 	
-	bool is_resusable = getPayload()["reusable"].asBoolean();
-
-	if (mTemporaryResponder && !is_resusable)
+	if (mTemporaryResponder && !isReusable())
 	{
 		LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName);
 		mResponseFunctorName = "";
@@ -879,11 +881,11 @@ bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPt
 		{
 			abortProcessing = mChanged(payload);
 			// do not delete the notification to make LLChatHistory::appendMessage add notification panel to IM window
-			if( ! pNotification->getPayload()["reusable"].asBoolean() )
+			if( ! pNotification->isReusable() )
 			{
 				mItems.erase(pNotification);
+				onDelete(pNotification);
 			}
-			onDelete(pNotification);
 		}
 	}
 	return abortProcessing;
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index a516a6723ecbc3887ff034c3190c9c8a38c59fe7..400491a1544ce55371d0f02c6dd50dbf2b83fcab 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -349,6 +349,7 @@ friend class LLNotifications;
 	ENotificationPriority mPriority;
 	LLNotificationFormPtr mForm;
 	void* mResponderObj;
+	bool mIsReusable;
 	
 	// a reference to the template
 	LLNotificationTemplatePtr mTemplatep;
@@ -517,6 +518,10 @@ friend class LLNotifications;
 	{
 		return mId;
 	}
+
+	bool isReusable() { return mIsReusable; }
+
+	void setReusable(bool reusable) { mIsReusable = reusable; }
 	
 	// comparing two notifications normally means comparing them by UUID (so we can look them
 	// up quickly this way)
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index 8efa814a2eb1b95f38eda7f252634e73571610ad..1f92686a43606edd7f9712be798612367f493b8b 100644
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -1137,7 +1137,7 @@ void im_chiclet_callback(LLChicletPanel* panel, const LLSD& data){
 	S32 unread = data["participant_unread"].asInteger();
 
 	LLIMFloater* im_floater = LLIMFloater::findInstance(session_id);
-	if (im_floater && im_floater->getVisible())
+	if (im_floater && im_floater->getVisible() && im_floater->hasFocus())
 	{
 		unread = 0;
 	}
diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp
index f0e195c37a8f7ed3832e5e532308f5f77d49033f..91f4f57e54458b55e673b3b743bc21a4af6d2a51 100644
--- a/indra/newview/llimfloater.cpp
+++ b/indra/newview/llimfloater.cpp
@@ -128,6 +128,11 @@ void LLIMFloater::onFocusReceived()
 	LLIMModel::getInstance()->setActiveSessionID(mSessionID);
 
 	LLBottomTray::getInstance()->getChicletPanel()->setChicletToggleState(mSessionID, true);
+
+	if (getVisible())
+	{
+		LLIMModel::instance().sendNoUnreadMessages(mSessionID);
+	}
 }
 
 // virtual
@@ -609,7 +614,16 @@ void LLIMFloater::updateMessages()
 	bool use_plain_text_chat_history = gSavedSettings.getBOOL("PlainTextChatHistory");
 
 	std::list<LLSD> messages;
-	LLIMModel::instance().getMessages(mSessionID, messages, mLastMessageIndex+1);
+
+	// we shouldn't reset unread message counters if IM floater doesn't have focus
+	if (hasFocus())
+	{
+		LLIMModel::instance().getMessages(mSessionID, messages, mLastMessageIndex+1);
+	}
+	else
+	{
+		LLIMModel::instance().getMessagesSilently(mSessionID, messages, mLastMessageIndex+1);
+	}
 
 	if (messages.size())
 	{
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 6ce06adc80f4edb1f1659037da09276d9659f2a2..7a4febec20069d2bda6c74db2dc07fda6e527f00 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -608,10 +608,10 @@ bool LLIMModel::clearSession(const LLUUID& session_id)
 	return true;
 }
 
-void LLIMModel::getMessages(const LLUUID& session_id, std::list<LLSD>& messages, int start_index)
+void LLIMModel::getMessagesSilently(const LLUUID& session_id, std::list<LLSD>& messages, int start_index)
 {
 	LLIMSession* session = findIMSession(session_id);
-	if (!session) 
+	if (!session)
 	{
 		llwarns << "session " << session_id << "does not exist " << llendl;
 		return;
@@ -619,7 +619,7 @@ void LLIMModel::getMessages(const LLUUID& session_id, std::list<LLSD>& messages,
 
 	int i = session->mMsgs.size() - start_index;
 
-	for (std::list<LLSD>::iterator iter = session->mMsgs.begin(); 
+	for (std::list<LLSD>::iterator iter = session->mMsgs.begin();
 		iter != session->mMsgs.end() && i > 0;
 		iter++)
 	{
@@ -628,6 +628,16 @@ void LLIMModel::getMessages(const LLUUID& session_id, std::list<LLSD>& messages,
 		messages.push_back(*iter);
 		i--;
 	}
+}
+
+void LLIMModel::sendNoUnreadMessages(const LLUUID& session_id)
+{
+	LLIMSession* session = findIMSession(session_id);
+	if (!session)
+	{
+		llwarns << "session " << session_id << "does not exist " << llendl;
+		return;
+	}
 
 	session->mNumUnread = 0;
 	session->mParticipantUnreadMessageCount = 0;
@@ -639,6 +649,13 @@ void LLIMModel::getMessages(const LLUUID& session_id, std::list<LLSD>& messages,
 	mNoUnreadMsgsSignal(arg);
 }
 
+void LLIMModel::getMessages(const LLUUID& session_id, std::list<LLSD>& messages, int start_index)
+{
+	getMessagesSilently(session_id, messages, start_index);
+
+	sendNoUnreadMessages(session_id);
+}
+
 bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text) {
 	
 	LLIMSession* session = findIMSession(session_id);
diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h
index e7404074e0475878f12468804819d99df8142734..f1693d0e17564b64843e5bc6a1d2b3183a76eac3 100644
--- a/indra/newview/llimview.h
+++ b/indra/newview/llimview.h
@@ -177,6 +177,17 @@ class LLIMModel :  public LLSingleton<LLIMModel>
 	 */
 	bool clearSession(const LLUUID& session_id);
 
+	/**
+	 * Populate supplied std::list with messages starting from index specified by start_index without
+	 * emitting no unread messages signal.
+	 */
+	void getMessagesSilently(const LLUUID& session_id, std::list<LLSD>& messages, int start_index = 0);
+
+	/**
+	 * Sends no unread messages signal.
+	 */
+	void sendNoUnreadMessages(const LLUUID& session_id);
+
 	/**
 	 * Populate supplied std::list with messages starting from index specified by start_index
 	 */
diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h
index 62008b91a0724a907ced74ca28950dd52bf531c5..1dc0e414a26698108afc73d8ed53476f6e18b107 100644
--- a/indra/newview/llnotificationhandler.h
+++ b/indra/newview/llnotificationhandler.h
@@ -290,6 +290,11 @@ class LLHandlerUtil
 	 */
 	static bool canAddNotifPanelToIM(const LLNotificationPtr& notification);
 
+	/**
+	 * Checks whether notification can be used multiple times or not.
+	 */
+	static bool isNotificationReusable(const LLNotificationPtr& notification);
+
 	/**
 	 * Checks if passed notification can create IM session and be written into it.
 	 *
diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp
index 55e0f33121be85edd00309794c329641c4146b93..d3ad61128dbf8e5bb369da209ee6e97348bca1ec 100644
--- a/indra/newview/llnotificationhandlerutil.cpp
+++ b/indra/newview/llnotificationhandlerutil.cpp
@@ -176,6 +176,14 @@ bool LLHandlerUtil::canAddNotifPanelToIM(const LLNotificationPtr& notification)
 					|| TELEPORT_OFFERED == notification->getName();
 }
 
+// static
+bool LLHandlerUtil::isNotificationReusable(const LLNotificationPtr& notification)
+{
+	return OFFER_FRIENDSHIP == notification->getName()
+		|| USER_GIVE_ITEM == notification->getName()
+		|| TELEPORT_OFFERED == notification->getName();
+}
+
 // static
 bool LLHandlerUtil::canSpawnSessionAndLogToIM(const LLNotificationPtr& notification)
 {
diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp
index 0a42d8adbeefa886961bf1e86b56e81a7ecaefe3..e93aec9d018ee93c93a45e11250cbc4d5ecb7ffc 100644
--- a/indra/newview/llnotificationofferhandler.cpp
+++ b/indra/newview/llnotificationofferhandler.cpp
@@ -103,6 +103,8 @@ bool LLOfferHandler::processNotification(const LLSD& notify)
 		}
 		else
 		{
+			notification->setReusable(LLHandlerUtil::isNotificationReusable(notification));
+
 			LLUUID session_id;
 			if (LLHandlerUtil::canSpawnIMSession(notification))
 			{
diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp
index d7a3bc146230d96717e2ebc7fdf237028bb90232..907740a88e27f46ec826b79df6b498a08c234029 100644
--- a/indra/newview/lltoastnotifypanel.cpp
+++ b/indra/newview/lltoastnotifypanel.cpp
@@ -205,7 +205,7 @@ mCloseNotificationOnDestroy(true)
 	mInfoPanel->setFollowsAll();
 	snapToMessageHeight(mTextBox, MAX_LENGTH);
 
-	if(notification->getPayload()["reusable"].asBoolean())
+	if(notification->isReusable())
 	{
 		mButtonClickConnection = sButtonClickSignal.connect(
 			boost::bind(&LLToastNotifyPanel::onToastPanelButtonClicked, this, _1, _2));
@@ -288,6 +288,8 @@ LLToastNotifyPanel::~LLToastNotifyPanel()
 	std::for_each(mBtnCallbackData.begin(), mBtnCallbackData.end(), DeletePointer());
 	if (mCloseNotificationOnDestroy && LLNotificationsUtil::find(mNotification->getID()) != NULL)
 	{
+		// let reusable notification be deleted
+		mNotification->setReusable(false);
 		LLNotifications::getInstance()->cancel(mNotification);
 	}
 }
@@ -473,7 +475,7 @@ void LLToastNotifyPanel::onClickButton(void* data)
 		response[button_name] = true;
 	}
 	
-	bool is_reusable = self->mNotification->getPayload()["reusable"].asBoolean();
+	bool is_reusable = self->mNotification->isReusable();
 	// When we call respond(), LLOfferInfo will delete itself in inventory_offer_callback(), 
 	// lets copy it while it's still valid.
 	LLOfferInfo* old_info = static_cast<LLOfferInfo*>(self->mNotification->getResponder());
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 7ecff4c2d85f3fa81569069c6a807185252887e9..3d0dfbed402abdb8907dc5a1c553c27047892a91 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -1590,7 +1590,6 @@ void inventory_offer_handler(LLOfferInfo* info)
 	}
 	else // Agent -> Agent Inventory Offer
 	{
-		payload["reusable"] = true;
 		p.responder = info;
 		// Note: sets inventory_offer_callback as the callback
 		// *TODO fix memory leak
@@ -2323,7 +2322,6 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 				payload["from_id"] = from_id;
 				payload["lure_id"] = session_id;
 				payload["godlike"] = FALSE;
-				payload["reusable"] = true;
 				LLNotificationsUtil::add("TeleportOffered", args, payload);
 			}
 		}
@@ -2392,7 +2390,6 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 				}
 				else
 				{
-					payload["reusable"] = true;
 					args["[MESSAGE]"] = message;
 				        LLNotificationsUtil::add("OfferFriendship", args, payload);
 				}