=== indra/newview/llviewermessage.cpp
==================================================================
--- indra/newview/llviewermessage.cpp	(/dg/branches/buildfixes)	(revision 108)
+++ indra/newview/llviewermessage.cpp	(/dg/branches/viewercomm)	(revision 108)
@@ -58,6 +58,7 @@
 #include "llteleportflags.h"
 #include "lltracker.h"
 #include "lltransactionflags.h"
+#include "llviewercommunication.h"
 #include "llwindow.h"			// shell_open()
 #include "llxfermanager.h"
 #include "message.h"
@@ -2306,18 +2307,24 @@
 
 		chat.mMuted = is_muted && !is_linden;
 		
-		
-		if (!visible_in_chat_bubble 
-			&& (is_linden || !is_busy || is_owned_by_me))
-		{
-			// show on screen and add to history
-			LLFloaterChat::addChat(chat, FALSE, FALSE);
+		bool suppress = false;
+		if ( chat.mSourceType == CHAT_SOURCE_OBJECT )
+			suppress = gViewerCommunication->parse(mesg, from_id);
+
+		if (!suppress)
+		{		
+			if (!visible_in_chat_bubble 
+				&& (is_linden || !is_busy || is_owned_by_me))
+			{
+				// show on screen and add to history
+				LLFloaterChat::addChat(chat, FALSE, FALSE);
+			}
+			else
+			{
+				// just add to chat history
+				LLFloaterChat::addChatHistory(chat);
+			}
 		}
-		else
-		{
-			// just add to chat history
-			LLFloaterChat::addChatHistory(chat);
-		}
 	}
 }
 
=== indra/newview/files.lst
==================================================================
--- indra/newview/files.lst	(/dg/branches/buildfixes)	(revision 108)
+++ indra/newview/files.lst	(/dg/branches/viewercomm)	(revision 108)
@@ -267,6 +267,7 @@
 newview/llviewchildren.cpp
 newview/llviewerassetstorage.cpp
 newview/llviewercamera.cpp
+newview/llviewercommunication.cpp
 newview/llviewercontrol.cpp
 newview/llviewerdisplay.cpp
 newview/llviewergenericmessage.cpp
