diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index aaaa8ac5a68d2b0a45ad47a92c2c27243d54941c..a8c9e6a31dcd873143f6352443c721e8bed47c92 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -67,6 +67,7 @@ include_directories(
 set(viewer_SOURCE_FILES
     llaccordionpanel.cpp
     llagent.cpp
+    llagentlistener.cpp
     llagentaccess.cpp
     llagentdata.cpp
     llagentlanguage.cpp
@@ -483,6 +484,7 @@ set(viewer_HEADER_FILES
     ViewerInstall.cmake
     llaccordionpanel.h
     llagent.h
+    llagentlistener.h
     llagentaccess.h
     llagentdata.h
     llagentlanguage.h
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index a8094a5850d3123954cdf77cba300c83636c6d06..13546347b9aa842a9ed842a164c21d7321a75ce6 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -35,6 +35,7 @@
 #include "llagent.h" 
 #include "llagentwearables.h"
 
+#include "llagentlistener.h"
 #include "llanimationstates.h"
 #include "llcallingcard.h"
 #include "llchatbar.h"
@@ -254,6 +255,7 @@ LLAgent::LLAgent() :
 	mHUDTargetZoom(1.f),
 	mHUDCurZoom(1.f),
 	mInitialized(FALSE),
+	mListener(),
 	mForceMouselook(FALSE),
 
 	mDoubleTapRunTimer(),
@@ -381,6 +383,8 @@ LLAgent::LLAgent() :
 	}
 
 	mFollowCam.setMaxCameraDistantFromSubject( MAX_CAMERA_DISTANCE_FROM_AGENT );
+
+	mListener.reset(new LLAgentListener(*this));
 }
 
 // Requires gSavedSettings to be initialized.
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index 94f6229838aa4624674749bd80add611ff19c3ab..22e7ccc0e5952f5c117b69be5b07326b5a233d40 100644
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -91,6 +91,8 @@ struct LLGroupData
 	std::string mName;
 };
 
+class LLAgentListener;
+
 //------------------------------------------------------------------------
 // LLAgent
 //------------------------------------------------------------------------
@@ -128,6 +130,8 @@ class LLAgent : public LLOldEvents::LLObservable
 	BOOL			mInitialized;
 	BOOL			mFirstLogin;
 	std::string		mMOTD; 					// Message of the day
+private:
+	boost::shared_ptr<LLAgentListener> mListener;
 
 	//--------------------------------------------------------------------
 	// Session
diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..90070b2143662b1c7ee35a9039dec00ce449cacf
--- /dev/null
+++ b/indra/newview/llagentlistener.cpp
@@ -0,0 +1,78 @@
+/**
+ * @file   llagentlistener.cpp
+ * @author Brad Kittenbrink
+ * @date   2009-07-10
+ * @brief  Implementation for llagentlistener.
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llagentlistener.h"
+
+#include "llagent.h"
+#include "llcommandhandler.h"
+#include "llslurl.h"
+#include "llurldispatcher.h"
+#include "llviewerobject.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+
+LLAgentListener::LLAgentListener(LLAgent &agent)
+  : LLDispatchListener("LLAgent", "op"),
+    mAgent(agent)
+{
+	add("requestTeleport", &LLAgentListener::requestTeleport);
+	add("requestSit", &LLAgentListener::requestSit);
+	add("requestStand", &LLAgentListener::requestStand);
+}
+
+void LLAgentListener::requestTeleport(LLSD const & event_data) const
+{
+	if(event_data["skip_confirmation"].asBoolean())
+	{
+		LLSD params(LLSD::emptyArray());
+		params.append(event_data["regionname"]);
+		params.append(event_data["x"]);
+		params.append(event_data["y"]);
+		params.append(event_data["z"]);
+		LLCommandDispatcher::dispatch("teleport", params, LLSD(), NULL, true);
+		// *TODO - lookup other LLCommandHandlers for "agent", "classified", "event", "group", "floater", "objectim", "parcel", "login", login_refresh", "balance", "chat"
+		// should we just compose LLCommandHandler and LLDispatchListener?
+	}
+	else
+	{
+		std::string url = LLSLURL::buildSLURL(event_data["regionname"].asString(), event_data["x"].asReal(), event_data["y"].asReal(), event_data["z"].asReal());
+		LLURLDispatcher::dispatch(url, NULL, false);
+	}
+}
+
+void LLAgentListener::requestSit(LLSD const & event_data) const
+{
+	//mAgent.getAvatarObject()->sitOnObject();
+	// shamelessly ripped from llviewermenu.cpp:handle_sit_or_stand()
+	// *TODO - find a permanent place to share this code properly.
+	LLViewerObject *object = gObjectList.findObject(event_data["obj_uuid"]);
+
+	if (object && object->getPCode() == LL_PCODE_VOLUME)
+	{
+		gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit);
+		gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+		gMessageSystem->addUUIDFast(_PREHASH_AgentID, mAgent.getID());
+		gMessageSystem->addUUIDFast(_PREHASH_SessionID, mAgent.getSessionID());
+		gMessageSystem->nextBlockFast(_PREHASH_TargetObject);
+		gMessageSystem->addUUIDFast(_PREHASH_TargetID, object->mID);
+		gMessageSystem->addVector3Fast(_PREHASH_Offset, LLVector3(0,0,0));
+
+		object->getRegion()->sendReliableMessage();
+	}
+}
+
+void LLAgentListener::requestStand(LLSD const & event_data) const
+{
+	mAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
+}
+
diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f0b5a54c5f0efd54b8bd116437b00779ae63879
--- /dev/null
+++ b/indra/newview/llagentlistener.h
@@ -0,0 +1,36 @@
+/**
+ * @file   llagentlistener.h
+ * @author Brad Kittenbrink
+ * @date   2009-07-09
+ * @brief  Event API for subset of LLViewerControl methods
+ * 
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+
+#ifndef LL_LLAGENTLISTENER_H
+#define LL_LLAGENTLISTENER_H
+
+#include "lleventdispatcher.h"
+
+class LLAgent;
+class LLSD;
+
+class LLAgentListener : public LLDispatchListener
+{
+public:
+	LLAgentListener(LLAgent &agent);
+
+private:
+	void requestTeleport(LLSD const & event_data) const;
+	void requestSit(LLSD const & event_data) const;
+	void requestStand(LLSD const & event_data) const;
+
+private:
+	LLAgent & mAgent;
+};
+
+#endif // LL_LLAGENTLISTENER_H
+