예제 #1
0
void LLFloaterIMPanel::addTypingIndicator(const std::string &name)
{
	// we may have lost a "stop-typing" packet, don't add it twice
	if (!mOtherTyping)
	{
		mTypingLineStartIndex = mHistoryEditor->getWText().length();
		LLUIString typing_start = sTypingStartString;
		typing_start.setArg("[NAME]", name);
		addHistoryLine(typing_start, gSavedSettings.getColor4("SystemChatColor"), false);
		mOtherTypingName = name;
		mOtherTyping = true;
	}
	// MBW -- XXX -- merge from release broke this (argument to this function changed from an LLIMInfo to a name)
	// Richard will fix.
//	mSpeakers->setSpeakerTyping(im_info->mFromID, TRUE);
}
예제 #2
0
//
// LLFloaterIMPanel
//
LLFloaterIMPanel::LLFloaterIMPanel(
	const std::string& log_label,
	const LLUUID& session_id,
	const LLUUID& other_participant_id,
	const EInstantMessage& dialog,
	const LLDynamicArray<LLUUID>& ids) :
	LLFloater(log_label, LLRect(), log_label),
	mStartCallOnInitialize(false),
	mInputEditor(NULL),
	mHistoryEditor(NULL),
	mSessionInitialized(false),
	mSessionStartMsgPos(0),
	mSessionType(P2P_SESSION),
	mSessionUUID(session_id),
	mLogLabel(log_label),
	mQueuedMsgsForInit(),
	mOtherParticipantUUID(other_participant_id),
	mDialog(dialog),
	mTyping(false),
	mTypingLineStartIndex(0),
	mOtherTyping(false),
	mOtherTypingName(),
	mNumUnreadMessages(0),
	mSentTypingState(true),
	mShowSpeakersOnConnect(true),
	mDing(false),
	mRPMode(false),
	mTextIMPossible(true),
	mCallBackEnabled(true),
	mSpeakers(NULL),
	mSpeakerPanel(NULL),
	mVoiceChannel(NULL),
	mFirstKeystrokeTimer(),
	mLastKeystrokeTimer()
{
	if (mOtherParticipantUUID.isNull())
	{
		llwarns << "Other participant is NULL" << llendl;
	}

	// set P2P type by default
	static LLCachedControl<bool> concise_im("UseConciseIMButtons");
	std::string xml_filename = concise_im ? "floater_instant_message_concisebuttons.xml" : "floater_instant_message.xml";


	switch(mDialog)
	{
	case IM_SESSION_GROUP_START:
	case IM_SESSION_INVITE:
	case IM_SESSION_CONFERENCE_START:
		mCommitCallbackRegistrar.add("FlipDing", boost::bind<void>(boost::lambda::_1 = !boost::lambda::_1, boost::ref(mDing)));
		// determine whether it is group or conference session
		if (gAgent.isInGroup(mSessionUUID))
		{
			static LLCachedControl<bool> concise("UseConciseGroupChatButtons");
			xml_filename = concise ? "floater_instant_message_group_concisebuttons.xml" : "floater_instant_message_group.xml";
			mSessionType = GROUP_SESSION;
		}
		else
		{
			static LLCachedControl<bool> concise("UseConciseConferenceButtons");
			xml_filename = concise ? "floater_instant_message_ad_hoc_concisebuttons.xml" : "floater_instant_message_ad_hoc.xml";
			mSessionType = ADHOC_SESSION;
		}
		mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this);
		mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, mLogLabel);
		break;
	// just received text from another user
	case IM_NOTHING_SPECIAL:
		mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionUUID);
		mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionUUID);
		// fallthrough
	case IM_SESSION_P2P_INVITE:
		mVoiceChannel = new LLVoiceChannelP2P(mSessionUUID, mLogLabel, mOtherParticipantUUID);
		LLAvatarTracker::instance().addParticularFriendObserver(mOtherParticipantUUID, this);
		break;
	default:
		llwarns << "Unknown session type" << llendl;
		break;
	}

	mSpeakers = new LLIMSpeakerMgr(mVoiceChannel);

	LLUICtrlFactory::getInstance()->buildFloater(this,
								xml_filename,
								&getFactoryMap(),
								FALSE);

	// enable line history support for instant message bar
	mInputEditor->setEnableLineHistory(TRUE);

	if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") )
	{
		LLLogChat::loadHistory(mLogLabel,
				       &chatFromLogFile,
				       (void *)this);
	}

	if ( !mSessionInitialized )
	{
		if ( !send_start_session_messages(
				 mSessionUUID,
				 mOtherParticipantUUID,
				 ids,
				 mDialog) )
		{
			//we don't need to need to wait for any responses
			//so we're already initialized
			mSessionInitialized = true;
		}
		else
		{
			//locally echo a little "starting session" message
			LLUIString session_start = sSessionStartString;

			session_start.setArg("[NAME]", getTitle());
			mSessionStartMsgPos = mHistoryEditor->getWText().length();

			addHistoryLine(
				session_start,
				gSavedSettings.getColor4("SystemChatColor"),
				false);
		}
	}
}
예제 #3
0
// Singu Note: LLFloaterIMSession::sendMsg
void LLFloaterIMPanel::onSendMsg()
{
	if (!gAgent.isGodlike() 
		&& (mSessionType == P2P_SESSION)
		&& mOtherParticipantUUID.isNull())
	{
		llinfos << "Cannot send IM to everyone unless you're a god." << llendl;
		return;
	}

	if (mInputEditor)
	{
		LLWString text = mInputEditor->getConvertedText();
		if(!text.empty())
		{
			// store sent line in history, duplicates will get filtered
			if (mInputEditor) mInputEditor->updateHistory();
			// Truncate and convert to UTF8 for transport
			std::string utf8_text = wstring_to_utf8str(text);
			bool action = convert_roleplay_text(utf8_text);
			if (!action && mRPMode)
				utf8_text = "((" + utf8_text + "))";

// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0)
			if ( (RlvActions::hasBehaviour(RLV_BHVR_SENDIM)) || (RlvActions::hasBehaviour(RLV_BHVR_SENDIMTO)) )
			{
				bool fRlvFilter = false;
				switch (mSessionType)
				{
					case P2P_SESSION:	// One-on-one IM
						fRlvFilter = !RlvActions::canSendIM(mOtherParticipantUUID);
						break;
					case GROUP_SESSION:	// Group chat
						fRlvFilter = !RlvActions::canSendIM(mSessionUUID);
						break;
					case ADHOC_SESSION:	// Conference chat: allow if all participants can be sent an IM
						{
							if (!mSpeakers)
							{
								fRlvFilter = true;
								break;
							}

							LLSpeakerMgr::speaker_list_t speakers;
							mSpeakers->getSpeakerList(&speakers, TRUE);
							for (LLSpeakerMgr::speaker_list_t::const_iterator itSpeaker = speakers.begin(); 
									itSpeaker != speakers.end(); ++itSpeaker)
							{
								const LLSpeaker* pSpeaker = *itSpeaker;
								if ( (gAgentID != pSpeaker->mID) && (!RlvActions::canSendIM(pSpeaker->mID)) )
								{
									fRlvFilter = true;
									break;
								}
							}
						}
						break;
					default:
						fRlvFilter = true;
						break;
				}

				if (fRlvFilter)
				{
					utf8_text = RlvStrings::getString(RLV_STRING_BLOCKED_SENDIM);
				}
			}
// [/RLVa:KB]

			if ( mSessionInitialized )
			{
				// Split messages that are too long, same code like in llimpanel.cpp
				U32 split = MAX_MSG_BUF_SIZE - 1;
				U32 pos = 0;
				U32 total = utf8_text.length();

				while (pos < total)
				{
					U32 next_split = split;

					if (pos + next_split > total)
					{
						next_split = total - pos;
					}
					else
					{
						// don't split utf-8 bytes
						while (U8(utf8_text[pos + next_split]) != 0x20	// space
							&& U8(utf8_text[pos + next_split]) != 0x21	// !
							&& U8(utf8_text[pos + next_split]) != 0x2C	// ,
							&& U8(utf8_text[pos + next_split]) != 0x2E	// .
							&& U8(utf8_text[pos + next_split]) != 0x3F	// ?
							&& next_split > 0)
						{
							--next_split;
						}

						if (next_split == 0)
						{
							next_split = split;
							LL_WARNS("Splitting") << "utf-8 couldn't be split correctly" << LL_ENDL;
						}
						else
						{
							++next_split;
						}
					}

					std::string send = utf8_text.substr(pos, next_split);
					pos += next_split;
					LL_DEBUGS("Splitting") << "Pos: " << pos << " next_split: " << next_split << LL_ENDL;

					deliver_message(send,
									mSessionUUID,
									mOtherParticipantUUID,
									mDialog);
				}

				// local echo
				if((mSessionType == P2P_SESSION) &&
				   (mOtherParticipantUUID.notNull()))
				{
					std::string name;
					gAgent.buildFullname(name);

					// Look for actions here.
					if (action)
					{
						utf8_text.replace(0,3,"");
					}
					else
					{
						utf8_text.insert(0, ": ");
					}

					bool other_was_typing = mOtherTyping;
					addHistoryLine(utf8_text, gSavedSettings.getColor("UserChatColor"), true, gAgentID, name);
					if (other_was_typing) addTypingIndicator(mOtherTypingName);
				}
			}
			else
			{
				//queue up the message to send once the session is
				//initialized
				mQueuedMsgsForInit.append(utf8_text);
			}
		}

		LLViewerStats::getInstance()->incStat(LLViewerStats::ST_IM_COUNT);

		mInputEditor->setText(LLStringUtil::null);
	}

	// Don't need to actually send the typing stop message, the other
	// client will infer it from receiving the message.
	mTyping = false;
	mSentTypingState = true;
}
예제 #4
0
LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label,
								   const LLUUID& session_id,
								   const LLUUID& other_participant_id,
								   const std::vector<LLUUID>& ids,
								   EInstantMessage dialog)
