bool LLScriptFloater::isScriptTextbox(LLNotificationPtr notification)
{
	// get a form for the notification
	LLNotificationFormPtr form(notification->getForm());

	if (form)
	{
		// get number of elements in the form
		int num_options = form->getNumElements();
	
		// if ANY of the buttons have the magic lltextbox string as
		// name, then treat the whole dialog as a simple text entry
		// box (i.e. mixed button and textbox forms are not supported)
		for (int i=0; i<num_options; ++i)
		{
			LLSD form_element = form->getElement(i);
			if (form_element["name"].asString() == TEXTBOX_MAGIC_TOKEN)
			{
				return true;
			}
		}
	}

	return false;
}
Example #2
0
bool GrowlManager::onLLNotification(const LLSD& notice)
{
	if(notice["sigtype"].asString() != "add")
		return false;
	LLNotificationPtr notification = LLNotifications::instance().find(notice["id"].asUUID());
	std::string name = notification->getName();
	LLSD substitutions = notification->getSubstitutions();
	if(gGrowlManager->mNotifications.find(name) != gGrowlManager->mNotifications.end())
	{
		GrowlNotification* growl_notification = &gGrowlManager->mNotifications[name];
		std::string body = "";
		std::string title = "";
		if(growl_notification->useDefaultTextForTitle)
			title = notification->getMessage();
		else if(growl_notification->growlTitle != "")
		{
			title = growl_notification->growlTitle;
			LLStringUtil::format(title, substitutions);
		}
		if(growl_notification->useDefaultTextForBody)
			body = notification->getMessage();
		else if(growl_notification->growlBody != "")
		{
			body = growl_notification->growlBody;
			LLStringUtil::format(body, substitutions);
		}
		//TM:FS no need to log whats sent to growl
		//LL_INFOS("GrowlLLNotification") << "Notice: " << title << ": " << body << LL_ENDL;
		if(name == "ObjectGiveItem" || name == "ObjectGiveItemUnknownUser" || name == "UserGiveItem" || name == "SystemMessageTip")
		{
			LLUrlMatch urlMatch;
			LLWString newLine = utf8str_to_wstring(body);
			LLWString workLine = utf8str_to_wstring(body);
			while (LLUrlRegistry::instance().findUrl(workLine, urlMatch) && !urlMatch.getUrl().empty())
			{
				LLWStringUtil::replaceString(newLine, utf8str_to_wstring(urlMatch.getUrl()), utf8str_to_wstring(urlMatch.getLabel()));

				// Remove the URL from the work line so we don't end in a loop in case of regular URLs!
				// findUrl will always return the very first URL in a string
				workLine = workLine.erase(0, urlMatch.getEnd() + 1);
			}
			body = wstring_to_utf8str(newLine);
		}
		gGrowlManager->notify(title, body, growl_notification->growlName);
	}
	return false;
}
// static
void LLHandlerUtil::updateVisibleIMFLoaterMesages(const LLNotificationPtr& notification)
{
	const std::string name = LLHandlerUtil::getSubstitutionName(notification);
	LLUUID from_id = notification->getPayload()["from_id"];
	LLUUID session_id = spawnIMSession(name, from_id);

	updateIMFLoaterMesages(session_id);
}
void LLNotifications::update(const LLNotificationPtr pNotif)
{
	LLNotificationSet::iterator it=mItems.find(pNotif);
	if (it != mItems.end())
	{
		updateItem(LLSD().insert("sigtype", "change").insert("id", pNotif->id()), pNotif);
	}
}
void UpdateItem::doit(void) const
{
  LLNotifications::getInstance()->updateItem(LLSD().with("sigtype", sigtype).with("id", pNotif->id()), pNotif);
  if (!strcmp(sigtype, "delete"))
  {
	pNotif->cancel();
  }
}
void LLScriptHandler::onDeleteToast(LLToast* toast)
{
	// send a signal to the counter manager
	mDelNotificationSignal();

	// send a signal to a listener to let him perform some action
	// in this case listener is a SysWellWindow and it will remove a corresponding item from its list
	mNotificationIDSignal(toast->getNotificationID());

	LLNotificationPtr notification = LLNotifications::getInstance()->find(toast->getNotificationID());
	
	if( notification && 
		(SCRIPT_DIALOG == notification->getName() || SCRIPT_DIALOG_GROUP == notification->getName()) )
	{
		LLScriptFloaterManager::getInstance()->onRemoveNotification(notification->getID());
	}
}
Example #7
0
void LLVoiceChannelGroup::handleError(EStatusType status)
{
	std::string notify;
	switch(status)
	{
	case ERROR_CHANNEL_LOCKED:
	case ERROR_CHANNEL_FULL:
		notify = "VoiceChannelFull";
		break;
	case ERROR_NOT_AVAILABLE:
		//clear URI and credentials
		//set the state to be no info
		//and activate
		if ( mRetries > 0 )
		{
			mRetries--;
			mIsRetrying = TRUE;
			mIgnoreNextSessionLeave = TRUE;

			getChannelInfo();
			return;
		}
		else
		{
			notify = "VoiceChannelJoinFailed";
			mRetries = DEFAULT_RETRIES_COUNT;
			mIsRetrying = FALSE;
		}

		break;

	case ERROR_UNKNOWN:
	default:
		break;
	}

	// notification
	if (!notify.empty())
	{
		LLNotificationPtr notification = LLNotificationsUtil::add(notify, mNotifyArgs);
		// echo to im window
		gIMMgr->addMessage(mSessionID, LLUUID::null, SYSTEM_FROM, notification->getMessage());
	}

	LLVoiceChannel::handleError(status);
}
// static
void LLHandlerUtil::logToIMP2P(const LLNotificationPtr& notification, bool to_file_only)
{
	const std::string name = LLHandlerUtil::getSubstitutionName(notification);

	const std::string& session_name = notification->getPayload().has(
			"SESSION_NAME") ? notification->getPayload()["SESSION_NAME"].asString() : name;

	// don't create IM p2p session with objects, it's necessary condition to log
	if (notification->getName() != OBJECT_GIVE_ITEM)
	{
		LLUUID from_id = notification->getPayload()["from_id"];

		//there still appears a log history file with weird name " .txt"
		if (" " == session_name || "{waiting}" == session_name || "{nobody}" == session_name)
		{
			llwarning("Weird session name (" + session_name + ") for notification " + notification->getName(), 666)
		}

		if(to_file_only)
		{
			logToIM(IM_NOTHING_SPECIAL, session_name, "", notification->getMessage(),
					LLUUID(), LLUUID());
		}
		else
		{
			logToIM(IM_NOTHING_SPECIAL, session_name, INTERACTIVE_SYSTEM_FROM, notification->getMessage(),
					from_id, LLUUID());
		}
	}
Example #9
0
//--------------------------------------------------------------------------
bool LLGroupHandler::processNotification(const LLSD& notify)
{
	if(!mChannel)
	{
		return false;
	}

	LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID());

	if(!notification)
		return false;

	// arrange a channel on a screen
	if(!mChannel->getVisible())
	{
		initChannel();
	}
	
	if(notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "change")
	{
		LLHandlerUtil::logGroupNoticeToIMGroup(notification);

		LLPanel* notify_box = new LLToastGroupNotifyPanel(notification);
		LLToast::Params p;
		p.notif_id = notification->getID();
		p.notification = notification;
		p.panel = notify_box;
		p.on_delete_toast = boost::bind(&LLGroupHandler::onDeleteToast, this, _1);

		LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);
		if(channel)
			channel->addToast(p);

		// send a signal to the counter manager
		mNewNotificationSignal();

		LLGroupActions::refresh_notices();
	}
	else if (notify["sigtype"].asString() == "delete")
	{
		mChannel->killToastByNotificationID(notification->getID());
	}
	return false;
}
Example #10
0
//--------------------------------------------------------------------------
bool LLNotificationManager::onNotification(const LLSD& notify)
{
	LLSysHandler* handle = NULL;

	LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID());
	
	if (!notification) 
		return false;

	std::string notification_type = notification->getType();
	handle = static_cast<LLSysHandler*>(mNotifyHandlers[notification_type].get());

	if(!handle)
		return false;
	
	// If we don't return false, everything that follows breaks.
	handle->processNotification(notify);
	return false;
}
// static
bool LLHandlerUtil::canSpawnIMSession(const LLNotificationPtr& notification)
{
//	return OFFER_FRIENDSHIP == notification->getName()
//			|| USER_GIVE_ITEM == notification->getName()
//			|| TELEPORT_OFFERED == notification->getName();
// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a
//	return 
//		(canEmbedNotificationInIM(notification)) && 
//		( (OFFER_FRIENDSHIP == notification->getName()) || (USER_GIVE_ITEM == notification->getName()) || 
//		  (TELEPORT_OFFERED == notification->getName()) );
// [/SL:KB]
// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h
	return 
		(canEmbedNotificationInIM(notification)) && 
		( (!rlv_handler_t::isEnabled()) || (gRlvHandler.canStartIM(notification->getPayload()["from_id"].asUUID())) ) &&
		( (OFFER_FRIENDSHIP == notification->getName()) || (USER_GIVE_ITEM == notification->getName()) || 
		  (TELEPORT_OFFERED == notification->getName()) );
// [/RLVa:KB]
}
bool LLNotifications::uniqueHandler(const LLSD& payload)
{
	LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
	if (pNotif && pNotif->hasUniquenessConstraints()) 
	{
		if (payload["sigtype"].asString() == "add")
		{
			// not a duplicate according to uniqueness criteria, so we keep it
			// and store it for future uniqueness checks
			mUniqueNotifications.insert(std::make_pair(pNotif->getName(), pNotif));
		}
		else if (payload["sigtype"].asString() == "delete")
		{
			mUniqueNotifications.erase(pNotif->getName());
		}
	}

	return false;
}
// static
LLScriptFloaterManager::EObjectType LLScriptFloaterManager::getObjectType(const LLUUID& notification_id)
{
	if(notification_id.isNull())
	{
		llwarns << "Invalid notification ID" << llendl;
		return OBJ_UNKNOWN;
	}

	static const object_type_map TYPE_MAP = initObjectTypeMap();

	LLNotificationPtr notification = LLNotificationsUtil::find(notification_id);
	object_type_map::const_iterator it = TYPE_MAP.find(notification->getName());
	if(it != TYPE_MAP.end())
	{
		return it->second;
	}

	llwarns << "Unknown object type" << llendl;
	return OBJ_UNKNOWN;
}
void LLNotifications::add(const LLNotificationPtr pNotif)
{
	// first see if we already have it -- if so, that's a problem
	LLNotificationSet::iterator it=mItems.find(pNotif);
	if (it != mItems.end())
	{
		llerrs << "Notification added a second time to the master notification channel." << llendl;
	}

	updateItem(LLSD().insert("sigtype", "add").insert("id", pNotif->id()), pNotif);
}
// static
void LLHandlerUtil::logToNearbyChat(const LLNotificationPtr& notification, EChatSourceType type)
{
	LLNearbyChat* nearby_chat = LLNearbyChat::getInstance();
	if(nearby_chat)
	{
		LLChat chat_msg(notification->getMessage());
		chat_msg.mSourceType = type;
		chat_msg.mFromName = SYSTEM_FROM;
		chat_msg.mFromID = LLUUID::null;
		nearby_chat->addMessage(chat_msg);
	}
}
// static
std::string LLHandlerUtil::getSubstitutionName(const LLNotificationPtr& notification)
{
	std::string res = notification->getSubstitutions().has("NAME")
		? notification->getSubstitutions()["NAME"]
		: notification->getSubstitutions()["[NAME]"];
	if (res.empty())
	{
		LLUUID from_id = notification->getPayload()["FROM_ID"];

		//*TODO all keys everywhere should be made of the same case, there is a mix of keys in lower and upper cases
		if (from_id.isNull()) 
		{
			from_id = notification->getPayload()["from_id"];
		}
		if(!gCacheName->getFullName(from_id, res))
		{
			res = "";
		}
	}
	return res;
}
// static
bool LLHandlerUtil::canSpawnToast(const LLNotificationPtr& notification)
{
	if(INVENTORY_DECLINED == notification->getName() 
		|| INVENTORY_ACCEPTED == notification->getName())
	{
		// return false for inventory accepted/declined notifications if respective IM window is open (EXT-5909)
		return ! isIMFloaterOpened(notification);
	}

	if(FRIENDSHIP_ACCEPTED == notification->getName())
	{
		// don't show FRIENDSHIP_ACCEPTED if IM window is opened and focused - EXT-6441
		return ! isIMFloaterFocused(notification);
	}

	if(OFFER_FRIENDSHIP == notification->getName()
		|| USER_GIVE_ITEM == notification->getName()
		|| TELEPORT_OFFERED == notification->getName())
	{
		// When ANY offer arrives, show toast, unless IM window is already open - EXT-5904
		return ! isIMFloaterOpened(notification);
	}

	return true;
}
bool handleIgnoredNotification(const LLSD& payload)
{
	if (payload["sigtype"].asString() == "add")
	{
		LLNotificationPtr pNotif = LLNotifications::instance().find(payload["id"].asUUID());
		if (!pNotif) return false;

		LLNotificationFormPtr form = pNotif->getForm();
		LLSD response;
		switch(form->getIgnoreType())
		{
		case LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE:
			response = pNotif->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON);
			break;
		case LLNotificationForm::IGNORE_WITH_LAST_RESPONSE:
			response = LLUI::sIgnoresGroup->getLLSD("Default" + pNotif->getName());
			break;
		case LLNotificationForm::IGNORE_SHOW_AGAIN:
			break;
		default:
			return false;
		}
		pNotif->setIgnored(true);
		pNotif->respond(response);
		return true; 	// don't process this item any further
	}
	return false;
}
static void on_avatar_name_cache_notify(const LLUUID& agent_id,
										const LLAvatarName& av_name,
										bool online,
										LLSD payload)
{
	// Popup a notify box with online status of this agent
	// Use display name only because this user is your friend
	LLSD args;
	args["NAME"] = av_name.mDisplayName;

	LLNotificationPtr notification;
	if (online)
	{
		notification =
			LLNotificationsUtil::add("FriendOnline",
									 args,
									 payload.with("respond_on_mousedown", TRUE),
									 boost::bind(&LLAvatarActions::startIM, agent_id));
	}
	else
	{
		notification =
			LLNotificationsUtil::add("FriendOffline", args, payload);
	}

	// If there's an open IM session with this agent, send a notification there too.
	LLUUID session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, agent_id);
	std::string notify_msg = notification->getMessage();
	LLIMModel::instance().proccessOnlineOfflineNotification(session_id, notify_msg);

	// If desired, also send it to nearby chat, this allows friends'
	// online/offline times to be referenced in chat & logged.
	if (gSavedSettings.getBOOL("OnlineOfflinetoNearbyChat")) {
		LLChat chat;
		chat.mText = notify_msg;
		chat.mSourceType = CHAT_SOURCE_SYSTEM;
		args["type"] = LLNotificationsUI::NT_NEARBYCHAT;
		LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args);
	}
}
// static
bool LLHandlerUtil::canSpawnToast(const LLNotificationPtr& notification)
{
	if(INVENTORY_DECLINED == notification->getName() 
		|| INVENTORY_ACCEPTED == notification->getName())
	{
		// return false for inventory accepted/declined notifications if respective IM window is open (EXT-5909)
		return ! isIMFloaterOpened(notification);
	}

	if(FRIENDSHIP_ACCEPTED == notification->getName())
	{
		// don't show FRIENDSHIP_ACCEPTED if IM window is opened and focused - EXT-6441
		return ! isIMFloaterFocused(notification);
	}

	if(OFFER_FRIENDSHIP == notification->getName()
		|| USER_GIVE_ITEM == notification->getName()
		|| TELEPORT_OFFERED == notification->getName())
	{
		// When ANY offer arrives, show toast, unless IM window is already open - EXT-5904
//		return ! isIMFloaterOpened(notification);
// [SL:KB] - Patch: UI-Notifications | Checked: 2011-04-11 (Catznip-2.5.0a) | Added: Catznip-2.5.0a
		// Force a toast if the user opted not to embed notifications panels in IMs
		return (!canEmbedNotificationInIM(notification)) || (!isIMFloaterOpened(notification));
// [/SL:KB]
	}

	return true;
}
void LLPersistentNotificationStorage::saveNotifications()
{
	LL_RECORD_BLOCK_TIME(FTM_SAVE_NOTIFICATIONS);

	boost::intrusive_ptr<LLPersistentNotificationChannel> history_channel = boost::dynamic_pointer_cast<LLPersistentNotificationChannel>(LLNotifications::instance().getChannel("Persistent"));
	if (!history_channel)
	{
		return;
	}

	LLSD output = LLSD::emptyMap();
	LLSD& data = output["data"];

	for ( std::vector<LLNotificationPtr>::iterator it = history_channel->beginHistory(), end_it = history_channel->endHistory();
		it != end_it;
		++it)
	{
		LLNotificationPtr notification = *it;

		// After a notification was placed in Persist channel, it can become
		// responded, expired or canceled - in this case we are should not save it
		if(notification->isRespondedTo() || notification->isCancelled()
			|| notification->isExpired())
		{
			continue;
		}

		data.append(notification->asLLSD(true));
		if (data.size() >= gSavedSettings.getS32("MaxPersistentNotifications"))
		{
			LL_WARNS() << "Too many persistent notifications."
					<< " Saved " << gSavedSettings.getS32("MaxPersistentNotifications") << " of " << history_channel->size()
					<< " persistent notifications." << LL_ENDL;
			break;
		}

	}

	writeNotifications(output);
}
bool LLNotifications::uniqueFilter(LLNotificationPtr pNotif)
{
	if (!pNotif->hasUniquenessConstraints())
	{
		return true;
	}

	// checks against existing unique notifications
	for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName());
		existing_it != mUniqueNotifications.end();
		++existing_it)
	{
		LLNotificationPtr existing_notification = existing_it->second;
		if (pNotif != existing_notification 
			&& pNotif->isEquivalentTo(existing_notification))
		{
			return false;
		}
	}

	return true;
}
		bool matches(const LLNotificationPtr notification) const
		{
			for (std::set<std::string>::const_iterator it = mExclGroup.begin(); it
					!= mExclGroup.end(); it++)
			{
				std::string from_name = LLHandlerUtil::getSubstitutionName(notification);
				if (notification->getName() == *it && from_name == mFromName)
				{
					return true;
				}
			}
			return false;
		}