=== indra/newview/llviewercommunication.cpp
==================================================================
--- indra/newview/llviewercommunication.cpp	(/dg/branches/buildfixes)	(revision 108)
+++ indra/newview/llviewercommunication.cpp	(/dg/branches/viewercomm)	(revision 108)
@@ -0,0 +1,192 @@
+/** 
+ * @file llviewercommunication.cpp
+ * @brief LLViewerCommunication implementation
+ * @author Dale Glass
+ *
+ * Copyright (c) 2005-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llviewercommunication.h"
+#include "llviewermessage.h"
+#include "llagent.h"
+#include "llviewerstats.h"
+#include "llchat.h"
+
+#include <vector>
+#include <string.h>
+
+const LLString DELIMITER        = "$";
+const LLString MAGIC_WORD       = "VwrComm";
+const LLString VERSION          = "0";
+
+const LLString VIEWER_EXTENSION = "DaleGlass.Viewer";
+
+const U32 MAX_TOKENS = 3;
+
+const U32 OFF_MAGIC     = 0;
+const U32 OFF_VERSION   = 1;
+const U32 OFF_EXTENSION = 2;
+const U32 OFF_DATA      = 3;
+
+LLViewerCommunication *gViewerCommunication = NULL;
+
+void LLViewerCircuit::sendReply(LLString& data)
+{
+	LLMessageSystem* msg = gMessageSystem;
+
+	msg->newMessageFast(_PREHASH_ChatFromViewer);
+	msg->nextBlockFast(_PREHASH_AgentData);
+	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+	msg->nextBlockFast(_PREHASH_ChatData);
+	msg->addStringFast(_PREHASH_Message, data);
+	msg->addU8Fast(_PREHASH_Type, CHAT_TYPE_WHISPER);
+	msg->addS32("Channel", mChannel);
+
+	gAgent.sendReliableMessage();
+
+	gViewerStats->incStat(LLViewerStats::ST_CHAT_COUNT);
+}
+
+std::vector<LLString> tokenize(LLString text, U32 max_tokens = 0)
+{
+	U32 count = 0;
+
+	std::vector<LLString> tokens;
+
+	LLString::size_type last_pos = text.find_first_not_of(DELIMITER, 0);
+	LLString::size_type pos      = text.find_first_of(DELIMITER, last_pos);
+
+	while(LLString::npos != pos && LLString::npos != last_pos && !(max_tokens > 0 && count >= max_tokens))
+	{
+		llinfos << "token: " << text.substr(last_pos, pos - last_pos) << llendl;
+		tokens.push_back(text.substr(last_pos, pos - last_pos));
+
+		last_pos = text.find_first_not_of(DELIMITER, pos);
+		pos      = text.find_first_of(DELIMITER, last_pos);
+
+		count++;
+	}
+
+	if (LLString::npos != last_pos)
+	{
+		// We stopped due to max token count, but there's still more data
+		// add it all as the last token
+		llinfos << "extra token: " << text.substr(last_pos) << llendl;
+		tokens.push_back(text.substr(last_pos));
+	}
+	lldebugs << "Got " << count << " tokens" << llendl;
+
+	return tokens;
+}
+
+void protocol_handler(LLString& data, LLViewerCircuit& circuit, void* userdata)
+{
+	lldebugs << data << llendl;
+	std::vector<LLString> tokens = tokenize(data);
+
+	LLString reply;
+	if ( tokens[0] == "Connect" )
+	{
+		reply = "OK";
+	} 
+	else if ( tokens[0] == "Ping" )
+	{
+		reply = "Pong";
+	}
+	else 
+	{
+		llwarns << "Unrecognized command: " << tokens[0] << ", data " << data << llendl;
+		return;
+	}
+	
+	circuit.sendReply(reply);
+}
+
+LLViewerCommunication::LLViewerCommunication()
+{
+	registerExtension( LLViewerExtension(VIEWER_EXTENSION, 1, protocol_handler, NULL, "Dale Glass", "General viewer info") );
+}
+
+bool LLViewerCommunication::parse(const LLString &text, const LLUUID& speaker)
+{
+	llinfos << "Parsing message: " << text << llendl;
+
+	std::vector<LLString> tokens = tokenize(text, MAX_TOKENS);
+
+	if ( !(tokens.size() >= MAX_TOKENS && tokens[OFF_MAGIC] == MAGIC_WORD) ) return false;	
+	llinfos << "Viewer communication detected" << llendl;
+
+	if ( !(tokens[OFF_VERSION] == VERSION) ) 
+	{
+		llwarns << "Viewer/object protocol version " << tokens[OFF_VERSION] << " not recognized" << llendl;
+		return false;
+	}
+	llinfos << "Version correct" << llendl;
+
+	// The connection step presents a small problem: To handle a command to a callback
+	// there must be a connection, but there isn't one yet. So we handle it here.
+	if ( tokens[OFF_EXTENSION] == VIEWER_EXTENSION && tokens[OFF_DATA].find("Connect$") == 0 )
+	{
+		std::vector<LLString> tmp = tokenize(tokens[OFF_DATA]);
+		if ( tmp.size() >= 2 )
+		{
+			S32 channel = atoi(tmp[1].c_str());
+			LLViewerCircuit circuit( channel );
+	
+			mCircuits[speaker] = circuit;
+			llinfos << "Connection to object " << speaker << "established on channel " << channel << llendl;
+		}
+		else
+		{
+			llwarns << "Bad connection attempt, too few tokens" << llendl;
+		}
+	}
+
+	// Find the extension
+	std::map<LLString, LLViewerExtension>::iterator iter_e = mExtensions.find(tokens[OFF_EXTENSION]);
+	if ( iter_e == mExtensions.end() )
+	{
+		llwarns << "Object requested inexistent extension " << tokens[OFF_EXTENSION] << llendl;
+		return false;
+	}
+	LLViewerExtension* ext = &iter_e->second;
+	llinfos << "Viewer extension found" << llendl;
+
+	// Find the circuit
+	std::map<LLUUID, LLViewerCircuit>::iterator iter_c = mCircuits.find(speaker);
+	if ( iter_c == mCircuits.end() )
+	{
+		llwarns << "Object " << speaker << " tried to communicate without an established connection" << llendl;
+		return false;
+	}
+	//LLViewerCircuit* circuit = &iter_c->second;
+	llinfos << "Viewer circuit found" << llendl;
+
+	ext->notify(tokens[OFF_DATA], iter_c->second);
+
+	return true;
+}
+
=== indra/newview/llstartup.cpp
==================================================================
--- indra/newview/llstartup.cpp	(/dg/branches/buildfixes)	(revision 108)
+++ indra/newview/llstartup.cpp	(/dg/branches/viewercomm)	(revision 108)
@@ -127,6 +127,7 @@
 #include "lluserauth.h"
 #include "llviewerassetstorage.h"
 #include "llviewercamera.h"
+#include "llviewercommunication.h"
 #include "llviewerdisplay.h"
 #include "llviewergenericmessage.h"
 #include "llviewergesture.h"
@@ -494,6 +495,9 @@
 		// initialize the economy
 		gGlobalEconomy = new LLGlobalEconomy();
 
+		// Initialize viewer/object communication
+		gViewerCommunication = new LLViewerCommunication();
+
 		//---------------------------------------------------------------------
 		// LibXUL (Mozilla) initialization
 		//---------------------------------------------------------------------
=== indra/newview/llviewercommunication.h
==================================================================
--- indra/newview/llviewercommunication.h	(/dg/branches/buildfixes)	(revision 108)
+++ indra/newview/llviewercommunication.h	(/dg/branches/viewercomm)	(revision 108)
@@ -0,0 +1,141 @@
+/** 
+ * @file llviewercommunication.cpp
+ * @brief LLViewerCommunication definition
+ * @author Dale Glass
+ *
+ * Copyright (c) 2005-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ */
+
+#ifndef LL_LLVIEWERCOMMUNICATION_H
+#define LL_LLVIEWERCOMMUNICATION_H
+
+#include <map>
+
+/**
+ * @brief Viewer/LSL script communication circuit
+ * This object describes a connection between the viewer and an object.
+ *
+ * When an object sends a message to the viewer, the LLViewerCommunication class
+ * calls the registered callback, and passes a reference to this object so that 
+ * it can reply to the request.
+ */
+class LLViewerCircuit
+{
+public:
+	LLViewerCircuit(U32 channel) : mChannel(channel) {};
+	LLViewerCircuit() : mChannel(0) {}
+
+	/**
+	 * @brief Returns the chat channel the object requested
+	 */
+	U32 getChannel() const { return mChannel; }
+
+	/**
+	 * @brief Sends a reply to the object that made the request
+	 * @param data Text to send
+	 */
+	void sendReply(LLString& data);
+protected:
+	U32 mChannel;
+};
+
+
+
+typedef void(*viewer_extension_callback_t)(LLString& data, LLViewerCircuit& circuit, void *user_data);
+
+
+/**
+ * @brief Viewer extension class
+ * Describes a Second Life viewer extension
+ */
+class LLViewerExtension
+{
+public:
+	/**
+	 * @brief Creates a LLViewerExtension
+	 * @param name Extension name
+	 * @param version Extension's version
+	 * @param callback Callback to call when a script tries to communicate with this extension
+	 * @param user_data arbitrary data to pass to the callback
+	 * @param author Extension's author
+	 * @param description Extension's description
+	 */
+	LLViewerExtension(const LLString& name = "<unknown>", const U32 version = 0, viewer_extension_callback_t callback = NULL, void *user_data = NULL, const LLString& author = "", const LLString& description = "") :
+		mName(name), mAuthor(author), mDescription(description), mVersion(version), mCallback(callback), mUserData(user_data) {};
+
+	LLString asString() const { return mName; }
+
+	LLString getName() const { return mName; }
+	LLString getAuthor() const { return mAuthor; }
+	LLString getDescription() const { return mDescription; }
+	U32 getVersion() const { return mVersion; }
+
+	/**
+	 * @brief Notifies the extension that a message has arrived
+	 * @param data String the object sent to the extension
+	 * @param circuit Circuit between viewer and object. Used to reply to the request.
+	 */
+	void notify(LLString& data, LLViewerCircuit& circuit) { mCallback(data, circuit, mUserData); }
+protected:
+	LLString mName;
+	LLString mAuthor;
+	LLString mDescription;
+	U32 mVersion;
+
+	viewer_extension_callback_t mCallback;
+	void *mUserData;
+};
+
+
+
+/**
+ * @brief Implements viewer/object communication
+ * This object manages the process by registering extensions and handling
+ * parsing of the protocol
+ */
+class LLViewerCommunication
+{
+public:
+	LLViewerCommunication();
+
+	/**
+	 * @brief Parses a chat message and extracts protocol data from it if present
+	 * @param text Chat message
+	 * @param speaker Speaker's key
+	 * @returns TRUE if the message was a protocol message, FALSE otherwise.
+	 */
+	bool parse(const LLString &text, const LLUUID& speaker);
+	bool parse(char *text, const LLUUID& speaker) { LLString tmp = text; return parse(tmp, speaker); }
+
+	void registerExtension(LLViewerExtension ext) { mExtensions[ext.getName()] = ext; }
+	
+
+protected:
+	std::map<LLString, LLViewerExtension> mExtensions;
+	std::map<LLUUID, LLViewerCircuit> mCircuits;
+};
+
+extern LLViewerCommunication *gViewerCommunication;
+
+#endif

Property changes on: 
___________________________________________________________________
Name: svk:merge
 +93fb72a0-b45c-4a43-a7b4-55dc9b559838:/dg/branches/buildfixes:98
  a6265765-422e-0410-accc-9fb60e44a920:/release:47
 +fac5ab44-3233-0410-a0d7-a8f4c5ff577d:/branches/buildfixes:3