:	LLFloater(session_id),
	mInputEditor(NULL),
	mHistoryEditor(NULL),
	mSessionUUID(session_id),
	mSessionLabel(session_label),
	mSessionInitialized(FALSE),
	mSessionStartMsgPos(0),
	mOtherParticipantUUID(other_participant_id),
	mDialog(dialog),
	mSessionInitialTargetIDs(ids),
	mTyping(FALSE),
	mOtherTyping(FALSE),
	mTypingLineStartIndex(0),
	mSentTypingState(TRUE),
	mNumUnreadMessages(0),
	mShowSpeakersOnConnect(TRUE),
	mTextIMPossible(TRUE),
	mProfileButtonEnabled(TRUE),
	mCallBackEnabled(TRUE),
	mSpeakerPanel(NULL),
	mFirstKeystrokeTimer(),
	mLastKeystrokeTimer()
{
	std::string xml_filename;
	switch(mDialog)
	{
	case IM_SESSION_GROUP_START:
		mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this);
		xml_filename = "floater_instant_message_group.xml";
		break;
	case IM_SESSION_INVITE:
		mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this);
		if (gAgent.isInGroup(mSessionUUID))
		{
			xml_filename = "floater_instant_message_group.xml";
		}
		else // must be invite to ad hoc IM
		{
			xml_filename = "floater_instant_message_ad_hoc.xml";
		}
		break;
	case IM_SESSION_P2P_INVITE:
		xml_filename = "floater_instant_message.xml";
		break;
	case IM_SESSION_CONFERENCE_START:
		mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this);
		xml_filename = "floater_instant_message_ad_hoc.xml";
		break;
	// just received text from another user
	case IM_NOTHING_SPECIAL:

		xml_filename = "floater_instant_message.xml";
		
		mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionUUID);
		mProfileButtonEnabled = LLVoiceClient::getInstance()->isParticipantAvatar(mSessionUUID);
		mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionUUID);
		break;
	default:
		llwarns << "Unknown session type" << llendl;
		xml_filename = "floater_instant_message.xml";
		break;
	}

	LLUICtrlFactory::getInstance()->buildFloater(this, xml_filename, NULL);

	setTitle(mSessionLabel);
	mInputEditor->setMaxTextLength(1023);
	// enable line history support for instant message bar
	mInputEditor->setEnableLineHistory(TRUE);

	//*TODO we probably need the same "awaiting message" thing in LLIMFloater
	LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(mSessionUUID);
	if (!im_session)
	{
		llerror("im session with id " + mSessionUUID.asString() + " does not exist!", 0);
		return;
	}

	mSessionInitialized =  im_session->mSessionInitialized;
	if (!mSessionInitialized)
	{
		//locally echo a little "starting session" message
		LLUIString session_start = sSessionStartString;

		session_start.setArg("[NAME]", getTitle());
		mSessionStartMsgPos = 
			mHistoryEditor->getWText().length();

		addHistoryLine(
			session_start,
			LLUIColorTable::instance().getColor("SystemChatColor"),
			false);
	}
}