void chat_notification(const LLNotificationPtr notification)
{
	// TODO: Make a separate archive for these.
	if (gSavedSettings.getBOOL("HideNotificationsInChat")) return;
	LLChat chat(notification->getMessage());
	chat.mSourceType = CHAT_SOURCE_SYSTEM;
// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0e) | Added: RLVa-0.2.0b
	// Notices should already have their contents filtered where necessary
	if (rlv_handler_t::isEnabled())
		chat.mRlvLocFiltered = chat.mRlvNamesFiltered = true;
// [/RLVa:KB]
	LLFloaterChat::getInstance()->addChatHistory(chat);
}
LLPanelOnlineStatus::LLPanelOnlineStatus(
		const LLNotificationPtr& notification) :
	LLPanelTipToast(notification)
{

	buildFromFile(
			"panel_online_status_toast.xml");


	getChild<LLUICtrl>("avatar_icon")->setValue(notification->getPayload()["FROM_ID"]);
	getChild<LLUICtrl>("message")->setValue(notification->getMessage());

	if (notification->getPayload().has("respond_on_mousedown")
			&& notification->getPayload()["respond_on_mousedown"])
	{
		setMouseDownCallback(boost::bind(&LLNotification::respond,
				notification, notification->getResponseTemplate()));
	}

	S32 max_line_count =  gSavedSettings.getS32("TipToastMessageLineCount");
	snapToMessageHeight(getChild<LLTextBox> ("message"), max_line_count);

}
// static
void LLHandlerUtil::logToIMP2P(const LLNotificationPtr& notification, bool to_file_only)
{
	// don't create IM p2p session with objects, it's necessary condition to log
	if (notification->getName() != OBJECT_GIVE_ITEM)
	{
		LLUUID from_id = notification->getPayload()["from_id"];

		if (from_id.isNull())
		{
			llwarns << " from_id for notification " << notification->getName() << " is null " << llendl;
			return;
		}

		if(to_file_only)
		{
			gCacheName->get(from_id, false, boost::bind(&log_name_callback, _2, "", notification->getMessage(), LLUUID()));
		}
		else
		{
			gCacheName->get(from_id, false, boost::bind(&log_name_callback, _2, INTERACTIVE_SYSTEM_FROM, notification->getMessage(), from_id));
		}
	}
}
Example #27
0
//static 
bool LLNotifyBox::onNotification(const LLSD& notify)
{
	LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID());
	
	if (!notification) return false;

	if(notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "change")
	{
		//bring existing notification to top
		//This getInstance is ugly, as LLNotifyBox is derived from both LLInstanceTracker and LLEventTimer, which also is derived from its own LLInstanceTracker
		//Have to explicitly determine which getInstance function to use.
		LLNotifyBox* boxp = LLInstanceTracker<LLNotifyBox, LLUUID>::getInstance(notification->getID());
		if (boxp && !boxp->isDead())
		{
			gNotifyBoxView->showOnly(boxp);
		}
		else
		{
			bool is_script_dialog = (notification->getName() == "ScriptDialog" || notification->getName() == "ScriptDialogGroup");
			LLNotifyBox* notify_box = new LLNotifyBox(
				notification,
				is_script_dialog); //layout_script_dialog);

			gNotifyBoxView->addChild(notify_box);
		}
	}
	else if (notify["sigtype"].asString() == "delete")
	{
		LLNotifyBox* boxp = LLInstanceTracker<LLNotifyBox, LLUUID>::getInstance(notification->getID());
		if (boxp && !boxp->isDead())
		{
			boxp->close();
		}
	}

	return false;
}
//static 
bool LLNotifyBox::onNotification(const LLSD& notify)
{
	LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID());
	
	if (!notification) return false;

	if (notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "change")
	{
		if (notification->getPayload().has("SUPPRESS_TOAST"))
		{
			chat_notification(notification);
			return false;
		}
		//bring existing notification to top
		//This getInstance is ugly, as LLNotifyBox is derived from both LLInstanceTracker and LLEventTimer, which also is derived from its own LLInstanceTracker
		//Have to explicitly determine which getInstance function to use.
		LLNotifyBox* boxp = LLInstanceTracker<LLNotifyBox, LLUUID>::getInstance(notification->getID());
		if (boxp && !boxp->isDead())
		{
			gNotifyBoxView->showOnly(boxp);
		}
		else
		{
			gNotifyBoxView->addChild(new LLNotifyBox(notification));
		}
	}
	else if (notify["sigtype"].asString() == "delete")
	{
		LLNotifyBox* boxp = LLInstanceTracker<LLNotifyBox, LLUUID>::getInstance(notification->getID());
		if (boxp && !boxp->isDead())
		{
			boxp->close();
		}
	}

	return false;
}
static void on_avatar_name_cache_notify(const LLUUID& agent_id,
										const LLAvatarName& av_name,
										bool online,
										LLSD payload)
{
	// Popup a notify box with online status of this agent
	// Use display name only because this user is your friend
	LLSD args;
	args["NAME"] = av_name.getNSName(friend_name_system());
	args["STATUS"] = online ? LLTrans::getString("OnlineStatus") : LLTrans::getString("OfflineStatus");

	// Popup a notify box with online status of this agent
	LLNotificationPtr notification;
	static const LLCachedControl<S32> behavior(gSavedSettings, "LiruOnlineNotificationBehavior", 1);
	if (online && behavior)
	{
		notification =
			LLNotifications::instance().add("FriendOnlineOffline",
									 args,
									 payload,
									 behavior == 1 ? boost::bind(&LLAvatarActions::startIM, agent_id) : (LLNotificationResponder)boost::bind(LLAvatarActions::showProfile, agent_id, false));
	}
	else
	{
		notification =
			LLNotifications::instance().add("FriendOnlineOffline", args, payload);
	}

	// If there's an open IM session with this agent, send a notification there too.
	LLUUID session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, agent_id);
	if (LLFloaterIMPanel* floater = gIMMgr->findFloaterBySession(session_id))
	{
		std::string notify_msg = notification->getMessage();
		if (!notify_msg.empty())
			floater->addHistoryLine(notify_msg, gSavedSettings.getColor4("SystemChatColor"));
	}
}
bool LLNotification::isEquivalentTo(LLNotificationPtr that) const
{
	if (this->mTemplatep->mName != that->mTemplatep->mName) 
	{
		return false; // must have the same template name or forget it
	}
	if (this->mTemplatep->mUnique)
	{
		// highlander bit sez there can only be one of these
		return
			this->payloadContainsAll(that->mTemplatep->mUniqueContext) &&
			that->payloadContainsAll(this->mTemplatep->mUniqueContext);
	}
	return false; 
}