Compare commits
	
		
			No commits in common. "master" and "xassetservice" have entirely different histories. 
		
	
	
		
			master
			...
			xassetserv
		
	
		|  | @ -1,6 +1,5 @@ | |||
| .project | ||||
| .settings | ||||
| .gitignore | ||||
| *.csproj | ||||
| *.csproj.user | ||||
| *.build | ||||
|  | @ -11,13 +10,6 @@ | |||
| *.pidb | ||||
| *.dll.build | ||||
| *.dll | ||||
| *.log | ||||
| 
 | ||||
| # Ignore .user and .suo files as these are user preference specific | ||||
| # http://stackoverflow.com/questions/72298/should-i-add-the-visual-studio-suo-and-user-files-to-source-control | ||||
| *.suo | ||||
| *.user | ||||
| 
 | ||||
| *.VisualState.xml | ||||
| */*/obj | ||||
| */*/*/obj | ||||
|  | @ -31,19 +23,12 @@ | |||
| */*/*/*/*/bin | ||||
| */*/*/*/*/*/bin | ||||
| */*/*/*/*/*/*/bin | ||||
| .vs/ | ||||
| addon-modules/ | ||||
| bin/Debug/*.dll | ||||
| bin/*.dll.mdb | ||||
| bin/*.db | ||||
| bin/*.db-journal | ||||
| bin/addin-db-* | ||||
| bin/*.dll | ||||
| bin/OpenSim.vshost.exe.config | ||||
| bin/OpenSim.32BitLaunch.vshost.exe.config | ||||
| bin/OpenSim.32BitLaunch.log | ||||
| UpgradeLog.XML | ||||
| _UpgradeReport_Files/ | ||||
| bin/ScriptEngines/*-*-*-*-* | ||||
| bin/ScriptEngines/*.dll | ||||
| bin/ScriptEngines/*/*.dll | ||||
|  | @ -56,9 +41,6 @@ bin/Physics* | |||
| bin/Terrain* | ||||
| bin/Regions/* | ||||
| bin/UserAssets | ||||
| bin/assetcache | ||||
| bin/maptiles | ||||
| bin/bakes | ||||
| bin/estate_settings.xml | ||||
| bin/config-include/CenomeCache.ini | ||||
| bin/config-include/FlotsamCache.ini | ||||
|  | @ -71,18 +53,12 @@ bin/OpenSim.Grid.InventoryServer.log | |||
| bin/OpenSim.Grid.MessagingServer.log | ||||
| bin/OpenSim.Grid.UserServer.log | ||||
| bin/OpenSim.log | ||||
| bin/OpenSimStats.log | ||||
| bin/Robust.log | ||||
| bin/RobustStats.log | ||||
| bin/OpenSimConsoleHistory.txt | ||||
| bin/RobustConsoleHistory.txt | ||||
| bin/*.Tests.log | ||||
| bin/*.manifest | ||||
| bin/crashes/ | ||||
| Examples/*.dll | ||||
| OpenSim.build | ||||
| OpenSim.sln | ||||
| OpenSim.userprefs | ||||
| OpenSim.suo | ||||
| Prebuild/Prebuild.build | ||||
| Prebuild/Prebuild.sln | ||||
| TestResult.xml | ||||
|  | @ -94,6 +70,7 @@ TAGS | |||
| Makefile.local | ||||
| bin/.version | ||||
| compile.bat | ||||
| addon-modules | ||||
| OpenSim/Data/Tests/test-results/ | ||||
| OpenSim/Framework/Serialization/Tests/test-results/ | ||||
| OpenSim/Framework/Servers/Tests/test-results/ | ||||
|  | @ -110,7 +87,3 @@ OpenSim/Region/ScriptEngine/test-results/ | |||
| OpenSim/Tests/Common/test-results/ | ||||
| OpenSim/Tests/test-results/ | ||||
| test-results/ | ||||
| doc/html | ||||
| doc/doxygen.error.log | ||||
| 
 | ||||
| *.patch | ||||
|  |  | |||
|  | @ -43,11 +43,10 @@ | |||
|   <delete dir="${distbindir}/Prebuild"/> | ||||
|   <delete dir="${distbindir}/%temp%"/> | ||||
|   <delete dir="${distbindir}/.nant"/> | ||||
|   <delete dir="${distbindir}/ThirdParty"/> | ||||
|   <delete> | ||||
|     <fileset basedir="${distbindir}"> | ||||
|       <include name="compile.bat"/> | ||||
|       <include name="BUILDING.md"/> | ||||
|       <include name="BUILDING.txt"/> | ||||
|       <include name="Makefile"/> | ||||
|       <include name="nant-color"/> | ||||
|       <include name="OpenSim.*"/> | ||||
|  | @ -113,12 +112,10 @@ | |||
|   </exec> | ||||
|   <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.coremodules.tests)==0}" />  | ||||
| 
 | ||||
| <!-- | ||||
|   <exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.region.optionalmodules.tests"> | ||||
|     <arg value="./bin/OpenSim.Region.OptionalModules.Tests.dll" /> | ||||
|   </exec> | ||||
|   <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.optionalmodules.tests)==0}" />  | ||||
| --> | ||||
| 
 | ||||
|   <exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.region.framework.tests"> | ||||
|     <arg value="./bin/OpenSim.Region.Framework.Tests.dll" /> | ||||
|  | @ -135,43 +132,17 @@ | |||
|   </exec> | ||||
|   <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.capabilities.handlers.tests)==0}" />  | ||||
| 
 | ||||
|   <exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.server.handlers.tests"> | ||||
|     <arg value="./bin/OpenSim.Server.Handlers.Tests.dll" /> | ||||
|   </exec> | ||||
|   <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.server.handlers.tests)==0}" />  | ||||
| 
 | ||||
|   <exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.services.inventoryservice.tests"> | ||||
|     <arg value="./bin/OpenSim.Services.InventoryService.Tests.dll" /> | ||||
|   </exec> | ||||
|   <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.services.inventoryservice.tests)==0}" />  | ||||
| 
 | ||||
|   <exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.tests.permissions"> | ||||
|     <arg value="./bin/OpenSim.Tests.Permissions.dll" /> | ||||
|   </exec> | ||||
|   <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.tests.permissions)==0}" />  | ||||
|    | ||||
| <delete dir="%temp%"/> | ||||
| </target> | ||||
| 
 | ||||
| <target name="test-stress" depends="build, find-nunit"> | ||||
|   <setenv name="MONO_THREADS_PER_CPU" value="100" /> | ||||
| 
 | ||||
|   <exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.tests.stress"> | ||||
|     <arg value="./bin/OpenSim.Tests.Stress.dll" /> | ||||
|   </exec> | ||||
| 
 | ||||
|   <fail message="Failures reported in stress tests." unless="${int::parse(testresult.opensim.tests.stress)==0}" />  | ||||
|   <delete dir="%temp%"/> | ||||
| </target> | ||||
| 
 | ||||
| <target name="test-perf" depends="build, find-nunit"> | ||||
| <target name="torture" depends="build, find-nunit"> | ||||
|   <setenv name="MONO_THREADS_PER_CPU" value="100" /> | ||||
| 
 | ||||
|   <exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.tests.performance"> | ||||
|     <arg value="./bin/OpenSim.Tests.Performance.dll" /> | ||||
|   <exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.tests.torture"> | ||||
|     <arg value="./bin/OpenSim.Tests.Torture.dll" /> | ||||
|   </exec> | ||||
| 
 | ||||
|   <fail message="Failures reported in performance tests." unless="${int::parse(testresult.opensim.tests.performance)==0}" />  | ||||
|   <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.tests.torture)==0}" />  | ||||
|   <delete dir="%temp%"/> | ||||
| </target> | ||||
| 
 | ||||
|  | @ -233,12 +204,10 @@ | |||
|     <arg value="-xml=test-results/OpenSim.Region.CoreModules.Tests.dll-Results.xml" /> | ||||
|   </exec> | ||||
| 
 | ||||
| <!-- | ||||
|  <exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.region.optionalmodules.tests"> | ||||
|     <arg value="./bin/OpenSim.Region.OptionalModules.Tests.dll" /> | ||||
|     <arg value="-xml=test-results/OpenSim.Region.OptionalModules.Tests.dll-Results.xml" /> | ||||
|   </exec> | ||||
| --> | ||||
| 
 | ||||
|  <exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.region.framework.tests"> | ||||
|     <arg value="./bin/OpenSim.Region.Framework.Tests.dll" /> | ||||
|  | @ -255,33 +224,16 @@ | |||
|     <arg value="-xml=test-results/OpenSim.Capabilities.Handlers.Tests.dll-Results.xml" /> | ||||
|   </exec> | ||||
| 
 | ||||
|  <exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.server.handlers.tests"> | ||||
|     <arg value="./bin/OpenSim.Server.Handlers.Tests.dll" /> | ||||
|     <arg value="-xml=test-results/OpenSim.Server.Handlers.Tests.dll-Results.xml" /> | ||||
|   </exec> | ||||
| 
 | ||||
|  <exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.services.inventoryservice.tests"> | ||||
|     <arg value="./bin/OpenSim.Services.InventoryService.Tests.dll" /> | ||||
|     <arg value="-xml=test-results/OpenSim.Services.InventoryService.Tests.dll-Results.xml" /> | ||||
|   </exec> | ||||
| 
 | ||||
|  <exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.tests.permissions"> | ||||
|     <arg value="./bin/OpenSim.Tests.Permissions.dll" /> | ||||
|     <arg value="-xml=test-results/OpenSim.Tests.Permissions.dll-Results.xml" /> | ||||
|   </exec> | ||||
|    | ||||
|  <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.tests)==0}" />  | ||||
|  <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.framework.tests)==0}" />  | ||||
|  <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.framework.servers.tests)==0}" />  | ||||
|  <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.clientstack.lindenudp.tests)==0}" /> | ||||
|  <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.scriptengine.tests)==0}" />  | ||||
|  <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.coremodules.tests)==0}" />  | ||||
| <!--  <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.optionalmodules.tests)==0}" /> --> | ||||
|  <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.optionalmodules.tests)==0}" />  | ||||
|  <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.framework.tests)==0}" />  | ||||
|  <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.data.tests)==0}" />  | ||||
|  <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.capabilities.handlers.tests)==0}" />  | ||||
|  <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.services.inventoryservice.tests)==0}" />  | ||||
|  <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.tests.permissions)==0}" />  | ||||
| </target> | ||||
| 
 | ||||
| <target name="doxygen"> | ||||
|  |  | |||
							
								
								
									
										37
									
								
								BUILDING.md
								
								
								
								
							
							
						
						
									
										37
									
								
								BUILDING.md
								
								
								
								
							|  | @ -1,37 +0,0 @@ | |||
| # Building on Windows | ||||
| 
 | ||||
| Steps: | ||||
| 
 | ||||
|  * runprebuild.bat | ||||
|  * Load OpenSim.sln into Visual Studio .NET and build the solution. | ||||
|  * chdir bin  | ||||
|  * copy OpenSim.ini.example to OpenSim.ini and other appropriate files in bin/config-include | ||||
|  * run OpenSim.exe | ||||
| 
 | ||||
| # Building on Linux / Mac | ||||
| 
 | ||||
| Prereqs: | ||||
| 
 | ||||
|  *	Mono > 5.0 | ||||
|  *	On some Linux distributions you may need to install additional packages. | ||||
|  *	msbuild or xbuild if still supported by the mono version | ||||
|  *   See http://opensimulator.org/wiki/Dependencies for more information. | ||||
| 
 | ||||
| From the distribution type: | ||||
| 
 | ||||
|  * ./runprebuild.sh | ||||
|  * type msbuild or xbuild | ||||
|  * cd bin  | ||||
|  * copy OpenSim.ini.example to OpenSim.ini and other appropriate files in bin/config-include | ||||
|  * review and change those ini files according to your needs | ||||
|  * windows: execute opensim.exe or opensim32.exe for small regions | ||||
|  * linux: run ./opensim.sh | ||||
|  * msbuild (xbuild) option switches | ||||
|    *  clean:  msbuild /target:clean | ||||
|    *  debug: (default) msbuild /property:Configuration=Debug | ||||
|    *  release: msbuild /property:Configuration=Release | ||||
| 
 | ||||
| # References | ||||
|   | ||||
| Helpful resources: | ||||
| * http://opensimulator.org/wiki/Build_Instructions | ||||
|  | @ -0,0 +1,39 @@ | |||
| ==== Building OpenSim ==== | ||||
| 
 | ||||
| === Building on Windows === | ||||
| 
 | ||||
| Steps: | ||||
|  * runprebuild.bat | ||||
|  * Load OpenSim.sln into Visual Studio .NET and build the solution. | ||||
|  * chdir bin  | ||||
|  * copy OpenSim.ini.example to OpenSim.ini and other appropriate files in bin/config-include | ||||
|  * run OpenSim.exe | ||||
| 
 | ||||
| === Building on Linux === | ||||
| 
 | ||||
| Prereqs: | ||||
|  * Mono >= 2.4.3 | ||||
|  * Nant >= 0.85 | ||||
|  * On some Linux distributions you may need to install additional packages.   | ||||
|     See http://opensimulator.org/wiki/Dependencies for more information. | ||||
| 
 | ||||
|  * May also use xbuild (included in mono distributions) | ||||
|  * May use Monodevelop, a cross-platform IDE  | ||||
| 
 | ||||
| From the distribution type: | ||||
|  * ./runprebuild.sh | ||||
|  * nant (or xbuild) | ||||
|  * cd bin  | ||||
|  * copy OpenSim.ini.example to OpenSim.ini and other appropriate files in bin/config-include | ||||
|  * run mono OpenSim.exe | ||||
| 
 | ||||
| === Using Monodevelop === | ||||
| 
 | ||||
| From the distribution type: | ||||
|  * ./runprebuild.sh | ||||
|  * type monodevelop OpenSim.sln | ||||
| 
 | ||||
| === References === | ||||
|   | ||||
| Helpful resources: | ||||
| * http://opensimulator.org/wiki/Build_Instructions | ||||
							
								
								
									
										131
									
								
								CONTRIBUTORS.txt
								
								
								
								
							
							
						
						
									
										131
									
								
								CONTRIBUTORS.txt
								
								
								
								
							|  | @ -1,22 +1,39 @@ | |||
| The following people have contributed to OpenSim (Thank you for your effort!)  | ||||
| The following people have contributed to OpenSim (Thank you  | ||||
| for your effort!) | ||||
| 
 | ||||
| = Current OpenSim Developers (in very rough order of appearance) = | ||||
| These folks represent the current core team for OpenSim, and are the | ||||
| people that make the day to day of OpenSim happen. | ||||
| 
 | ||||
| * justincc (OSVW Consulting, justincc.org) | ||||
| * chi11ken (Genkii) | ||||
| * dahlia | ||||
| * Melanie Thielker | ||||
| * Diva (Crista Lopes, University of California, Irvine) | ||||
| * Robert Adams (MisterBlue) | ||||
| * Kevin Cozens | ||||
| * Leal Duarte (Ubit Umarov) | ||||
| * Dan Lake (Intel) | ||||
| * Marck | ||||
| * Mic Bowman (Intel) | ||||
| * BlueWall (James Hughes) | ||||
| * Nebadon Izumi (Michael Cerquoni, OSgrid) | ||||
| * Snoopy Pfeffer | ||||
| * Richard Adams (Intel) | ||||
| 
 | ||||
| = Core Developers Following the White Rabbit = | ||||
| Core developers who have temporarily (we hope) gone chasing the white rabbit.  | ||||
| They are in all similar to the active core developers, except that they haven't | ||||
| been that active lately, so their voting rights are awaiting their come back.  | ||||
| 
 | ||||
| * Nebadon Izumi (Michael Cerquoni, OSgrid) | ||||
| * Alicia Raven | ||||
| * MW (Tribal Media AB) | ||||
| * Adam Frisby 	(DeepThink Pty Ltd) | ||||
| * lbsa71 (Tribal Media AB) | ||||
| * Teravus (w3z) | ||||
| * Ckrinke (Charles Krinke) | ||||
| * Dr Scofield aka Dirk Husemann (IBM Research - Zurich) | ||||
| * mikem (3Di) | ||||
| * Homer_Horwitz | ||||
| * nlin (3Di) | ||||
| * Arthur Rodrigo S Valadares (IBM) | ||||
| * John Hurliman | ||||
| 
 | ||||
| = Past Open Sim Developers = | ||||
| These folks are alumns of the OpenSim core group, but are now | ||||
|  | @ -38,123 +55,65 @@ where we are today. | |||
| * adjohn (Genkii) | ||||
| * idb (Ian Brown) | ||||
| * Johan Berntsson (3Di) | ||||
| * MW (Tribal Media AB) | ||||
| * Adam Frisby 	(DeepThink Pty Ltd) | ||||
| * lbsa71 (Tribal Media AB) | ||||
| * Ckrinke (Charles Krinke) | ||||
| * Dr Scofield aka Dirk Husemann (IBM Research - Zurich) | ||||
| * mikem (3Di) | ||||
| * Homer_Horwitz | ||||
| * nlin (3Di) | ||||
| * John Hurliman | ||||
| * chi11ken (Genkii) | ||||
| * dahlia | ||||
| * justincc (OSVW Consulting, justincc.org) | ||||
| * Arthur Rodrigo S Valadares (IBM) | ||||
| * BlueWall (James Hughes) | ||||
| * Dan Lake  | ||||
| * Marck | ||||
| * Mic Bowman | ||||
| * Oren Hurvitz (Kitely) | ||||
| * Snoopy Pfeffer | ||||
| * Teravus (w3z) | ||||
| 
 | ||||
| 
 | ||||
| = Additional OpenSim Contributors = | ||||
| These folks have contributed code patches or content to OpenSimulator to help make it | ||||
| These folks have contributed code patches to OpenSim to help make it | ||||
| what it is today.   | ||||
| 
 | ||||
| * A_Biondi | ||||
| * aduffy70 | ||||
| * Ai Austin | ||||
| * A_Biondi | ||||
| * alex_carnell | ||||
| * Alan Webb (IBM) | ||||
| * Aleric | ||||
| * Allen Kerensky | ||||
| * BigFootAg | ||||
| * Bill Blight | ||||
| * BlueWall Slade | ||||
| * bobshaffer2 | ||||
| * brianw/Sir_Ahzz | ||||
| * CharlieO | ||||
| * ChrisDown | ||||
| * Chris Yeoh (IBM) | ||||
| * cinderblocks | ||||
| * controlbreak | ||||
| * coyled | ||||
| * ctrlaltdavid (David Rowe) | ||||
| * Daedius | ||||
| * daTwitch  | ||||
| * Dev Random | ||||
| * devalnor-#708 | ||||
| * dmiles (Daxtron Labs) | ||||
| * Dong Jun Lan (IBM) | ||||
| * DoranZemlja | ||||
| * Drake Arconis | ||||
| * dr0b3rts | ||||
| * dslake | ||||
| * eeyore | ||||
| * daTwitch  | ||||
| * devalnor-#708 | ||||
| * dmiles (Daxtron Labs) | ||||
| * dslake (Intel) | ||||
| * FredoChaplin | ||||
| * FreakyTech | ||||
| * Garmin Kawaguichi | ||||
| * Gavin Hird | ||||
| * Gerhard | ||||
| * Godfrey | ||||
| * Greg C. | ||||
| * Grumly57 | ||||
| * GuduleLapointe | ||||
| * Ewe Loon | ||||
| * Fernando Oliveira | ||||
| * Fly-Man | ||||
| * Flyte Xevious | ||||
| * Freaky Tech | ||||
| * Garmin Kawaguichi | ||||
| * Geir Noklebye | ||||
| * Glenn Martin (MOSES) | ||||
| * Gryc Ueusp | ||||
| * H-H-H (ginge264) | ||||
| * Hiro Lecker | ||||
| * Iain Oliver | ||||
| * Imaze Rhiano | ||||
| * Intimidated | ||||
| * Jak Daniels | ||||
| * Jeff Kelly | ||||
| * Jeremy Bongio (IBM) | ||||
| * jhurliman | ||||
| * John R Sohn (XenReborn) | ||||
| * jonc | ||||
| * Jon Cundill | ||||
| * Junta Kohime | ||||
| * Kayne | ||||
| * Kevin Cozens | ||||
| * kinoc (Daxtron Labs) | ||||
| * Kira | ||||
| * Kitto Flora | ||||
| * KittyLiu | ||||
| * Kurt Taylor (IBM) | ||||
| * Lani Global | ||||
| * lickx | ||||
| * lillith_xue | ||||
| * lkalif | ||||
| * LuciusSirnah | ||||
| * lulurun  | ||||
| * M.Igarashi | ||||
| * Magnuz Binder | ||||
| * maimedleech | ||||
| * Mana Janus | ||||
| * Mandarinka Tasty | ||||
| * MarcelEdward | ||||
| * Matt Lehmann | ||||
| * mewtwo0641 | ||||
| * Mic Bowman | ||||
| * Michelle Argus | ||||
| * Michael Cortez (The Flotsam Project, http://osflotsam.org/) | ||||
| * Michael Heilmann (MOSES) | ||||
| * Micheil Merlin | ||||
| * Mike Osias (IBM) | ||||
| * Mike Pitman (IBM) | ||||
| * Mike Rieker (Dreamnation) | ||||
| * mikemig | ||||
| * mikkopa/_someone - RealXtend | ||||
| * Misterblue | ||||
| * Misterblue (Intel) | ||||
| * Mircea Kitsune | ||||
| * mpallari | ||||
| * MrMonkE | ||||
|  | @ -163,75 +122,61 @@ what it is today. | |||
| * nornalbion | ||||
| * Omar Vera Ustariz (IBM) | ||||
| * openlifegrid.com | ||||
| * Oren Hurvitz (Kitely) | ||||
| * otakup0pe | ||||
| * Pixel Tomsen | ||||
| * Quill Littlefeather | ||||
| * ralphos | ||||
| * RemedyTomm | ||||
| * Revolution | ||||
| * Richard Alimi (IBM) | ||||
| * Rick Alther (IBM) | ||||
| * Rob Smart (IBM) | ||||
| * Robert Louden (MOSES) | ||||
| * Roger Kirkman (zadark) | ||||
| * rtomita | ||||
| * Ruud Lathorp | ||||
| * SachaMagne | ||||
| * Salahzar Stenvaag | ||||
| * satguru p srivastava | ||||
| * sempuki | ||||
| * Shy Robbiani | ||||
| * SignpostMarv | ||||
| * SpotOn3D | ||||
| * Stefan_Boom / stoehr | ||||
| * Steven Zielinski (MOSES) | ||||
| * Stolen Ruby  | ||||
| * Strawberry Fride | ||||
| * Talun | ||||
| * TechplexEngineer (Blake Bourque) | ||||
| * TBG Renfold | ||||
| * Terry Ford | ||||
| * tglion | ||||
| * tlaukkan/Tommil (Tommi S. E. Laukkanen, Bubble Cloud) | ||||
| * TomDataWorks | ||||
| * TomTheDragon (muckwaddle) | ||||
| * tyre | ||||
| * uriesk | ||||
| * Vegaslon <vegaslon@gmail.com> | ||||
| * Vincent Sylvester | ||||
| * VikingErik | ||||
| * Vytek | ||||
| * webmage (IBM) | ||||
| * Xantor | ||||
| * Y. Nitta | ||||
| * YoshikoFazuku | ||||
| * YZh | ||||
| * Zackary Geers aka Kunnis Basiat | ||||
| * Zha Ewry | ||||
| * ziah | ||||
| 
 | ||||
| 
 | ||||
| = LSL Devs = | ||||
| 
 | ||||
| * Alondria | ||||
| * CharlieO | ||||
| * Tedd | ||||
| * Melanie Thielker | ||||
| 
 | ||||
| 
 | ||||
| = Testers = | ||||
| 
 | ||||
| * Ai Austin | ||||
| * CharlieO (LSL) | ||||
| * Ckrinke | ||||
| * openlifegrid.com | ||||
| 
 | ||||
| 
 | ||||
| This software uses components from the following developers: | ||||
| * Sleepycat Software (Berkeley DB) | ||||
| * Aurora-Sim (http://aurora-sim.org) | ||||
| * SQLite (Public Domain) | ||||
| * XmlRpcCS (http://xmlrpccs.sf.net/) | ||||
| * MySQL, Inc. (MySQL Connector/NET) | ||||
| * NUnit (http://www.nunit.org) | ||||
| * AGEIA Inc. (PhysX) | ||||
| * Russel L. Smith (ODE) | ||||
| * Erwin Coumans (Bullet) | ||||
| * Prebuild (http://sourceforge.net/projects/dnpb/) | ||||
| * LibOpenMetaverse (http://lib.openmetaverse.org/) | ||||
| * DotNetOpenMail v0.5.8b (http://dotnetopenmail.sourceforge.net) | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -1,78 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| 
 | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Region.Framework.Interfaces; | ||||
| using OpenSim.Services.Interfaces; | ||||
| 
 | ||||
| namespace OpenSim.Groups | ||||
| { | ||||
|     public class ForeignImporter | ||||
|     { | ||||
|         IUserManagement m_UserManagement; | ||||
|         public ForeignImporter(IUserManagement uman) | ||||
|         { | ||||
|             m_UserManagement = uman; | ||||
|         } | ||||
| 
 | ||||
|         public GroupMembersData ConvertGroupMembersData(ExtendedGroupMembersData _m) | ||||
|         { | ||||
|             GroupMembersData m = new GroupMembersData(); | ||||
|             m.AcceptNotices = _m.AcceptNotices; | ||||
|             m.AgentPowers = _m.AgentPowers; | ||||
|             m.Contribution = _m.Contribution; | ||||
|             m.IsOwner = _m.IsOwner; | ||||
|             m.ListInProfile = _m.ListInProfile; | ||||
|             m.OnlineStatus = _m.OnlineStatus; | ||||
|             m.Title = _m.Title; | ||||
| 
 | ||||
|             string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty; | ||||
|             Util.ParseUniversalUserIdentifier(_m.AgentID, out m.AgentID, out url, out first, out last, out tmp); | ||||
|             if (url != string.Empty) | ||||
|                 m_UserManagement.AddUser(m.AgentID, first, last, url); | ||||
| 
 | ||||
|             return m; | ||||
|         } | ||||
| 
 | ||||
|         public GroupRoleMembersData ConvertGroupRoleMembersData(ExtendedGroupRoleMembersData _rm) | ||||
|         { | ||||
|             GroupRoleMembersData rm = new GroupRoleMembersData(); | ||||
|             rm.RoleID = _rm.RoleID; | ||||
| 
 | ||||
|             string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty; | ||||
|             Util.ParseUniversalUserIdentifier(_rm.MemberID, out rm.MemberID, out url, out first, out last, out tmp); | ||||
|             if (url != string.Empty) | ||||
|                 m_UserManagement.AddUser(rm.MemberID, first, last, url); | ||||
| 
 | ||||
|             return rm; | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | @ -1,533 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| 
 | ||||
| using OpenSim.Framework; | ||||
| using OpenMetaverse; | ||||
| 
 | ||||
| namespace OpenSim.Groups | ||||
| { | ||||
|     public class ExtendedGroupRecord : GroupRecord | ||||
|     { | ||||
|         public int MemberCount; | ||||
|         public int RoleCount; | ||||
|         public string ServiceLocation; | ||||
|         public string FounderUUI; | ||||
|     } | ||||
| 
 | ||||
|     public class ExtendedGroupMembershipData : GroupMembershipData | ||||
|     { | ||||
|         public string AccessToken; | ||||
|     } | ||||
| 
 | ||||
|     public class ExtendedGroupMembersData | ||||
|     { | ||||
|         // This is the only difference: this is a string | ||||
|         public string AgentID; | ||||
|         public int Contribution; | ||||
|         public string OnlineStatus; | ||||
|         public ulong AgentPowers; | ||||
|         public string Title; | ||||
|         public bool IsOwner; | ||||
|         public bool ListInProfile; | ||||
|         public bool AcceptNotices; | ||||
|         public string AccessToken; | ||||
|     } | ||||
| 
 | ||||
|     public class ExtendedGroupRoleMembersData | ||||
|     { | ||||
|         public UUID RoleID; | ||||
|         // This is the only difference: this is a string | ||||
|         public string MemberID; | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public struct ExtendedGroupNoticeData | ||||
|     { | ||||
|         public UUID NoticeID; | ||||
|         public uint Timestamp; | ||||
|         public string FromName; | ||||
|         public string Subject; | ||||
|         public bool HasAttachment; | ||||
|         public byte AttachmentType; | ||||
|         public string AttachmentName; | ||||
|         public UUID AttachmentItemID; | ||||
|         public string AttachmentOwnerID; | ||||
| 
 | ||||
|         public GroupNoticeData ToGroupNoticeData() | ||||
|         { | ||||
|             GroupNoticeData n = new GroupNoticeData(); | ||||
|             n.FromName = this.FromName; | ||||
|             n.AssetType = this.AttachmentType; | ||||
|             n.HasAttachment = this.HasAttachment; | ||||
|             n.NoticeID = this.NoticeID; | ||||
|             n.Subject = this.Subject; | ||||
|             n.Timestamp = this.Timestamp; | ||||
| 
 | ||||
|             return n; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public class GroupsDataUtils | ||||
|     { | ||||
|         public static string Sanitize(string s) | ||||
|         { | ||||
|             return s == null ? string.Empty : s; | ||||
|         } | ||||
| 
 | ||||
|         public static Dictionary<string, object> GroupRecord(ExtendedGroupRecord grec) | ||||
|         { | ||||
|             Dictionary<string, object> dict = new Dictionary<string, object>(); | ||||
|             if (grec == null) | ||||
|                 return dict; | ||||
| 
 | ||||
|             dict["AllowPublish"] = grec.AllowPublish.ToString(); | ||||
|             dict["Charter"] = Sanitize(grec.Charter); | ||||
|             dict["FounderID"] = grec.FounderID.ToString(); | ||||
|             dict["FounderUUI"] = Sanitize(grec.FounderUUI); | ||||
|             dict["GroupID"] = grec.GroupID.ToString(); | ||||
|             dict["GroupName"] = Sanitize(grec.GroupName); | ||||
|             dict["InsigniaID"] = grec.GroupPicture.ToString(); | ||||
|             dict["MaturePublish"] = grec.MaturePublish.ToString(); | ||||
|             dict["MembershipFee"] = grec.MembershipFee.ToString(); | ||||
|             dict["OpenEnrollment"] = grec.OpenEnrollment.ToString(); | ||||
|             dict["OwnerRoleID"] = grec.OwnerRoleID.ToString(); | ||||
|             dict["ServiceLocation"] = Sanitize(grec.ServiceLocation); | ||||
|             dict["ShownInList"] = grec.ShowInList.ToString(); | ||||
|             dict["MemberCount"] =  grec.MemberCount.ToString(); | ||||
|             dict["RoleCount"] = grec.RoleCount.ToString(); | ||||
| 
 | ||||
|             return dict; | ||||
|         } | ||||
| 
 | ||||
|         public static ExtendedGroupRecord GroupRecord(Dictionary<string, object> dict) | ||||
|         { | ||||
|             if (dict == null) | ||||
|                 return null; | ||||
| 
 | ||||
|             ExtendedGroupRecord grec = new ExtendedGroupRecord(); | ||||
|             if (dict.ContainsKey("AllowPublish") && dict["AllowPublish"] != null) | ||||
|                 grec.AllowPublish = bool.Parse(dict["AllowPublish"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("Charter") && dict["Charter"] != null) | ||||
|                 grec.Charter = dict["Charter"].ToString(); | ||||
|             else | ||||
|                 grec.Charter = string.Empty; | ||||
| 
 | ||||
|             if (dict.ContainsKey("FounderID") && dict["FounderID"] != null) | ||||
|                 grec.FounderID = UUID.Parse(dict["FounderID"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("FounderUUI") && dict["FounderUUI"] != null) | ||||
|                 grec.FounderUUI = dict["FounderUUI"].ToString(); | ||||
|             else | ||||
|                 grec.FounderUUI = string.Empty; | ||||
| 
 | ||||
|             if (dict.ContainsKey("GroupID") && dict["GroupID"] != null) | ||||
|                 grec.GroupID = UUID.Parse(dict["GroupID"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("GroupName") && dict["GroupName"] != null) | ||||
|                 grec.GroupName = dict["GroupName"].ToString(); | ||||
|             else | ||||
|                 grec.GroupName = string.Empty; | ||||
| 
 | ||||
|             if (dict.ContainsKey("InsigniaID") && dict["InsigniaID"] != null) | ||||
|                 grec.GroupPicture = UUID.Parse(dict["InsigniaID"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("MaturePublish") && dict["MaturePublish"] != null) | ||||
|                 grec.MaturePublish = bool.Parse(dict["MaturePublish"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("MembershipFee") && dict["MembershipFee"] != null) | ||||
|                 grec.MembershipFee = Int32.Parse(dict["MembershipFee"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("OpenEnrollment") && dict["OpenEnrollment"] != null) | ||||
|                 grec.OpenEnrollment = bool.Parse(dict["OpenEnrollment"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("OwnerRoleID") && dict["OwnerRoleID"] != null) | ||||
|                 grec.OwnerRoleID = UUID.Parse(dict["OwnerRoleID"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("ServiceLocation") && dict["ServiceLocation"] != null) | ||||
|                 grec.ServiceLocation = dict["ServiceLocation"].ToString(); | ||||
|             else | ||||
|                 grec.ServiceLocation = string.Empty; | ||||
| 
 | ||||
|             if (dict.ContainsKey("ShownInList") && dict["ShownInList"] != null) | ||||
|                 grec.ShowInList = bool.Parse(dict["ShownInList"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("MemberCount") && dict["MemberCount"] != null) | ||||
|                 grec.MemberCount = Int32.Parse(dict["MemberCount"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("RoleCount") && dict["RoleCount"] != null) | ||||
|                 grec.RoleCount = Int32.Parse(dict["RoleCount"].ToString()); | ||||
| 
 | ||||
|             return grec; | ||||
|         } | ||||
| 
 | ||||
|         public static Dictionary<string, object> GroupMembershipData(ExtendedGroupMembershipData membership) | ||||
|         { | ||||
|             Dictionary<string, object> dict = new Dictionary<string, object>(); | ||||
|             if (membership == null) | ||||
|                 return dict; | ||||
| 
 | ||||
|             dict["AcceptNotices"] = membership.AcceptNotices.ToString(); | ||||
|             dict["AccessToken"] = Sanitize(membership.AccessToken); | ||||
|             dict["Active"] = membership.Active.ToString(); | ||||
|             dict["ActiveRole"] = membership.ActiveRole.ToString(); | ||||
|             dict["AllowPublish"] = membership.AllowPublish.ToString(); | ||||
|             dict["Charter"] = Sanitize(membership.Charter); | ||||
|             dict["Contribution"] = membership.Contribution.ToString(); | ||||
|             dict["FounderID"] = membership.FounderID.ToString(); | ||||
|             dict["GroupID"] = membership.GroupID.ToString(); | ||||
|             dict["GroupName"] = Sanitize(membership.GroupName); | ||||
|             dict["GroupPicture"] = membership.GroupPicture.ToString(); | ||||
|             dict["GroupPowers"] = membership.GroupPowers.ToString(); | ||||
|             dict["GroupTitle"] = Sanitize(membership.GroupTitle); | ||||
|             dict["ListInProfile"] = membership.ListInProfile.ToString(); | ||||
|             dict["MaturePublish"] = membership.MaturePublish.ToString(); | ||||
|             dict["MembershipFee"] = membership.MembershipFee.ToString(); | ||||
|             dict["OpenEnrollment"] = membership.OpenEnrollment.ToString(); | ||||
|             dict["ShowInList"] = membership.ShowInList.ToString(); | ||||
| 
 | ||||
|             return dict; | ||||
|         } | ||||
| 
 | ||||
|         public static ExtendedGroupMembershipData GroupMembershipData(Dictionary<string, object> dict) | ||||
|         { | ||||
|             if (dict == null) | ||||
|                 return null; | ||||
| 
 | ||||
|             ExtendedGroupMembershipData membership = new ExtendedGroupMembershipData(); | ||||
| 
 | ||||
|             if (dict.ContainsKey("AcceptNotices") && dict["AcceptNotices"] != null) | ||||
|                 membership.AcceptNotices = bool.Parse(dict["AcceptNotices"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("AccessToken") && dict["AccessToken"] != null) | ||||
|                 membership.AccessToken = dict["AccessToken"].ToString(); | ||||
|             else | ||||
|                 membership.AccessToken = string.Empty; | ||||
| 
 | ||||
|             if (dict.ContainsKey("Active") && dict["Active"] != null) | ||||
|                 membership.Active = bool.Parse(dict["Active"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("ActiveRole") && dict["ActiveRole"] != null) | ||||
|                 membership.ActiveRole = UUID.Parse(dict["ActiveRole"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("AllowPublish") && dict["AllowPublish"] != null) | ||||
|                 membership.AllowPublish = bool.Parse(dict["AllowPublish"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("Charter") && dict["Charter"] != null) | ||||
|                 membership.Charter = dict["Charter"].ToString(); | ||||
|             else | ||||
|                 membership.Charter = string.Empty; | ||||
| 
 | ||||
|             if (dict.ContainsKey("Contribution") && dict["Contribution"] != null) | ||||
|                 membership.Contribution = Int32.Parse(dict["Contribution"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("FounderID") && dict["FounderID"] != null) | ||||
|                 membership.FounderID = UUID.Parse(dict["FounderID"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("GroupID") && dict["GroupID"] != null) | ||||
|                 membership.GroupID = UUID.Parse(dict["GroupID"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("GroupName") && dict["GroupName"] != null) | ||||
|                 membership.GroupName = dict["GroupName"].ToString(); | ||||
|             else | ||||
|                 membership.GroupName = string.Empty; | ||||
| 
 | ||||
|             if (dict.ContainsKey("GroupPicture") && dict["GroupPicture"] != null) | ||||
|                 membership.GroupPicture = UUID.Parse(dict["GroupPicture"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("GroupPowers") && dict["GroupPowers"] != null) | ||||
|                 membership.GroupPowers = UInt64.Parse(dict["GroupPowers"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("GroupTitle") && dict["GroupTitle"] != null) | ||||
|                 membership.GroupTitle = dict["GroupTitle"].ToString(); | ||||
|             else | ||||
|                 membership.GroupTitle = string.Empty; | ||||
| 
 | ||||
|             if (dict.ContainsKey("ListInProfile") && dict["ListInProfile"] != null) | ||||
|                 membership.ListInProfile = bool.Parse(dict["ListInProfile"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("MaturePublish") && dict["MaturePublish"] != null) | ||||
|                 membership.MaturePublish = bool.Parse(dict["MaturePublish"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("MembershipFee") && dict["MembershipFee"] != null) | ||||
|                 membership.MembershipFee = Int32.Parse(dict["MembershipFee"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("OpenEnrollment") && dict["OpenEnrollment"] != null) | ||||
|                 membership.OpenEnrollment = bool.Parse(dict["OpenEnrollment"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("ShowInList") && dict["ShowInList"] != null) | ||||
|                 membership.ShowInList = bool.Parse(dict["ShowInList"].ToString()); | ||||
| 
 | ||||
|             return membership; | ||||
|         } | ||||
| 
 | ||||
|         public static Dictionary<string, object> GroupMembersData(ExtendedGroupMembersData member) | ||||
|         { | ||||
|             Dictionary<string, object> dict = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             dict["AcceptNotices"] = member.AcceptNotices.ToString(); | ||||
|             dict["AccessToken"] = Sanitize(member.AccessToken); | ||||
|             dict["AgentID"] = Sanitize(member.AgentID); | ||||
|             dict["AgentPowers"] = member.AgentPowers.ToString(); | ||||
|             dict["Contribution"] = member.Contribution.ToString(); | ||||
|             dict["IsOwner"] = member.IsOwner.ToString(); | ||||
|             dict["ListInProfile"] = member.ListInProfile.ToString(); | ||||
|             dict["OnlineStatus"] = Sanitize(member.OnlineStatus); | ||||
|             dict["Title"] = Sanitize(member.Title); | ||||
| 
 | ||||
|             return dict; | ||||
|         } | ||||
| 
 | ||||
|         public static ExtendedGroupMembersData GroupMembersData(Dictionary<string, object> dict) | ||||
|         { | ||||
|             ExtendedGroupMembersData member = new ExtendedGroupMembersData(); | ||||
| 
 | ||||
|             if (dict == null) | ||||
|                 return member; | ||||
| 
 | ||||
|             if (dict.ContainsKey("AcceptNotices") && dict["AcceptNotices"] != null) | ||||
|                 member.AcceptNotices = bool.Parse(dict["AcceptNotices"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("AccessToken") && dict["AccessToken"] != null) | ||||
|                 member.AccessToken = Sanitize(dict["AccessToken"].ToString()); | ||||
|             else | ||||
|                 member.AccessToken = string.Empty; | ||||
| 
 | ||||
|             if (dict.ContainsKey("AgentID") && dict["AgentID"] != null) | ||||
|                 member.AgentID = Sanitize(dict["AgentID"].ToString()); | ||||
|             else | ||||
|                 member.AgentID = UUID.Zero.ToString(); | ||||
| 
 | ||||
|             if (dict.ContainsKey("AgentPowers") && dict["AgentPowers"] != null) | ||||
|                 member.AgentPowers = UInt64.Parse(dict["AgentPowers"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("Contribution") && dict["Contribution"] != null) | ||||
|                 member.Contribution = Int32.Parse(dict["Contribution"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("IsOwner") && dict["IsOwner"] != null) | ||||
|                 member.IsOwner = bool.Parse(dict["IsOwner"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("ListInProfile") && dict["ListInProfile"] != null) | ||||
|                 member.ListInProfile = bool.Parse(dict["ListInProfile"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("OnlineStatus") && dict["OnlineStatus"] != null) | ||||
|                 member.OnlineStatus = Sanitize(dict["OnlineStatus"].ToString()); | ||||
|             else | ||||
|                 member.OnlineStatus = string.Empty; | ||||
| 
 | ||||
|             if (dict.ContainsKey("Title") && dict["Title"] != null) | ||||
|                 member.Title = Sanitize(dict["Title"].ToString()); | ||||
|             else | ||||
|                 member.Title = string.Empty; | ||||
| 
 | ||||
|             return member; | ||||
|         } | ||||
| 
 | ||||
|         public static Dictionary<string, object> GroupRolesData(GroupRolesData role) | ||||
|         { | ||||
|             Dictionary<string, object> dict = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             dict["Description"] = Sanitize(role.Description); | ||||
|             dict["Members"] = role.Members.ToString(); | ||||
|             dict["Name"] = Sanitize(role.Name); | ||||
|             dict["Powers"] = role.Powers.ToString(); | ||||
|             dict["RoleID"] = role.RoleID.ToString(); | ||||
|             dict["Title"] = Sanitize(role.Title); | ||||
| 
 | ||||
|             return dict; | ||||
|         } | ||||
| 
 | ||||
|         public static GroupRolesData GroupRolesData(Dictionary<string, object> dict) | ||||
|         { | ||||
|             GroupRolesData role = new GroupRolesData(); | ||||
| 
 | ||||
|             if (dict == null) | ||||
|                 return role; | ||||
| 
 | ||||
|             if (dict.ContainsKey("Description") && dict["Description"] != null) | ||||
|                 role.Description = Sanitize(dict["Description"].ToString()); | ||||
|             else | ||||
|                 role.Description = string.Empty; | ||||
| 
 | ||||
|             if (dict.ContainsKey("Members") && dict["Members"] != null) | ||||
|                 role.Members = Int32.Parse(dict["Members"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("Name") && dict["Name"] != null) | ||||
|                 role.Name = Sanitize(dict["Name"].ToString()); | ||||
|             else | ||||
|                 role.Name = string.Empty; | ||||
| 
 | ||||
|             if (dict.ContainsKey("Powers") && dict["Powers"] != null) | ||||
|                 role.Powers = UInt64.Parse(dict["Powers"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("Title") && dict["Title"] != null) | ||||
|                 role.Title = Sanitize(dict["Title"].ToString()); | ||||
|             else | ||||
|                 role.Title = string.Empty; | ||||
| 
 | ||||
|             if (dict.ContainsKey("RoleID") && dict["RoleID"] != null) | ||||
|                 role.RoleID = UUID.Parse(dict["RoleID"].ToString()); | ||||
| 
 | ||||
|             return role; | ||||
|         } | ||||
| 
 | ||||
|         public static Dictionary<string, object> GroupRoleMembersData(ExtendedGroupRoleMembersData rmember) | ||||
|         { | ||||
|             Dictionary<string, object> dict = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             dict["RoleID"] = rmember.RoleID.ToString(); | ||||
|             dict["MemberID"] = rmember.MemberID; | ||||
|             return dict; | ||||
|         } | ||||
| 
 | ||||
|         public static ExtendedGroupRoleMembersData GroupRoleMembersData(Dictionary<string, object> dict) | ||||
|         { | ||||
|             ExtendedGroupRoleMembersData rmember = new ExtendedGroupRoleMembersData(); | ||||
| 
 | ||||
|             if (dict.ContainsKey("RoleID") && dict["RoleID"] != null) | ||||
|                 rmember.RoleID = new UUID(dict["RoleID"].ToString()); | ||||
| 
 | ||||
|             if (dict.ContainsKey("MemberID") && dict["MemberID"] != null) | ||||
|                 rmember.MemberID = dict["MemberID"].ToString(); | ||||
| 
 | ||||
|             return rmember; | ||||
|         } | ||||
| 
 | ||||
|         public static Dictionary<string, object> GroupInviteInfo(GroupInviteInfo invite) | ||||
|         { | ||||
|             Dictionary<string, object> dict = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             dict["InviteID"] = invite.InviteID.ToString(); | ||||
|             dict["GroupID"] = invite.GroupID.ToString(); | ||||
|             dict["RoleID"] = invite.RoleID.ToString(); | ||||
|             dict["AgentID"] = invite.AgentID; | ||||
| 
 | ||||
|             return dict; | ||||
|         } | ||||
| 
 | ||||
|         public static GroupInviteInfo GroupInviteInfo(Dictionary<string, object> dict) | ||||
|         { | ||||
|             if (dict == null) | ||||
|                 return null; | ||||
| 
 | ||||
|             GroupInviteInfo invite = new GroupInviteInfo(); | ||||
| 
 | ||||
|             invite.InviteID = new UUID(dict["InviteID"].ToString()); | ||||
|             invite.GroupID = new UUID(dict["GroupID"].ToString()); | ||||
|             invite.RoleID = new UUID(dict["RoleID"].ToString()); | ||||
|             invite.AgentID = Sanitize(dict["AgentID"].ToString()); | ||||
| 
 | ||||
|             return invite; | ||||
|         } | ||||
| 
 | ||||
|         public static Dictionary<string, object> GroupNoticeData(ExtendedGroupNoticeData notice) | ||||
|         { | ||||
|             Dictionary<string, object> dict = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             dict["NoticeID"] = notice.NoticeID.ToString(); | ||||
|             dict["Timestamp"] = notice.Timestamp.ToString(); | ||||
|             dict["FromName"] = Sanitize(notice.FromName); | ||||
|             dict["Subject"] = Sanitize(notice.Subject); | ||||
|             dict["HasAttachment"] = notice.HasAttachment.ToString(); | ||||
|             dict["AttachmentItemID"] = notice.AttachmentItemID.ToString(); | ||||
|             dict["AttachmentName"] = Sanitize(notice.AttachmentName); | ||||
|             dict["AttachmentType"] = notice.AttachmentType.ToString(); | ||||
|             dict["AttachmentOwnerID"] = Sanitize(notice.AttachmentOwnerID); | ||||
| 
 | ||||
|             return dict; | ||||
|         } | ||||
| 
 | ||||
|         public static ExtendedGroupNoticeData GroupNoticeData(Dictionary<string, object> dict) | ||||
|         { | ||||
|             ExtendedGroupNoticeData notice = new ExtendedGroupNoticeData(); | ||||
| 
 | ||||
|             if (dict == null) | ||||
|                 return notice; | ||||
| 
 | ||||
|             notice.NoticeID = new UUID(dict["NoticeID"].ToString()); | ||||
|             notice.Timestamp = UInt32.Parse(dict["Timestamp"].ToString()); | ||||
|             notice.FromName = Sanitize(dict["FromName"].ToString()); | ||||
|             notice.Subject = Sanitize(dict["Subject"].ToString()); | ||||
|             notice.HasAttachment = bool.Parse(dict["HasAttachment"].ToString()); | ||||
|             notice.AttachmentItemID = new UUID(dict["AttachmentItemID"].ToString()); | ||||
|             notice.AttachmentName = dict["AttachmentName"].ToString(); | ||||
|             notice.AttachmentType = byte.Parse(dict["AttachmentType"].ToString()); | ||||
|             notice.AttachmentOwnerID = dict["AttachmentOwnerID"].ToString(); | ||||
| 
 | ||||
|             return notice; | ||||
|         } | ||||
| 
 | ||||
|         public static Dictionary<string, object> GroupNoticeInfo(GroupNoticeInfo notice) | ||||
|         { | ||||
|             Dictionary<string, object> dict = GroupNoticeData(notice.noticeData); | ||||
| 
 | ||||
|             dict["GroupID"] = notice.GroupID.ToString(); | ||||
|             dict["Message"] = Sanitize(notice.Message); | ||||
| 
 | ||||
|             return dict; | ||||
|         } | ||||
| 
 | ||||
|         public static GroupNoticeInfo GroupNoticeInfo(Dictionary<string, object> dict) | ||||
|         { | ||||
|             GroupNoticeInfo notice = new GroupNoticeInfo(); | ||||
| 
 | ||||
|             notice.noticeData = GroupNoticeData(dict); | ||||
|             notice.GroupID = new UUID(dict["GroupID"].ToString()); | ||||
|             notice.Message = Sanitize(dict["Message"].ToString()); | ||||
| 
 | ||||
|             return notice; | ||||
|         } | ||||
| 
 | ||||
|         public static Dictionary<string, object> DirGroupsReplyData(DirGroupsReplyData g) | ||||
|         { | ||||
|             Dictionary<string, object> dict = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             dict["GroupID"] = g.groupID; | ||||
|             dict["Name"] = g.groupName; | ||||
|             dict["NMembers"] = g.members; | ||||
|             dict["SearchOrder"] = g.searchOrder; | ||||
| 
 | ||||
|             return dict; | ||||
|         } | ||||
| 
 | ||||
|         public static DirGroupsReplyData DirGroupsReplyData(Dictionary<string, object> dict) | ||||
|         { | ||||
|             DirGroupsReplyData g; | ||||
| 
 | ||||
|             g.groupID = new UUID(dict["GroupID"].ToString()); | ||||
|             g.groupName = dict["Name"].ToString(); | ||||
|             Int32.TryParse(dict["NMembers"].ToString(), out g.members); | ||||
|             float.TryParse(dict["SearchOrder"].ToString(), out g.searchOrder); | ||||
| 
 | ||||
|             return g; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -1,841 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Reflection; | ||||
| using log4net; | ||||
| using Mono.Addins; | ||||
| using Nini.Config; | ||||
| using OpenMetaverse; | ||||
| using OpenMetaverse.StructuredData; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Region.Framework.Interfaces; | ||||
| using OpenSim.Region.Framework.Scenes; | ||||
| using OpenSim.Services.Interfaces; | ||||
| using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; | ||||
| using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||||
| 
 | ||||
| namespace OpenSim.Groups | ||||
| { | ||||
|     [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsMessagingModule")] | ||||
|     public class GroupsMessagingModule : ISharedRegionModule, IGroupsMessagingModule | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private List<Scene> m_sceneList = new List<Scene>(); | ||||
|         private IPresenceService m_presenceService; | ||||
| 
 | ||||
|         private IMessageTransferModule m_msgTransferModule = null; | ||||
|         private IUserManagement m_UserManagement = null; | ||||
|         private IGroupsServicesConnector m_groupData = null; | ||||
| 
 | ||||
|         // Config Options | ||||
|         private bool m_groupMessagingEnabled; | ||||
|         private bool m_debugEnabled; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// If enabled, module only tries to send group IMs to online users by querying cached presence information. | ||||
|         /// </summary> | ||||
|         private bool m_messageOnlineAgentsOnly; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Cache for online users. | ||||
|         /// </summary> | ||||
|         /// <remarks> | ||||
|         /// Group ID is key, presence information for online members is value. | ||||
|         /// Will only be non-null if m_messageOnlineAgentsOnly = true | ||||
|         /// We cache here so that group messages don't constantly have to re-request the online user list to avoid | ||||
|         /// attempted expensive sending of messages to offline users. | ||||
|         /// The tradeoff is that a user that comes online will not receive messages consistently from all other users | ||||
|         /// until caches have updated. | ||||
|         /// Therefore, we set the cache expiry to just 20 seconds. | ||||
|         /// </remarks> | ||||
|         private ExpiringCache<UUID, PresenceInfo[]> m_usersOnlineCache; | ||||
| 
 | ||||
|         private int m_usersOnlineCacheExpirySeconds = 20; | ||||
| 
 | ||||
|         private Dictionary<UUID, List<string>> m_groupsAgentsDroppedFromChatSession = new Dictionary<UUID, List<string>>(); | ||||
|         private Dictionary<UUID, List<string>> m_groupsAgentsInvitedToChatSession = new Dictionary<UUID, List<string>>(); | ||||
| 
 | ||||
|         #region Region Module interfaceBase Members | ||||
| 
 | ||||
|         public void Initialise(IConfigSource config) | ||||
|         { | ||||
|             IConfig groupsConfig = config.Configs["Groups"]; | ||||
| 
 | ||||
|             if (groupsConfig == null) | ||||
|                 // Do not run this module by default. | ||||
|                 return; | ||||
| 
 | ||||
|             // if groups aren't enabled, we're not needed. | ||||
|             // if we're not specified as the connector to use, then we're not wanted | ||||
|             if ((groupsConfig.GetBoolean("Enabled", false) == false) | ||||
|                     || (groupsConfig.GetString("MessagingModule", "") != Name)) | ||||
|             { | ||||
|                 m_groupMessagingEnabled = false; | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             m_groupMessagingEnabled = groupsConfig.GetBoolean("MessagingEnabled", true); | ||||
| 
 | ||||
|             if (!m_groupMessagingEnabled) | ||||
|                 return; | ||||
| 
 | ||||
|             m_messageOnlineAgentsOnly = groupsConfig.GetBoolean("MessageOnlineUsersOnly", false); | ||||
| 
 | ||||
|             if (m_messageOnlineAgentsOnly) | ||||
|             { | ||||
|                 m_usersOnlineCache = new ExpiringCache<UUID, PresenceInfo[]>(); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 m_log.Error("[Groups.Messaging]: GroupsMessagingModule V2 requires MessageOnlineUsersOnly = true"); | ||||
|                 m_groupMessagingEnabled = false; | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             m_debugEnabled = groupsConfig.GetBoolean("MessagingDebugEnabled", m_debugEnabled); | ||||
| 
 | ||||
|             m_log.InfoFormat( | ||||
|                 "[Groups.Messaging]: GroupsMessagingModule enabled with MessageOnlineOnly = {0}, DebugEnabled = {1}", | ||||
|                 m_messageOnlineAgentsOnly, m_debugEnabled); | ||||
|         } | ||||
| 
 | ||||
|         public void AddRegion(Scene scene) | ||||
|         { | ||||
|             if (!m_groupMessagingEnabled) | ||||
|                 return; | ||||
| 
 | ||||
|             scene.RegisterModuleInterface<IGroupsMessagingModule>(this); | ||||
|             m_sceneList.Add(scene); | ||||
| 
 | ||||
|             scene.EventManager.OnNewClient += OnNewClient; | ||||
|             scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; | ||||
|             scene.EventManager.OnMakeChildAgent += OnMakeChildAgent; | ||||
|             scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; | ||||
|             scene.EventManager.OnClientLogin += OnClientLogin; | ||||
| 
 | ||||
|             scene.AddCommand( | ||||
|                 "Debug", | ||||
|                 this, | ||||
|                 "debug groups messaging verbose", | ||||
|                 "debug groups messaging verbose <true|false>", | ||||
|                 "This setting turns on very verbose groups messaging debugging", | ||||
|                 HandleDebugGroupsMessagingVerbose); | ||||
|         } | ||||
| 
 | ||||
|         public void RegionLoaded(Scene scene) | ||||
|         { | ||||
|             if (!m_groupMessagingEnabled) | ||||
|                 return; | ||||
| 
 | ||||
|             if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); | ||||
| 
 | ||||
|             m_groupData = scene.RequestModuleInterface<IGroupsServicesConnector>(); | ||||
| 
 | ||||
|             // No groups module, no groups messaging | ||||
|             if (m_groupData == null) | ||||
|             { | ||||
|                 m_log.Error("[Groups.Messaging]: Could not get IGroupsServicesConnector, GroupsMessagingModule is now disabled."); | ||||
|                 RemoveRegion(scene); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             m_msgTransferModule = scene.RequestModuleInterface<IMessageTransferModule>(); | ||||
| 
 | ||||
|             // No message transfer module, no groups messaging | ||||
|             if (m_msgTransferModule == null) | ||||
|             { | ||||
|                 m_log.Error("[Groups.Messaging]: Could not get MessageTransferModule"); | ||||
|                 RemoveRegion(scene); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             m_UserManagement = scene.RequestModuleInterface<IUserManagement>(); | ||||
| 
 | ||||
|             // No groups module, no groups messaging | ||||
|             if (m_UserManagement == null) | ||||
|             { | ||||
|                 m_log.Error("[Groups.Messaging]: Could not get IUserManagement, GroupsMessagingModule is now disabled."); | ||||
|                 RemoveRegion(scene); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (m_presenceService == null) | ||||
|                 m_presenceService = scene.PresenceService; | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveRegion(Scene scene) | ||||
|         { | ||||
|             if (!m_groupMessagingEnabled) | ||||
|                 return; | ||||
| 
 | ||||
|             if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); | ||||
| 
 | ||||
|             m_sceneList.Remove(scene); | ||||
|             scene.EventManager.OnNewClient -= OnNewClient; | ||||
|             scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; | ||||
|             scene.EventManager.OnClientLogin -= OnClientLogin; | ||||
|             scene.UnregisterModuleInterface<IGroupsMessagingModule>(this); | ||||
|         } | ||||
| 
 | ||||
|         public void Close() | ||||
|         { | ||||
|             if (!m_groupMessagingEnabled) | ||||
|                 return; | ||||
| 
 | ||||
|             if (m_debugEnabled) m_log.Debug("[Groups.Messaging]: Shutting down GroupsMessagingModule module."); | ||||
| 
 | ||||
|             m_sceneList.Clear(); | ||||
| 
 | ||||
|             m_groupData = null; | ||||
|             m_msgTransferModule = null; | ||||
|         } | ||||
| 
 | ||||
|         public Type ReplaceableInterface | ||||
|         { | ||||
|             get { return null; } | ||||
|         } | ||||
| 
 | ||||
|         public string Name | ||||
|         { | ||||
|             get { return "Groups Messaging Module V2"; } | ||||
|         } | ||||
| 
 | ||||
|         public void PostInitialise() | ||||
|         { | ||||
|             // NoOp | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
|         private void HandleDebugGroupsMessagingVerbose(object modules, string[] args) | ||||
|         { | ||||
|             if (args.Length < 5) | ||||
|             { | ||||
|                 MainConsole.Instance.Output("Usage: debug groups messaging verbose <true|false>"); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             bool verbose = false; | ||||
|             if (!bool.TryParse(args[4], out verbose)) | ||||
|             { | ||||
|                 MainConsole.Instance.Output("Usage: debug groups messaging verbose <true|false>"); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             m_debugEnabled = verbose; | ||||
| 
 | ||||
|             MainConsole.Instance.Output("{0} verbose logging set to {1}", Name, m_debugEnabled); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Not really needed, but does confirm that the group exists. | ||||
|         /// </summary> | ||||
|         public bool StartGroupChatSession(UUID agentID, UUID groupID) | ||||
|         { | ||||
|             if (m_debugEnabled) | ||||
|                 m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); | ||||
| 
 | ||||
|             GroupRecord groupInfo = m_groupData.GetGroupRecord(agentID.ToString(), groupID, null); | ||||
| 
 | ||||
|             if (groupInfo != null) | ||||
|             { | ||||
|                 return true; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void SendMessageToGroup(GridInstantMessage im, UUID groupID) | ||||
|         { | ||||
|             SendMessageToGroup(im, groupID, UUID.Zero, null); | ||||
|         } | ||||
| 
 | ||||
|         public void SendMessageToGroup( | ||||
|             GridInstantMessage im, UUID groupID, UUID sendingAgentForGroupCalls, Func<GroupMembersData, bool> sendCondition) | ||||
|         { | ||||
|             int requestStartTick = Environment.TickCount; | ||||
| 
 | ||||
|             UUID fromAgentID = new UUID(im.fromAgentID); | ||||
| 
 | ||||
|             // Unlike current XmlRpcGroups, Groups V2 can accept UUID.Zero when a perms check for the requesting agent | ||||
|             // is not necessary. | ||||
|             List<GroupMembersData> groupMembers = m_groupData.GetGroupMembers(UUID.Zero.ToString(), groupID); | ||||
| 
 | ||||
|             int groupMembersCount = groupMembers.Count; | ||||
|             PresenceInfo[] onlineAgents = null; | ||||
| 
 | ||||
|             // In V2 we always only send to online members. | ||||
|             // Sending to offline members is not an option. | ||||
|             string[] t1 = groupMembers.ConvertAll<string>(gmd => gmd.AgentID.ToString()).ToArray(); | ||||
| 
 | ||||
|             // We cache in order not to overwhelm the presence service on large grids with many groups.  This does | ||||
|             // mean that members coming online will not see all group members until after m_usersOnlineCacheExpirySeconds has elapsed. | ||||
|             // (assuming this is the same across all grid simulators). | ||||
|             if (!m_usersOnlineCache.TryGetValue(groupID, out onlineAgents)) | ||||
|             { | ||||
|                 onlineAgents = m_presenceService.GetAgents(t1); | ||||
|                 m_usersOnlineCache.Add(groupID, onlineAgents, m_usersOnlineCacheExpirySeconds); | ||||
|             } | ||||
| 
 | ||||
|             HashSet<string> onlineAgentsUuidSet = new HashSet<string>(); | ||||
|             Array.ForEach<PresenceInfo>(onlineAgents, pi => onlineAgentsUuidSet.Add(pi.UserID)); | ||||
| 
 | ||||
|             groupMembers = groupMembers.Where(gmd => onlineAgentsUuidSet.Contains(gmd.AgentID.ToString())).ToList(); | ||||
| 
 | ||||
| //            if (m_debugEnabled) | ||||
| //                    m_log.DebugFormat( | ||||
| //                        "[Groups.Messaging]: SendMessageToGroup called for group {0} with {1} visible members, {2} online", | ||||
| //                        groupID, groupMembersCount, groupMembers.Count()); | ||||
| 
 | ||||
|             im.imSessionID = groupID.Guid; | ||||
|             im.fromGroup = true; | ||||
|             IClientAPI thisClient = GetActiveClient(fromAgentID); | ||||
|             if (thisClient != null) | ||||
|             { | ||||
|                 im.RegionID = thisClient.Scene.RegionInfo.RegionID.Guid; | ||||
|             } | ||||
| 
 | ||||
|             if ((im.binaryBucket == null) || (im.binaryBucket.Length == 0) || ((im.binaryBucket.Length == 1 && im.binaryBucket[0] == 0))) | ||||
|             { | ||||
|                 ExtendedGroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero.ToString(), groupID, null); | ||||
|                 if (groupInfo != null) | ||||
|                     im.binaryBucket = Util.StringToBytes256(groupInfo.GroupName); | ||||
|             } | ||||
| 
 | ||||
|             // Send to self first of all | ||||
|             im.toAgentID = im.fromAgentID; | ||||
|             im.fromGroup = true; | ||||
|             ProcessMessageFromGroupSession(im); | ||||
| 
 | ||||
|             List<UUID> regions = new List<UUID>(); | ||||
|             List<UUID> clientsAlreadySent = new List<UUID>(); | ||||
| 
 | ||||
|             // Then send to everybody else | ||||
|             foreach (GroupMembersData member in groupMembers) | ||||
|             { | ||||
|                 if (member.AgentID.Guid == im.fromAgentID) | ||||
|                     continue; | ||||
| 
 | ||||
|                 if (clientsAlreadySent.Contains(member.AgentID)) | ||||
|                     continue; | ||||
| 
 | ||||
|                 clientsAlreadySent.Add(member.AgentID); | ||||
| 
 | ||||
|                 if (sendCondition != null) | ||||
|                 { | ||||
|                     if (!sendCondition(member)) | ||||
|                     { | ||||
|                         if (m_debugEnabled) | ||||
|                             m_log.DebugFormat( | ||||
|                                 "[Groups.Messaging]: Not sending to {0} as they do not fulfill send condition", | ||||
|                                  member.AgentID); | ||||
| 
 | ||||
|                         continue; | ||||
|                     } | ||||
|                 } | ||||
|                 else if (hasAgentDroppedGroupChatSession(member.AgentID.ToString(), groupID)) | ||||
|                 { | ||||
|                     // Don't deliver messages to people who have dropped this session | ||||
|                     if (m_debugEnabled) | ||||
|                         m_log.DebugFormat("[Groups.Messaging]: {0} has dropped session, not delivering to them", member.AgentID); | ||||
| 
 | ||||
|                     continue; | ||||
|                 } | ||||
| 
 | ||||
|                 im.toAgentID = member.AgentID.Guid; | ||||
| 
 | ||||
|                 IClientAPI client = GetActiveClient(member.AgentID); | ||||
|                 if (client == null) | ||||
|                 { | ||||
|                     // If they're not local, forward across the grid | ||||
|                     // BUT do it only once per region, please! Sim would be even better! | ||||
|                     if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Delivering to {0} via Grid", member.AgentID); | ||||
| 
 | ||||
|                     bool reallySend = true; | ||||
|                     if (onlineAgents != null) | ||||
|                     { | ||||
|                         PresenceInfo presence = onlineAgents.First(p => p.UserID == member.AgentID.ToString()); | ||||
|                         if (regions.Contains(presence.RegionID)) | ||||
|                             reallySend = false; | ||||
|                         else | ||||
|                             regions.Add(presence.RegionID); | ||||
|                     } | ||||
| 
 | ||||
|                     if (reallySend) | ||||
|                     { | ||||
|                         // We have to create a new IM structure because the transfer module | ||||
|                         // uses async send | ||||
|                         GridInstantMessage msg = new GridInstantMessage(im, true); | ||||
|                         m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { }); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     // Deliver locally, directly | ||||
|                     if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Passing to ProcessMessageFromGroupSession to deliver to {0} locally", client.Name); | ||||
| 
 | ||||
|                     ProcessMessageFromGroupSession(im); | ||||
|                 } | ||||
| 
 | ||||
|             } | ||||
| 
 | ||||
|             if (m_debugEnabled) | ||||
|                 m_log.DebugFormat( | ||||
|                     "[Groups.Messaging]: SendMessageToGroup for group {0} with {1} visible members, {2} online took {3}ms", | ||||
|                     groupID, groupMembersCount, groupMembers.Count(), Environment.TickCount - requestStartTick); | ||||
|         } | ||||
| 
 | ||||
|         #region SimGridEventHandlers | ||||
| 
 | ||||
|         void OnClientLogin(IClientAPI client) | ||||
|         { | ||||
|             if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: OnInstantMessage registered for {0}", client.Name); | ||||
|         } | ||||
| 
 | ||||
|         private void OnNewClient(IClientAPI client) | ||||
|         { | ||||
|             if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: OnInstantMessage registered for {0}", client.Name); | ||||
| 
 | ||||
|             ResetAgentGroupChatSessions(client.AgentId.ToString()); | ||||
|         } | ||||
| 
 | ||||
|         void OnMakeRootAgent(ScenePresence sp) | ||||
|         { | ||||
|             sp.ControllingClient.OnInstantMessage += OnInstantMessage; | ||||
|         } | ||||
| 
 | ||||
|         void OnMakeChildAgent(ScenePresence sp) | ||||
|         { | ||||
|             sp.ControllingClient.OnInstantMessage -= OnInstantMessage; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         private void OnGridInstantMessage(GridInstantMessage msg) | ||||
|         { | ||||
|             // The instant message module will only deliver messages of dialog types: | ||||
|             // MessageFromAgent, StartTyping, StopTyping, MessageFromObject | ||||
|             // | ||||
|             // Any other message type will not be delivered to a client by the | ||||
|             // Instant Message Module | ||||
| 
 | ||||
|             UUID regionID = new UUID(msg.RegionID); | ||||
|             if (m_debugEnabled) | ||||
|             { | ||||
|                 m_log.DebugFormat("[Groups.Messaging]: {0} called, IM from region {1}", | ||||
|                     System.Reflection.MethodBase.GetCurrentMethod().Name, regionID); | ||||
| 
 | ||||
|                 DebugGridInstantMessage(msg); | ||||
|             } | ||||
| 
 | ||||
|             // Incoming message from a group | ||||
|             if ((msg.fromGroup == true) && (msg.dialog == (byte)InstantMessageDialog.SessionSend)) | ||||
|             { | ||||
|                 // We have to redistribute the message across all members of the group who are here | ||||
|                 // on this sim | ||||
| 
 | ||||
|                 UUID GroupID = new UUID(msg.imSessionID); | ||||
| 
 | ||||
|                 Scene aScene = m_sceneList[0]; | ||||
|                 GridRegion regionOfOrigin = aScene.GridService.GetRegionByUUID(aScene.RegionInfo.ScopeID, regionID); | ||||
| 
 | ||||
|                 List<GroupMembersData> groupMembers = m_groupData.GetGroupMembers(UUID.Zero.ToString(), GroupID); | ||||
| 
 | ||||
|                 //if (m_debugEnabled) | ||||
|                 //    foreach (GroupMembersData m in groupMembers) | ||||
|                 //        m_log.DebugFormat("[Groups.Messaging]: member {0}", m.AgentID); | ||||
| 
 | ||||
|                 foreach (Scene s in m_sceneList) | ||||
|                 { | ||||
|                     s.ForEachScenePresence(sp => | ||||
|                         { | ||||
|                             // If we got this via grid messaging, it's because the caller thinks | ||||
|                             // that the root agent is here. We should only send the IM to root agents. | ||||
|                             if (sp.IsChildAgent) | ||||
|                                 return; | ||||
| 
 | ||||
|                             GroupMembersData m = groupMembers.Find(gmd => | ||||
|                                 { | ||||
|                                     return gmd.AgentID == sp.UUID; | ||||
|                                 }); | ||||
|                             if (m.AgentID == UUID.Zero) | ||||
|                             { | ||||
|                                 if (m_debugEnabled) | ||||
|                                     m_log.DebugFormat("[Groups.Messaging]: skipping agent {0} because he is not a member of the group", sp.UUID); | ||||
|                                 return; | ||||
|                             } | ||||
| 
 | ||||
|                             // Check if the user has an agent in the region where | ||||
|                             // the IM came from, and if so, skip it, because the IM | ||||
|                             // was already sent via that agent | ||||
|                             if (regionOfOrigin != null) | ||||
|                             { | ||||
|                                 AgentCircuitData aCircuit = s.AuthenticateHandler.GetAgentCircuitData(sp.UUID); | ||||
|                                 if (aCircuit != null) | ||||
|                                 { | ||||
|                                     if (aCircuit.ChildrenCapSeeds.Keys.Contains(regionOfOrigin.RegionHandle)) | ||||
|                                     { | ||||
|                                         if (m_debugEnabled) | ||||
|                                             m_log.DebugFormat("[Groups.Messaging]: skipping agent {0} because he has an agent in region of origin", sp.UUID); | ||||
|                                         return; | ||||
|                                     } | ||||
|                                     else | ||||
|                                     { | ||||
|                                         if (m_debugEnabled) | ||||
|                                             m_log.DebugFormat("[Groups.Messaging]: not skipping agent {0}", sp.UUID); | ||||
|                                     } | ||||
|                                 } | ||||
|                             } | ||||
| 
 | ||||
|                             UUID AgentID = sp.UUID; | ||||
|                             msg.toAgentID = AgentID.Guid; | ||||
| 
 | ||||
|                             if (!hasAgentDroppedGroupChatSession(AgentID.ToString(), GroupID)) | ||||
|                             { | ||||
|                                 if (!hasAgentBeenInvitedToGroupChatSession(AgentID.ToString(), GroupID)) | ||||
|                                     AddAgentToSession(AgentID, GroupID, msg); | ||||
|                                 else | ||||
|                                 { | ||||
|                                     if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Passing to ProcessMessageFromGroupSession to deliver to {0} locally", sp.Name); | ||||
| 
 | ||||
|                                     ProcessMessageFromGroupSession(msg); | ||||
|                                 } | ||||
|                             } | ||||
|                         }); | ||||
| 
 | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private void ProcessMessageFromGroupSession(GridInstantMessage msg) | ||||
|         { | ||||
|             if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Session message from {0} going to agent {1}", msg.fromAgentName, msg.toAgentID); | ||||
| 
 | ||||
|             UUID AgentID = new UUID(msg.fromAgentID); | ||||
|             UUID GroupID = new UUID(msg.imSessionID); | ||||
|             UUID toAgentID = new UUID(msg.toAgentID); | ||||
| 
 | ||||
|             switch (msg.dialog) | ||||
|             { | ||||
|                 case (byte)InstantMessageDialog.SessionAdd: | ||||
|                     AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); | ||||
|                     break; | ||||
| 
 | ||||
|                 case (byte)InstantMessageDialog.SessionDrop: | ||||
|                     AgentDroppedFromGroupChatSession(AgentID.ToString(), GroupID); | ||||
|                     break; | ||||
| 
 | ||||
|                 case (byte)InstantMessageDialog.SessionSend: | ||||
|                     // User hasn't dropped, so they're in the session, | ||||
|                     // maybe we should deliver it. | ||||
|                     IClientAPI client = GetActiveClient(new UUID(msg.toAgentID)); | ||||
|                     if (client != null) | ||||
|                     { | ||||
|                         // Deliver locally, directly | ||||
|                         if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Delivering to {0} locally", client.Name); | ||||
| 
 | ||||
|                         if (!hasAgentDroppedGroupChatSession(toAgentID.ToString(), GroupID)) | ||||
|                         { | ||||
|                             if (!hasAgentBeenInvitedToGroupChatSession(toAgentID.ToString(), GroupID)) | ||||
|                                 // This actually sends the message too, so no need to resend it | ||||
|                                 // with client.SendInstantMessage | ||||
|                                 AddAgentToSession(toAgentID, GroupID, msg); | ||||
|                             else | ||||
|                                 client.SendInstantMessage(msg); | ||||
|                         } | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         m_log.WarnFormat("[Groups.Messaging]: Received a message over the grid for a client that isn't here: {0}", msg.toAgentID); | ||||
|                     } | ||||
|                     break; | ||||
| 
 | ||||
|                 default: | ||||
|                     m_log.WarnFormat("[Groups.Messaging]: I don't know how to proccess a {0} message.", ((InstantMessageDialog)msg.dialog).ToString()); | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private void AddAgentToSession(UUID AgentID, UUID GroupID, GridInstantMessage msg) | ||||
|         { | ||||
|             // Agent not in session and hasn't dropped from session | ||||
|             // Add them to the session for now, and Invite them | ||||
|             AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); | ||||
| 
 | ||||
|             IClientAPI activeClient = GetActiveClient(AgentID); | ||||
|             if (activeClient != null) | ||||
|             { | ||||
|                 GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero.ToString(), GroupID, null); | ||||
|                 if (groupInfo != null) | ||||
|                 { | ||||
|                     if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Sending chatterbox invite instant message"); | ||||
| 
 | ||||
|                     UUID fromAgent = new UUID(msg.fromAgentID); | ||||
|                     // Force? open the group session dialog??? | ||||
|                     // and simultanously deliver the message, so we don't need to do a seperate client.SendInstantMessage(msg); | ||||
|                     IEventQueue eq = activeClient.Scene.RequestModuleInterface<IEventQueue>(); | ||||
|                     if (eq != null) | ||||
|                     { | ||||
|                         eq.ChatterboxInvitation( | ||||
|                             GroupID | ||||
|                             , groupInfo.GroupName | ||||
|                             , fromAgent | ||||
|                             , msg.message | ||||
|                             , AgentID | ||||
|                             , msg.fromAgentName | ||||
|                             , msg.dialog | ||||
|                             , msg.timestamp | ||||
|                             , msg.offline == 1 | ||||
|                             , (int)msg.ParentEstateID | ||||
|                             , msg.Position | ||||
|                             , 1 | ||||
|                             , new UUID(msg.imSessionID) | ||||
|                             , msg.fromGroup | ||||
|                             , OpenMetaverse.Utils.StringToBytes(groupInfo.GroupName) | ||||
|                             ); | ||||
| 
 | ||||
|                         var update = new GroupChatListAgentUpdateData(AgentID); | ||||
|                         var updates = new List<GroupChatListAgentUpdateData> { update }; | ||||
|                         eq.ChatterBoxSessionAgentListUpdates(GroupID, new UUID(msg.toAgentID), updates); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|         #region ClientEvents | ||||
|         private void OnInstantMessage(IClientAPI remoteClient, GridInstantMessage im) | ||||
|         { | ||||
|             if (m_debugEnabled) | ||||
|             { | ||||
|                 m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); | ||||
| 
 | ||||
|                 DebugGridInstantMessage(im); | ||||
|             } | ||||
| 
 | ||||
|             // Start group IM session | ||||
|             if ((im.dialog == (byte)InstantMessageDialog.SessionGroupStart)) | ||||
|             { | ||||
|                 if (m_debugEnabled) m_log.InfoFormat("[Groups.Messaging]: imSessionID({0}) toAgentID({1})", im.imSessionID, im.toAgentID); | ||||
| 
 | ||||
|                 UUID GroupID = new UUID(im.imSessionID); | ||||
|                 UUID AgentID = new UUID(im.fromAgentID); | ||||
| 
 | ||||
|                 GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero.ToString(), GroupID, null); | ||||
| 
 | ||||
|                 if (groupInfo != null) | ||||
|                 { | ||||
|                     AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); | ||||
| 
 | ||||
|                     ChatterBoxSessionStartReplyViaCaps(remoteClient, groupInfo.GroupName, GroupID); | ||||
| 
 | ||||
|                     IEventQueue queue = remoteClient.Scene.RequestModuleInterface<IEventQueue>(); | ||||
|                     if (queue != null) | ||||
|                     { | ||||
|                         var update = new GroupChatListAgentUpdateData(AgentID); | ||||
|                         var updates = new List<GroupChatListAgentUpdateData> { update }; | ||||
|                         queue.ChatterBoxSessionAgentListUpdates(GroupID, remoteClient.AgentId, updates); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // Send a message from locally connected client to a group | ||||
|             if ((im.dialog == (byte)InstantMessageDialog.SessionSend)) | ||||
|             { | ||||
|                 UUID GroupID = new UUID(im.imSessionID); | ||||
|                 UUID AgentID = new UUID(im.fromAgentID); | ||||
| 
 | ||||
|                 if (m_debugEnabled) | ||||
|                     m_log.DebugFormat("[Groups.Messaging]: Send message to session for group {0} with session ID {1}", GroupID, im.imSessionID.ToString()); | ||||
| 
 | ||||
|                 //If this agent is sending a message, then they want to be in the session | ||||
|                 AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); | ||||
| 
 | ||||
|                 SendMessageToGroup(im, GroupID); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
|         void ChatterBoxSessionStartReplyViaCaps(IClientAPI remoteClient, string groupName, UUID groupID) | ||||
|         { | ||||
|             if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); | ||||
| 
 | ||||
|             OSDMap moderatedMap = new OSDMap(4); | ||||
|             moderatedMap.Add("voice", OSD.FromBoolean(false)); | ||||
| 
 | ||||
|             OSDMap sessionMap = new OSDMap(4); | ||||
|             sessionMap.Add("moderated_mode", moderatedMap); | ||||
|             sessionMap.Add("session_name", OSD.FromString(groupName)); | ||||
|             sessionMap.Add("type", OSD.FromInteger(0)); | ||||
|             sessionMap.Add("voice_enabled", OSD.FromBoolean(false)); | ||||
| 
 | ||||
|             OSDMap bodyMap = new OSDMap(4); | ||||
|             bodyMap.Add("session_id", OSD.FromUUID(groupID)); | ||||
|             bodyMap.Add("temp_session_id", OSD.FromUUID(groupID)); | ||||
|             bodyMap.Add("success", OSD.FromBoolean(true)); | ||||
|             bodyMap.Add("session_info", sessionMap); | ||||
| 
 | ||||
|             IEventQueue queue = remoteClient.Scene.RequestModuleInterface<IEventQueue>(); | ||||
|             queue?.Enqueue(queue.BuildEvent("ChatterBoxSessionStartReply", bodyMap), remoteClient.AgentId); | ||||
|         } | ||||
| 
 | ||||
|         private void DebugGridInstantMessage(GridInstantMessage im) | ||||
|         { | ||||
|             // Don't log any normal IMs (privacy!) | ||||
|             if (m_debugEnabled && im.dialog != (byte)InstantMessageDialog.MessageFromAgent) | ||||
|             { | ||||
|                 m_log.WarnFormat("[Groups.Messaging]: IM: fromGroup({0})", im.fromGroup ? "True" : "False"); | ||||
|                 m_log.WarnFormat("[Groups.Messaging]: IM: Dialog({0})", ((InstantMessageDialog)im.dialog).ToString()); | ||||
|                 m_log.WarnFormat("[Groups.Messaging]: IM: fromAgentID({0})", im.fromAgentID.ToString()); | ||||
|                 m_log.WarnFormat("[Groups.Messaging]: IM: fromAgentName({0})", im.fromAgentName.ToString()); | ||||
|                 m_log.WarnFormat("[Groups.Messaging]: IM: imSessionID({0})", im.imSessionID.ToString()); | ||||
|                 m_log.WarnFormat("[Groups.Messaging]: IM: message({0})", im.message.ToString()); | ||||
|                 m_log.WarnFormat("[Groups.Messaging]: IM: offline({0})", im.offline.ToString()); | ||||
|                 m_log.WarnFormat("[Groups.Messaging]: IM: toAgentID({0})", im.toAgentID.ToString()); | ||||
|                 m_log.WarnFormat("[Groups.Messaging]: IM: binaryBucket({0})", OpenMetaverse.Utils.BytesToHexString(im.binaryBucket, "BinaryBucket")); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #region Client Tools | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Try to find an active IClientAPI reference for agentID giving preference to root connections | ||||
|         /// </summary> | ||||
|         private IClientAPI GetActiveClient(UUID agentID) | ||||
|         { | ||||
|             if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Looking for local client {0}", agentID); | ||||
| 
 | ||||
|             IClientAPI child = null; | ||||
| 
 | ||||
|             // Try root avatar first | ||||
|             foreach (Scene scene in m_sceneList) | ||||
|             { | ||||
|                 ScenePresence sp = scene.GetScenePresence(agentID); | ||||
|                 if (sp != null) | ||||
|                 { | ||||
|                     if (!sp.IsChildAgent) | ||||
|                     { | ||||
|                         if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Found root agent for client : {0}", sp.ControllingClient.Name); | ||||
|                         return sp.ControllingClient; | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Found child agent for client : {0}", sp.ControllingClient.Name); | ||||
|                         child = sp.ControllingClient; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // If we didn't find a root, then just return whichever child we found, or null if none | ||||
|             if (child == null) | ||||
|             { | ||||
|                 if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Could not find local client for agent : {0}", agentID); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Returning child agent for client : {0}", child.Name); | ||||
|             } | ||||
|             return child; | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
|         #region GroupSessionTracking | ||||
| 
 | ||||
|         public void ResetAgentGroupChatSessions(string agentID) | ||||
|         { | ||||
|             foreach (List<string> agentList in m_groupsAgentsDroppedFromChatSession.Values) | ||||
|                 agentList.Remove(agentID); | ||||
| 
 | ||||
|             foreach (List<string> agentList in m_groupsAgentsInvitedToChatSession.Values) | ||||
|                 agentList.Remove(agentID); | ||||
|         } | ||||
| 
 | ||||
|         public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID) | ||||
|         { | ||||
|             // If we're  tracking this group, and we can find them in the tracking, then they've been invited | ||||
|             return m_groupsAgentsInvitedToChatSession.ContainsKey(groupID) | ||||
|                 && m_groupsAgentsInvitedToChatSession[groupID].Contains(agentID); | ||||
|         } | ||||
| 
 | ||||
|         public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID) | ||||
|         { | ||||
|             // If we're tracking drops for this group, | ||||
|             // and we find them, well... then they've dropped | ||||
|             return m_groupsAgentsDroppedFromChatSession.ContainsKey(groupID) | ||||
|                 && m_groupsAgentsDroppedFromChatSession[groupID].Contains(agentID); | ||||
|         } | ||||
| 
 | ||||
|         public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID) | ||||
|         { | ||||
|             if (m_groupsAgentsDroppedFromChatSession.ContainsKey(groupID)) | ||||
|             { | ||||
|                 // If not in dropped list, add | ||||
|                 if (!m_groupsAgentsDroppedFromChatSession[groupID].Contains(agentID)) | ||||
|                 { | ||||
|                     m_groupsAgentsDroppedFromChatSession[groupID].Add(agentID); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void AgentInvitedToGroupChatSession(string agentID, UUID groupID) | ||||
|         { | ||||
|             // Add Session Status if it doesn't exist for this session | ||||
|             CreateGroupChatSessionTracking(groupID); | ||||
| 
 | ||||
|             // If nessesary, remove from dropped list | ||||
|             if (m_groupsAgentsDroppedFromChatSession[groupID].Contains(agentID)) | ||||
|             { | ||||
|                 m_groupsAgentsDroppedFromChatSession[groupID].Remove(agentID); | ||||
|             } | ||||
| 
 | ||||
|             // Add to invited | ||||
|             if (!m_groupsAgentsInvitedToChatSession[groupID].Contains(agentID)) | ||||
|                 m_groupsAgentsInvitedToChatSession[groupID].Add(agentID); | ||||
|         } | ||||
| 
 | ||||
|         private void CreateGroupChatSessionTracking(UUID groupID) | ||||
|         { | ||||
|             if (!m_groupsAgentsDroppedFromChatSession.ContainsKey(groupID)) | ||||
|             { | ||||
|                 m_groupsAgentsDroppedFromChatSession.Add(groupID, new List<string>()); | ||||
|                 m_groupsAgentsInvitedToChatSession.Add(groupID, new List<string>()); | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
|         #endregion | ||||
| 
 | ||||
|     } | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -1,289 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Reflection; | ||||
| using System.Text; | ||||
| 
 | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Server.Base; | ||||
| 
 | ||||
| using OpenMetaverse; | ||||
| using log4net; | ||||
| 
 | ||||
| namespace OpenSim.Groups | ||||
| { | ||||
|     public class GroupsServiceHGConnector | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private string m_ServerURI; | ||||
|         private object m_Lock = new object(); | ||||
| 
 | ||||
|         public GroupsServiceHGConnector(string url) | ||||
|         { | ||||
|             m_ServerURI = url; | ||||
|             if (!m_ServerURI.EndsWith("/")) | ||||
|                 m_ServerURI += "/"; | ||||
| 
 | ||||
|             m_log.DebugFormat("[Groups.HGConnector]: Groups server at {0}", m_ServerURI); | ||||
|         } | ||||
| 
 | ||||
|         public bool CreateProxy(string RequestingAgentID, string AgentID, string accessToken, UUID groupID, string url, string name, out string reason) | ||||
|         { | ||||
|             reason = string.Empty; | ||||
| 
 | ||||
|             Dictionary<string, object> sendData = new Dictionary<string,object>(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             sendData["AgentID"] = AgentID.ToString(); | ||||
|             sendData["AccessToken"] = accessToken; | ||||
|             sendData["GroupID"] = groupID.ToString(); | ||||
|             sendData["Location"] = url; | ||||
|             sendData["Name"] = name; | ||||
|             Dictionary<string, object> ret = MakeRequest("POSTGROUP", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString().ToLower() != "true") | ||||
|             { | ||||
|                 reason = ret["REASON"].ToString(); | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             return true; | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveAgentFromGroup(string AgentID, UUID GroupID, string token) | ||||
|         { | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["AgentID"] = AgentID; | ||||
|             sendData["GroupID"] = GroupID.ToString(); | ||||
|             sendData["AccessToken"] = GroupsDataUtils.Sanitize(token); | ||||
|             MakeRequest("REMOVEAGENTFROMGROUP", sendData); | ||||
|         } | ||||
| 
 | ||||
|         public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName, string token) | ||||
|         { | ||||
|             if (GroupID == UUID.Zero && (GroupName == null || (GroupName != null && GroupName == string.Empty))) | ||||
|                 return null; | ||||
| 
 | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             if (GroupID != UUID.Zero) | ||||
|                 sendData["GroupID"] = GroupID.ToString(); | ||||
|             if (!string.IsNullOrEmpty(GroupName)) | ||||
|                 sendData["Name"] = GroupsDataUtils.Sanitize(GroupName); | ||||
| 
 | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             sendData["AccessToken"] = GroupsDataUtils.Sanitize(token); | ||||
| 
 | ||||
|             Dictionary<string, object> ret = MakeRequest("GETGROUP", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return null; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return null; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString() == "NULL") | ||||
|                 return null; | ||||
| 
 | ||||
|             return GroupsDataUtils.GroupRecord((Dictionary<string, object>)ret["RESULT"]); | ||||
|         } | ||||
| 
 | ||||
|         public List<ExtendedGroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID, string token) | ||||
|         { | ||||
|             List<ExtendedGroupMembersData> members = new List<ExtendedGroupMembersData>(); | ||||
| 
 | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["GroupID"] = GroupID.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             sendData["AccessToken"] = GroupsDataUtils.Sanitize(token); | ||||
|             Dictionary<string, object> ret = MakeRequest("GETGROUPMEMBERS", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return members; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return members; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString() == "NULL") | ||||
|                 return members; | ||||
|             foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values) | ||||
|             { | ||||
|                 ExtendedGroupMembersData m = GroupsDataUtils.GroupMembersData((Dictionary<string, object>)v); | ||||
|                 members.Add(m); | ||||
|             } | ||||
| 
 | ||||
|             return members; | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID, string token) | ||||
|         { | ||||
|             List<GroupRolesData> roles = new List<GroupRolesData>(); | ||||
| 
 | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["GroupID"] = GroupID.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             sendData["AccessToken"] = GroupsDataUtils.Sanitize(token); | ||||
|             Dictionary<string, object> ret = MakeRequest("GETGROUPROLES", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return roles; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return roles; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString() == "NULL") | ||||
|                 return roles; | ||||
|             foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values) | ||||
|             { | ||||
|                 GroupRolesData m = GroupsDataUtils.GroupRolesData((Dictionary<string, object>)v); | ||||
|                 roles.Add(m); | ||||
|             } | ||||
| 
 | ||||
|             return roles; | ||||
|         } | ||||
| 
 | ||||
|         public List<ExtendedGroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID, string token) | ||||
|         { | ||||
|             List<ExtendedGroupRoleMembersData> rmembers = new List<ExtendedGroupRoleMembersData>(); | ||||
| 
 | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["GroupID"] = GroupID.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             sendData["AccessToken"] = GroupsDataUtils.Sanitize(token); | ||||
|             Dictionary<string, object> ret = MakeRequest("GETROLEMEMBERS", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return rmembers; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return rmembers; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString() == "NULL") | ||||
|                 return rmembers; | ||||
| 
 | ||||
|             foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values) | ||||
|             { | ||||
|                 ExtendedGroupRoleMembersData m = GroupsDataUtils.GroupRoleMembersData((Dictionary<string, object>)v); | ||||
|                 rmembers.Add(m); | ||||
|             } | ||||
| 
 | ||||
|             return rmembers; | ||||
|         } | ||||
| 
 | ||||
|         public bool AddNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, | ||||
|                                     bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID) | ||||
|         { | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["GroupID"] = groupID.ToString(); | ||||
|             sendData["NoticeID"] = noticeID.ToString(); | ||||
|             sendData["FromName"] = GroupsDataUtils.Sanitize(fromName); | ||||
|             sendData["Subject"] = GroupsDataUtils.Sanitize(subject); | ||||
|             sendData["Message"] = GroupsDataUtils.Sanitize(message); | ||||
|             sendData["HasAttachment"] = hasAttachment.ToString(); | ||||
|             if (hasAttachment) | ||||
|             { | ||||
|                 sendData["AttachmentType"] = attType.ToString(); | ||||
|                 sendData["AttachmentName"] = attName.ToString(); | ||||
|                 sendData["AttachmentItemID"] = attItemID.ToString(); | ||||
|                 sendData["AttachmentOwnerID"] = attOwnerID; | ||||
|             } | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
| 
 | ||||
|             Dictionary<string, object> ret = MakeRequest("ADDNOTICE", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString().ToLower() != "true") | ||||
|                 return false; | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         public bool VerifyNotice(UUID noticeID, UUID groupID) | ||||
|         { | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["NoticeID"] = noticeID.ToString(); | ||||
|             sendData["GroupID"] = groupID.ToString(); | ||||
|             Dictionary<string, object> ret = MakeRequest("VERIFYNOTICE", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString().ToLower() != "true") | ||||
|                 return false; | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         // | ||||
|         // | ||||
|         // | ||||
|         // | ||||
|         // | ||||
| 
 | ||||
|         #region Make Request | ||||
| 
 | ||||
|         private Dictionary<string, object> MakeRequest(string method, Dictionary<string, object> sendData) | ||||
|         { | ||||
|             sendData["METHOD"] = method; | ||||
| 
 | ||||
|             string reply = string.Empty; | ||||
|             lock (m_Lock) | ||||
|                 reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||||
|                          m_ServerURI + "hg-groups", | ||||
|                          ServerUtils.BuildQueryString(sendData)); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: reply was {0}", reply); | ||||
| 
 | ||||
|             if (string.IsNullOrEmpty(reply)) | ||||
|                 return null; | ||||
| 
 | ||||
|             Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse( | ||||
|                     reply); | ||||
| 
 | ||||
|             return replyData; | ||||
|         } | ||||
|         #endregion | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | @ -1,695 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Reflection; | ||||
| using System.Text; | ||||
| 
 | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Monitoring; | ||||
| using OpenSim.Framework.Servers; | ||||
| using OpenSim.Region.Framework.Scenes; | ||||
| using OpenSim.Region.Framework.Interfaces; | ||||
| using OpenSim.Services.Interfaces; | ||||
| 
 | ||||
| using OpenMetaverse; | ||||
| using Mono.Addins; | ||||
| using log4net; | ||||
| using Nini.Config; | ||||
| 
 | ||||
| namespace OpenSim.Groups | ||||
| { | ||||
|     [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsServiceHGConnectorModule")] | ||||
|     public class GroupsServiceHGConnectorModule : ISharedRegionModule, IGroupsServicesConnector | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private bool m_Enabled = false; | ||||
|         private IGroupsServicesConnector m_LocalGroupsConnector; | ||||
|         private string m_LocalGroupsServiceLocation; | ||||
|         private IUserManagement m_UserManagement; | ||||
|         private IOfflineIMService m_OfflineIM; | ||||
|         private IMessageTransferModule m_Messaging; | ||||
|         private List<Scene> m_Scenes; | ||||
|         private ForeignImporter m_ForeignImporter; | ||||
|         private string m_ServiceLocation; | ||||
|         private IConfigSource m_Config; | ||||
| 
 | ||||
|         private Dictionary<string, GroupsServiceHGConnector> m_NetworkConnectors = new Dictionary<string, GroupsServiceHGConnector>(); | ||||
|         private RemoteConnectorCacheWrapper m_CacheWrapper; // for caching info of external group services | ||||
| 
 | ||||
|         #region ISharedRegionModule | ||||
| 
 | ||||
|         public void Initialise(IConfigSource config) | ||||
|         { | ||||
|             IConfig groupsConfig = config.Configs["Groups"]; | ||||
|             if (groupsConfig == null) | ||||
|                 return; | ||||
| 
 | ||||
|             if ((groupsConfig.GetBoolean("Enabled", false) == false) | ||||
|                     || (groupsConfig.GetString("ServicesConnectorModule", string.Empty) != Name)) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             m_Config = config; | ||||
|             m_ServiceLocation = groupsConfig.GetString("LocalService", "local"); // local or remote | ||||
|             m_LocalGroupsServiceLocation = groupsConfig.GetString("GroupsExternalURI", "http://127.0.0.1"); | ||||
|             m_Scenes = new List<Scene>(); | ||||
| 
 | ||||
|             m_Enabled = true; | ||||
| 
 | ||||
|             m_log.DebugFormat("[Groups]: Initializing {0} with LocalService {1}", this.Name, m_ServiceLocation); | ||||
|         } | ||||
| 
 | ||||
|         public string Name | ||||
|         { | ||||
|             get { return "Groups HG Service Connector"; } | ||||
|         } | ||||
| 
 | ||||
|         public Type ReplaceableInterface | ||||
|         { | ||||
|             get { return null; } | ||||
|         } | ||||
| 
 | ||||
|         public void AddRegion(Scene scene) | ||||
|         { | ||||
|             if (!m_Enabled) | ||||
|                 return; | ||||
| 
 | ||||
|             m_log.DebugFormat("[Groups]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName); | ||||
|             scene.RegisterModuleInterface<IGroupsServicesConnector>(this); | ||||
|             m_Scenes.Add(scene); | ||||
| 
 | ||||
|             scene.EventManager.OnNewClient += OnNewClient; | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveRegion(Scene scene) | ||||
|         { | ||||
|             if (!m_Enabled) | ||||
|                 return; | ||||
| 
 | ||||
|             scene.UnregisterModuleInterface<IGroupsServicesConnector>(this); | ||||
|             m_Scenes.Remove(scene); | ||||
|         } | ||||
| 
 | ||||
|         public void RegionLoaded(Scene scene) | ||||
|         { | ||||
|             if (!m_Enabled) | ||||
|                 return; | ||||
| 
 | ||||
|             if (m_UserManagement == null) | ||||
|             { | ||||
|                 m_UserManagement = scene.RequestModuleInterface<IUserManagement>(); | ||||
|                 m_OfflineIM = scene.RequestModuleInterface<IOfflineIMService>(); | ||||
|                 m_Messaging = scene.RequestModuleInterface<IMessageTransferModule>(); | ||||
|                 m_ForeignImporter = new ForeignImporter(m_UserManagement); | ||||
| 
 | ||||
|                 if (m_ServiceLocation.Equals("local")) | ||||
|                 { | ||||
|                     m_LocalGroupsConnector = new GroupsServiceLocalConnectorModule(m_Config, m_UserManagement); | ||||
|                     // Also, if local, create the endpoint for the HGGroupsService | ||||
|                     new HGGroupsServiceRobustConnector(m_Config, MainServer.Instance, string.Empty, | ||||
|                         scene.RequestModuleInterface<IOfflineIMService>(), scene.RequestModuleInterface<IUserAccountService>()); | ||||
| 
 | ||||
|                 } | ||||
|                 else | ||||
|                     m_LocalGroupsConnector = new GroupsServiceRemoteConnectorModule(m_Config, m_UserManagement); | ||||
| 
 | ||||
|                 m_CacheWrapper = new RemoteConnectorCacheWrapper(m_UserManagement); | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         public void PostInitialise() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         public void Close() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
|         private void OnNewClient(IClientAPI client) | ||||
|         { | ||||
|             client.OnCompleteMovementToRegion += OnCompleteMovementToRegion; | ||||
|         } | ||||
| 
 | ||||
|         void OnCompleteMovementToRegion(IClientAPI client, bool arg2) | ||||
|         { | ||||
|             object sp = null; | ||||
|             if (client.Scene.TryGetScenePresence(client.AgentId, out sp)) | ||||
|             { | ||||
|                 if (sp is ScenePresence && ((ScenePresence)sp).PresenceType != PresenceType.Npc) | ||||
|                 { | ||||
|                     AgentCircuitData aCircuit = ((ScenePresence)sp).Scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId); | ||||
|                     if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0 && | ||||
|                         m_OfflineIM != null && m_Messaging != null) | ||||
|                     { | ||||
|                         List<GridInstantMessage> ims = m_OfflineIM.GetMessages(aCircuit.AgentID); | ||||
|                         if (ims != null && ims.Count > 0) | ||||
|                             foreach (GridInstantMessage im in ims) | ||||
|                                 m_Messaging.SendInstantMessage(im, delegate(bool success) { }); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #region IGroupsServicesConnector | ||||
| 
 | ||||
|         public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, | ||||
|             bool allowPublish, bool maturePublish, UUID founderID, out string reason) | ||||
|         { | ||||
|             reason = string.Empty; | ||||
|             if (m_UserManagement.IsLocalGridUser(RequestingAgentID)) | ||||
|                 return m_LocalGroupsConnector.CreateGroup(RequestingAgentID, name, charter, showInList, insigniaID, | ||||
|                     membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out reason); | ||||
|             else | ||||
|             { | ||||
|                 reason = "Only local grid users are allowed to create a new group"; | ||||
|                 return UUID.Zero; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, | ||||
|             bool openEnrollment, bool allowPublish, bool maturePublish, out string reason) | ||||
|         { | ||||
|             reason = string.Empty; | ||||
|             string url = string.Empty; | ||||
|             string name = string.Empty; | ||||
|             if (IsLocal(groupID, out url, out name)) | ||||
|                 return m_LocalGroupsConnector.UpdateGroup(AgentUUI(RequestingAgentID), groupID, charter, showInList, insigniaID, membershipFee, | ||||
|                     openEnrollment, allowPublish, maturePublish, out reason); | ||||
|             else | ||||
|             { | ||||
|                 reason = "Changes to remote group not allowed. Please go to the group's original world."; | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName) | ||||
|         { | ||||
|             string url = string.Empty; | ||||
|             string name = string.Empty; | ||||
|             if (IsLocal(GroupID, out url, out name)) | ||||
|                 return m_LocalGroupsConnector.GetGroupRecord(AgentUUI(RequestingAgentID), GroupID, GroupName); | ||||
|             else if (url != string.Empty) | ||||
|             { | ||||
|                 ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, GroupID); | ||||
|                 string accessToken = string.Empty; | ||||
|                 if (membership != null) | ||||
|                     accessToken = membership.AccessToken; | ||||
|                 else | ||||
|                     return null; | ||||
| 
 | ||||
|                 GroupsServiceHGConnector c = GetConnector(url); | ||||
|                 if (c != null) | ||||
|                 { | ||||
|                     ExtendedGroupRecord grec = m_CacheWrapper.GetGroupRecord(RequestingAgentID, GroupID, GroupName, delegate | ||||
|                     { | ||||
|                         return c.GetGroupRecord(AgentUUIForOutside(RequestingAgentID), GroupID, GroupName, accessToken); | ||||
|                     }); | ||||
| 
 | ||||
|                     if (grec != null) | ||||
|                         ImportForeigner(grec.FounderUUI); | ||||
|                     return grec; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|         public List<DirGroupsReplyData> FindGroups(string RequestingAgentIDstr, string search) | ||||
|         { | ||||
|             return m_LocalGroupsConnector.FindGroups(RequestingAgentIDstr, search); | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID) | ||||
|         { | ||||
|             string url = string.Empty, gname = string.Empty; | ||||
|             if (IsLocal(GroupID, out url, out gname)) | ||||
|             { | ||||
|                 string agentID = AgentUUI(RequestingAgentID); | ||||
|                 return m_LocalGroupsConnector.GetGroupMembers(agentID, GroupID); | ||||
|             } | ||||
|             else if (!string.IsNullOrEmpty(url)) | ||||
|             { | ||||
|                 ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, GroupID); | ||||
|                 string accessToken = string.Empty; | ||||
|                 if (membership != null) | ||||
|                     accessToken = membership.AccessToken; | ||||
|                 else | ||||
|                     return null; | ||||
| 
 | ||||
|                 GroupsServiceHGConnector c = GetConnector(url); | ||||
|                 if (c != null) | ||||
|                 { | ||||
|                     return m_CacheWrapper.GetGroupMembers(RequestingAgentID, GroupID, delegate | ||||
|                     { | ||||
|                         return c.GetGroupMembers(AgentUUIForOutside(RequestingAgentID), GroupID, accessToken); | ||||
|                     }); | ||||
| 
 | ||||
|                 } | ||||
|             } | ||||
|             return new List<GroupMembersData>(); | ||||
|         } | ||||
| 
 | ||||
|         public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason) | ||||
|         { | ||||
|             reason = string.Empty; | ||||
|             string url = string.Empty, gname = string.Empty; | ||||
| 
 | ||||
|             if (IsLocal(groupID, out url, out gname)) | ||||
|                 return m_LocalGroupsConnector.AddGroupRole(AgentUUI(RequestingAgentID), groupID, roleID, name, description, title, powers, out reason); | ||||
|             else | ||||
|             { | ||||
|                 reason = "Operation not allowed outside this group's origin world."; | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers) | ||||
|         { | ||||
|             string url = string.Empty, gname = string.Empty; | ||||
| 
 | ||||
|             if (IsLocal(groupID, out url, out gname)) | ||||
|                 return m_LocalGroupsConnector.UpdateGroupRole(AgentUUI(RequestingAgentID), groupID, roleID, name, description, title, powers); | ||||
|             else | ||||
|             { | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID) | ||||
|         { | ||||
|             string url = string.Empty, gname = string.Empty; | ||||
| 
 | ||||
|             if (IsLocal(groupID, out url, out gname)) | ||||
|                 m_LocalGroupsConnector.RemoveGroupRole(AgentUUI(RequestingAgentID), groupID, roleID); | ||||
|             else | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID groupID) | ||||
|         { | ||||
|             string url = string.Empty, gname = string.Empty; | ||||
| 
 | ||||
|             if (IsLocal(groupID, out url, out gname)) | ||||
|                 return m_LocalGroupsConnector.GetGroupRoles(AgentUUI(RequestingAgentID), groupID); | ||||
|             else if (!string.IsNullOrEmpty(url)) | ||||
|             { | ||||
|                 ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, groupID); | ||||
|                 string accessToken = string.Empty; | ||||
|                 if (membership != null) | ||||
|                     accessToken = membership.AccessToken; | ||||
|                 else | ||||
|                     return null; | ||||
| 
 | ||||
|                 GroupsServiceHGConnector c = GetConnector(url); | ||||
|                 if (c != null) | ||||
|                 { | ||||
|                     return m_CacheWrapper.GetGroupRoles(RequestingAgentID, groupID, delegate | ||||
|                     { | ||||
|                         return c.GetGroupRoles(AgentUUIForOutside(RequestingAgentID), groupID, accessToken); | ||||
|                     }); | ||||
| 
 | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return new List<GroupRolesData>(); | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID groupID) | ||||
|         { | ||||
|             string url = string.Empty, gname = string.Empty; | ||||
| 
 | ||||
|             if (IsLocal(groupID, out url, out gname)) | ||||
|                 return m_LocalGroupsConnector.GetGroupRoleMembers(AgentUUI(RequestingAgentID), groupID); | ||||
|             else if (!string.IsNullOrEmpty(url)) | ||||
|             { | ||||
|                 ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, groupID); | ||||
|                 string accessToken = string.Empty; | ||||
|                 if (membership != null) | ||||
|                     accessToken = membership.AccessToken; | ||||
|                 else | ||||
|                     return null; | ||||
| 
 | ||||
|                 GroupsServiceHGConnector c = GetConnector(url); | ||||
|                 if (c != null) | ||||
|                 { | ||||
|                     return m_CacheWrapper.GetGroupRoleMembers(RequestingAgentID, groupID, delegate | ||||
|                     { | ||||
|                         return c.GetGroupRoleMembers(AgentUUIForOutside(RequestingAgentID), groupID, accessToken); | ||||
|                     }); | ||||
| 
 | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return new List<GroupRoleMembersData>(); | ||||
|         } | ||||
| 
 | ||||
|         public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason) | ||||
|         { | ||||
|             string url = string.Empty; | ||||
|             string name = string.Empty; | ||||
|             reason = string.Empty; | ||||
| 
 | ||||
|             UUID uid = new UUID(AgentID); | ||||
|             if (IsLocal(GroupID, out url, out name)) | ||||
|             { | ||||
|                 if (m_UserManagement.IsLocalGridUser(uid)) // local user | ||||
|                 { | ||||
|                     // normal case: local group, local user | ||||
|                     return m_LocalGroupsConnector.AddAgentToGroup(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID, token, out reason); | ||||
|                 } | ||||
|                 else // local group, foreign user | ||||
|                 { | ||||
|                     // the user is accepting the  invitation, or joining, where the group resides | ||||
|                     token = UUID.Random().ToString(); | ||||
|                     bool success = m_LocalGroupsConnector.AddAgentToGroup(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID, token, out reason); | ||||
| 
 | ||||
|                     if (success) | ||||
|                     { | ||||
|                         // Here we always return true. The user has been added to the local group, | ||||
|                         // independent of whether the remote operation succeeds or not | ||||
|                         url = m_UserManagement.GetUserServerURL(uid, "GroupsServerURI"); | ||||
|                         if (url == string.Empty) | ||||
|                         { | ||||
|                             reason = "You don't have an accessible groups server in your home world. You membership to this group in only within this grid."; | ||||
|                             return true; | ||||
|                         } | ||||
| 
 | ||||
|                         GroupsServiceHGConnector c = GetConnector(url); | ||||
|                         if (c != null) | ||||
|                             c.CreateProxy(AgentUUI(RequestingAgentID), AgentID, token, GroupID, m_LocalGroupsServiceLocation, name, out reason); | ||||
|                         return true; | ||||
|                     } | ||||
|                     return false; | ||||
|                 } | ||||
|             } | ||||
|             else if (m_UserManagement.IsLocalGridUser(uid)) // local user | ||||
|             { | ||||
|                 // foreign group, local user. She's been added already by the HG service. | ||||
|                 // Let's just check | ||||
|                 if (m_LocalGroupsConnector.GetAgentGroupMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID) != null) | ||||
|                     return true; | ||||
|             } | ||||
| 
 | ||||
|             reason = "Operation not allowed outside this group's origin world"; | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID) | ||||
|         { | ||||
|             string url = string.Empty, name = string.Empty; | ||||
|             if (!IsLocal(GroupID, out url, out name) && url != string.Empty) | ||||
|             { | ||||
|                 ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID); | ||||
|                 if (membership != null) | ||||
|                 { | ||||
|                     GroupsServiceHGConnector c = GetConnector(url); | ||||
|                     if (c != null) | ||||
|                         c.RemoveAgentFromGroup(AgentUUIForOutside(AgentID), GroupID, membership.AccessToken); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // remove from local service | ||||
|             m_LocalGroupsConnector.RemoveAgentFromGroup(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID); | ||||
|         } | ||||
| 
 | ||||
|         public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID) | ||||
|         { | ||||
|             string url = string.Empty, gname = string.Empty; | ||||
| 
 | ||||
|             if (IsLocal(groupID, out url, out gname)) | ||||
|                 return m_LocalGroupsConnector.AddAgentToGroupInvite(AgentUUI(RequestingAgentID), inviteID, groupID, roleID, AgentUUI(agentID)); | ||||
|             else | ||||
|                 return false; | ||||
|         } | ||||
| 
 | ||||
|         public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID) | ||||
|         { | ||||
|             return m_LocalGroupsConnector.GetAgentToGroupInvite(AgentUUI(RequestingAgentID), inviteID); ; | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID) | ||||
|         { | ||||
|             m_LocalGroupsConnector.RemoveAgentToGroupInvite(AgentUUI(RequestingAgentID), inviteID); | ||||
|         } | ||||
| 
 | ||||
|         public void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) | ||||
|         { | ||||
|             string url = string.Empty, gname = string.Empty; | ||||
| 
 | ||||
|             if (IsLocal(GroupID, out url, out gname)) | ||||
|                 m_LocalGroupsConnector.AddAgentToGroupRole(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) | ||||
|         { | ||||
|             string url = string.Empty, gname = string.Empty; | ||||
| 
 | ||||
|             if (IsLocal(GroupID, out url, out gname)) | ||||
|                 m_LocalGroupsConnector.RemoveAgentFromGroupRole(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID); | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID) | ||||
|         { | ||||
|             string url = string.Empty, gname = string.Empty; | ||||
| 
 | ||||
|             if (IsLocal(GroupID, out url, out gname)) | ||||
|                 return m_LocalGroupsConnector.GetAgentGroupRoles(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID); | ||||
|             else | ||||
|                 return new List<GroupRolesData>(); | ||||
|         } | ||||
| 
 | ||||
|         public void SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID) | ||||
|         { | ||||
|             string url = string.Empty, gname = string.Empty; | ||||
| 
 | ||||
|             if (IsLocal(GroupID, out url, out gname)) | ||||
|                 m_LocalGroupsConnector.SetAgentActiveGroup(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID); | ||||
|         } | ||||
| 
 | ||||
|         public ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID) | ||||
|         { | ||||
|             return m_LocalGroupsConnector.GetAgentActiveMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID)); | ||||
|         } | ||||
| 
 | ||||
|         public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) | ||||
|         { | ||||
|             string url = string.Empty, gname = string.Empty; | ||||
| 
 | ||||
|             if (IsLocal(GroupID, out url, out gname)) | ||||
|                 m_LocalGroupsConnector.SetAgentActiveGroupRole(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID); | ||||
|         } | ||||
| 
 | ||||
|         public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile) | ||||
|         { | ||||
|             m_LocalGroupsConnector.UpdateMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, AcceptNotices, ListInProfile); | ||||
|         } | ||||
| 
 | ||||
|         public ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID) | ||||
|         { | ||||
|             string url = string.Empty, gname = string.Empty; | ||||
| 
 | ||||
|             if (IsLocal(GroupID, out url, out gname)) | ||||
|                 return m_LocalGroupsConnector.GetAgentGroupMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID); | ||||
|             else | ||||
|                 return null; | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupMembershipData> GetAgentGroupMemberships(string RequestingAgentID, string AgentID) | ||||
|         { | ||||
|             return m_LocalGroupsConnector.GetAgentGroupMemberships(AgentUUI(RequestingAgentID), AgentUUI(AgentID)); | ||||
|         } | ||||
| 
 | ||||
|         public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, | ||||
|             bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID) | ||||
|         { | ||||
|             string url = string.Empty, gname = string.Empty; | ||||
| 
 | ||||
|             if (IsLocal(groupID, out url, out gname)) | ||||
|             { | ||||
|                 if (m_LocalGroupsConnector.AddGroupNotice(AgentUUI(RequestingAgentID), groupID, noticeID, fromName, subject, message, | ||||
|                         hasAttachment, attType, attName, attItemID, AgentUUI(attOwnerID))) | ||||
|                 { | ||||
|                     // then send the notice to every grid for which there are members in this group | ||||
|                     List<GroupMembersData> members = m_LocalGroupsConnector.GetGroupMembers(AgentUUI(RequestingAgentID), groupID); | ||||
|                     List<string> urls = new List<string>(); | ||||
|                     foreach (GroupMembersData m in members) | ||||
|                     { | ||||
|                         if (!m_UserManagement.IsLocalGridUser(m.AgentID)) | ||||
|                         { | ||||
|                             string gURL = m_UserManagement.GetUserServerURL(m.AgentID, "GroupsServerURI"); | ||||
|                             if (!urls.Contains(gURL)) | ||||
|                                 urls.Add(gURL); | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     // so we have the list of urls to send the notice to | ||||
|                     // this may take a long time... | ||||
|                     WorkManager.RunInThread(delegate | ||||
|                     { | ||||
|                         foreach (string u in urls) | ||||
|                         { | ||||
|                             GroupsServiceHGConnector c = GetConnector(u); | ||||
|                             if (c != null) | ||||
|                             { | ||||
|                                 c.AddNotice(AgentUUIForOutside(RequestingAgentID), groupID, noticeID, fromName, subject, message, | ||||
|                                     hasAttachment, attType, attName, attItemID, AgentUUIForOutside(attOwnerID)); | ||||
|                             } | ||||
|                         } | ||||
|                     }, null, string.Format("AddGroupNotice (agent {0}, group {1})", RequestingAgentID, groupID)); | ||||
| 
 | ||||
|                     return true; | ||||
|                 } | ||||
| 
 | ||||
|                 return false; | ||||
|             } | ||||
|             else | ||||
|                 return false; | ||||
|         } | ||||
| 
 | ||||
|         public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID) | ||||
|         { | ||||
|             GroupNoticeInfo notice = m_LocalGroupsConnector.GetGroupNotice(AgentUUI(RequestingAgentID), noticeID); | ||||
| 
 | ||||
|             if (notice != null && notice.noticeData.HasAttachment && notice.noticeData.AttachmentOwnerID != null) | ||||
|                ImportForeigner(notice.noticeData.AttachmentOwnerID); | ||||
| 
 | ||||
|             return notice; | ||||
|         } | ||||
| 
 | ||||
|         public List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID) | ||||
|         { | ||||
|             return m_LocalGroupsConnector.GetGroupNotices(AgentUUI(RequestingAgentID), GroupID); | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
|         #region hypergrid groups | ||||
| 
 | ||||
|         private string AgentUUI(string AgentIDStr) | ||||
|         { | ||||
|             UUID AgentID = UUID.Zero; | ||||
|             if (!UUID.TryParse(AgentIDStr, out AgentID) || AgentID == UUID.Zero) | ||||
|                 return UUID.Zero.ToString(); | ||||
| 
 | ||||
|             if (m_UserManagement.IsLocalGridUser(AgentID)) | ||||
|                 return AgentID.ToString(); | ||||
| 
 | ||||
|             AgentCircuitData agent = null; | ||||
|             foreach (Scene scene in m_Scenes) | ||||
|             { | ||||
|                 agent = scene.AuthenticateHandler.GetAgentCircuitData(AgentID); | ||||
|                 if (agent != null) | ||||
|                     break; | ||||
|             } | ||||
|             if (agent != null) | ||||
|                 return Util.ProduceUserUniversalIdentifier(agent); | ||||
| 
 | ||||
|             // we don't know anything about this foreign user | ||||
|             // try asking the user management module, which may know more | ||||
|             return m_UserManagement.GetUserUUI(AgentID); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         private string AgentUUIForOutside(string AgentIDStr) | ||||
|         { | ||||
|             UUID AgentID = UUID.Zero; | ||||
|             if (!UUID.TryParse(AgentIDStr, out AgentID) || AgentID == UUID.Zero) | ||||
|                 return UUID.Zero.ToString(); | ||||
| 
 | ||||
|             AgentCircuitData agent = null; | ||||
|             foreach (Scene scene in m_Scenes) | ||||
|             { | ||||
|                 agent = scene.AuthenticateHandler.GetAgentCircuitData(AgentID); | ||||
|                 if (agent != null) | ||||
|                     break; | ||||
|             } | ||||
|             if (agent == null) // oops | ||||
|                 return AgentID.ToString(); | ||||
| 
 | ||||
|             return Util.ProduceUserUniversalIdentifier(agent); | ||||
|         } | ||||
| 
 | ||||
|         private UUID ImportForeigner(string uID) | ||||
|         { | ||||
|             UUID userID = UUID.Zero; | ||||
|             string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty; | ||||
|             if (Util.ParseUniversalUserIdentifier(uID, out userID, out url, out first, out last, out tmp)) | ||||
|                 m_UserManagement.AddUser(userID, first, last, url); | ||||
| 
 | ||||
|             return userID; | ||||
|         } | ||||
| 
 | ||||
|         private bool IsLocal(UUID groupID, out string serviceLocation, out string name) | ||||
|         { | ||||
|             serviceLocation = string.Empty; | ||||
|             name = string.Empty; | ||||
|             if (groupID.Equals(UUID.Zero)) | ||||
|                 return true; | ||||
| 
 | ||||
|             ExtendedGroupRecord group = m_LocalGroupsConnector.GetGroupRecord(UUID.Zero.ToString(), groupID, string.Empty); | ||||
|             if (group == null) | ||||
|             { | ||||
|                 //m_log.DebugFormat("[XXX]: IsLocal? group {0} not found -- no.", groupID); | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             serviceLocation = group.ServiceLocation; | ||||
|             name = group.GroupName; | ||||
|             bool isLocal = (group.ServiceLocation == string.Empty); | ||||
|             //m_log.DebugFormat("[XXX]: IsLocal? {0}", isLocal); | ||||
|             return isLocal; | ||||
|         } | ||||
| 
 | ||||
|         private GroupsServiceHGConnector GetConnector(string url) | ||||
|         { | ||||
|             lock (m_NetworkConnectors) | ||||
|             { | ||||
|                 if (m_NetworkConnectors.ContainsKey(url)) | ||||
|                     return m_NetworkConnectors[url]; | ||||
| 
 | ||||
|                 GroupsServiceHGConnector c = new GroupsServiceHGConnector(url); | ||||
|                 m_NetworkConnectors[url] = c; | ||||
|             } | ||||
| 
 | ||||
|             return m_NetworkConnectors[url]; | ||||
|         } | ||||
|         #endregion | ||||
|     } | ||||
| } | ||||
|  | @ -1,445 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Reflection; | ||||
| using System.Text; | ||||
| using System.Xml; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using Nini.Config; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Server.Base; | ||||
| using OpenSim.Services.Interfaces; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Server.Handlers.Base; | ||||
| using log4net; | ||||
| using OpenMetaverse; | ||||
| 
 | ||||
| namespace OpenSim.Groups | ||||
| { | ||||
|     public class HGGroupsServiceRobustConnector : ServiceConnector | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private HGGroupsService m_GroupsService; | ||||
|         private string m_ConfigName = "Groups"; | ||||
| 
 | ||||
|         // Called by Robust shell | ||||
|         public HGGroupsServiceRobustConnector(IConfigSource config, IHttpServer server, string configName) : | ||||
|             this(config, server, configName, null, null) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         // Called by the sim-bound module | ||||
|         public HGGroupsServiceRobustConnector(IConfigSource config, IHttpServer server, string configName, IOfflineIMService im, IUserAccountService users) : | ||||
|             base(config, server, configName) | ||||
|         { | ||||
|             if (configName != String.Empty) | ||||
|                 m_ConfigName = configName; | ||||
| 
 | ||||
|             m_log.DebugFormat("[Groups.RobustHGConnector]: Starting with config name {0}", m_ConfigName); | ||||
| 
 | ||||
|             string homeURI = Util.GetConfigVarFromSections<string>(config, "HomeURI", | ||||
|                 new string[] { "Startup", "Hypergrid", m_ConfigName}, string.Empty); | ||||
|             if (homeURI == string.Empty) | ||||
|                 throw new Exception(String.Format("[Groups.RobustHGConnector]: please provide the HomeURI [Startup] or in section {0}", m_ConfigName)); | ||||
| 
 | ||||
|             IConfig cnf = config.Configs[m_ConfigName]; | ||||
|             if (cnf == null) | ||||
|                 throw new Exception(String.Format("[Groups.RobustHGConnector]: {0} section does not exist", m_ConfigName)); | ||||
| 
 | ||||
|             if (im == null) | ||||
|             { | ||||
|                 string imDll = cnf.GetString("OfflineIMService", string.Empty); | ||||
|                 if (imDll == string.Empty) | ||||
|                     throw new Exception(String.Format("[Groups.RobustHGConnector]: please provide OfflineIMService in section {0}", m_ConfigName)); | ||||
| 
 | ||||
|                 Object[] args = new Object[] { config }; | ||||
|                 im = ServerUtils.LoadPlugin<IOfflineIMService>(imDll, args); | ||||
|             } | ||||
| 
 | ||||
|             if (users == null) | ||||
|             { | ||||
|                 string usersDll = cnf.GetString("UserAccountService", string.Empty); | ||||
|                 if (usersDll == string.Empty) | ||||
|                     throw new Exception(String.Format("[Groups.RobustHGConnector]: please provide UserAccountService in section {0}", m_ConfigName)); | ||||
| 
 | ||||
|                 Object[] args = new Object[] { config }; | ||||
|                 users = ServerUtils.LoadPlugin<IUserAccountService>(usersDll, args); | ||||
|             } | ||||
| 
 | ||||
|             m_GroupsService = new HGGroupsService(config, im, users, homeURI); | ||||
| 
 | ||||
|             server.AddStreamHandler(new HGGroupsServicePostHandler(m_GroupsService)); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public class HGGroupsServicePostHandler : BaseStreamHandler | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private HGGroupsService m_GroupsService; | ||||
| 
 | ||||
|         public HGGroupsServicePostHandler(HGGroupsService service) : | ||||
|             base("POST", "/hg-groups") | ||||
|         { | ||||
|             m_GroupsService = service; | ||||
|         } | ||||
| 
 | ||||
|         protected override byte[] ProcessRequest(string path, Stream requestData, | ||||
|                 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||||
|         { | ||||
|             string body; | ||||
|             using(StreamReader sr = new StreamReader(requestData)) | ||||
|                 body = sr.ReadToEnd(); | ||||
| 
 | ||||
|             body = body.Trim(); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: query String: {0}", body); | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 Dictionary<string, object> request = | ||||
|                         ServerUtils.ParseQueryString(body); | ||||
| 
 | ||||
|                 if (!request.ContainsKey("METHOD")) | ||||
|                     return FailureResult(); | ||||
| 
 | ||||
|                 string method = request["METHOD"].ToString(); | ||||
|                 request.Remove("METHOD"); | ||||
| 
 | ||||
|                 m_log.DebugFormat("[Groups.RobustHGConnector]: {0}", method); | ||||
|                 switch (method) | ||||
|                 { | ||||
|                     case "POSTGROUP": | ||||
|                         return HandleAddGroupProxy(request); | ||||
|                     case "REMOVEAGENTFROMGROUP": | ||||
|                         return HandleRemoveAgentFromGroup(request); | ||||
|                     case "GETGROUP": | ||||
|                         return HandleGetGroup(request); | ||||
|                     case "ADDNOTICE": | ||||
|                         return HandleAddNotice(request); | ||||
|                     case "VERIFYNOTICE": | ||||
|                         return HandleVerifyNotice(request); | ||||
|                     case "GETGROUPMEMBERS": | ||||
|                         return HandleGetGroupMembers(request); | ||||
|                     case "GETGROUPROLES": | ||||
|                         return HandleGetGroupRoles(request); | ||||
|                     case "GETROLEMEMBERS": | ||||
|                         return HandleGetRoleMembers(request); | ||||
| 
 | ||||
|                 } | ||||
|                 m_log.DebugFormat("[Groups.RobustHGConnector]: unknown method request: {0}", method); | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 m_log.Error(string.Format("[Groups.RobustHGConnector]: Exception {0} ", e.Message), e); | ||||
|             } | ||||
| 
 | ||||
|             return FailureResult(); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleAddGroupProxy(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") | ||||
|                 || !request.ContainsKey("AgentID") | ||||
|                 || !request.ContainsKey("AccessToken") || !request.ContainsKey("Location")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
| 
 | ||||
|             else | ||||
|             { | ||||
|                 string RequestingAgentID = request["RequestingAgentID"].ToString(); | ||||
|                 string agentID = request["AgentID"].ToString(); | ||||
|                 UUID groupID = new UUID(request["GroupID"].ToString()); | ||||
|                 string accessToken = request["AccessToken"].ToString(); | ||||
|                 string location = request["Location"].ToString(); | ||||
|                 string name = string.Empty; | ||||
|                 if (request.ContainsKey("Name")) | ||||
|                     name = request["Name"].ToString(); | ||||
| 
 | ||||
|                 string reason = string.Empty; | ||||
|                 bool success = m_GroupsService.CreateGroupProxy(RequestingAgentID, agentID, accessToken, groupID, location, name, out reason); | ||||
|                 result["REASON"] = reason; | ||||
|                 result["RESULT"] = success.ToString(); | ||||
|             } | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleRemoveAgentFromGroup(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("AccessToken") || !request.ContainsKey("AgentID") || | ||||
|                 !request.ContainsKey("GroupID")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
|             else | ||||
|             { | ||||
|                 UUID groupID = new UUID(request["GroupID"].ToString()); | ||||
|                 string agentID = request["AgentID"].ToString(); | ||||
|                 string token = request["AccessToken"].ToString(); | ||||
| 
 | ||||
|                 if (!m_GroupsService.RemoveAgentFromGroup(agentID, agentID, groupID, token)) | ||||
|                     NullResult(result, "Internal error"); | ||||
|                 else | ||||
|                     result["RESULT"] = "true"; | ||||
|             } | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result)); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleGetGroup(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AccessToken")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
|             else | ||||
|             { | ||||
|                 string RequestingAgentID = request["RequestingAgentID"].ToString(); | ||||
|                 string token = request["AccessToken"].ToString(); | ||||
| 
 | ||||
|                 UUID groupID = UUID.Zero; | ||||
|                 string groupName = string.Empty; | ||||
| 
 | ||||
|                 if (request.ContainsKey("GroupID")) | ||||
|                     groupID = new UUID(request["GroupID"].ToString()); | ||||
|                 if (request.ContainsKey("Name")) | ||||
|                     groupName = request["Name"].ToString(); | ||||
| 
 | ||||
|                 ExtendedGroupRecord grec = m_GroupsService.GetGroupRecord(RequestingAgentID, groupID, groupName, token); | ||||
|                 if (grec == null) | ||||
|                     NullResult(result, "Group not found"); | ||||
|                 else | ||||
|                     result["RESULT"] = GroupsDataUtils.GroupRecord(grec); | ||||
|             } | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleGetGroupMembers(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("AccessToken")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
|             else | ||||
|             { | ||||
|                 UUID groupID = new UUID(request["GroupID"].ToString()); | ||||
|                 string requestingAgentID = request["RequestingAgentID"].ToString(); | ||||
|                 string token = request["AccessToken"].ToString(); | ||||
| 
 | ||||
|                 List<ExtendedGroupMembersData> members = m_GroupsService.GetGroupMembers(requestingAgentID, groupID, token); | ||||
|                 if (members == null || (members != null && members.Count == 0)) | ||||
|                 { | ||||
|                     NullResult(result, "No members"); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     Dictionary<string, object> dict = new Dictionary<string, object>(); | ||||
|                     int i = 0; | ||||
|                     foreach (ExtendedGroupMembersData m in members) | ||||
|                     { | ||||
|                         dict["m-" + i++] = GroupsDataUtils.GroupMembersData(m); | ||||
|                     } | ||||
| 
 | ||||
|                     result["RESULT"] = dict; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleGetGroupRoles(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("AccessToken")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
|             else | ||||
|             { | ||||
|                 UUID groupID = new UUID(request["GroupID"].ToString()); | ||||
|                 string requestingAgentID = request["RequestingAgentID"].ToString(); | ||||
|                 string token = request["AccessToken"].ToString(); | ||||
| 
 | ||||
|                 List<GroupRolesData> roles = m_GroupsService.GetGroupRoles(requestingAgentID, groupID, token); | ||||
|                 if (roles == null || (roles != null && roles.Count == 0)) | ||||
|                 { | ||||
|                     NullResult(result, "No members"); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     Dictionary<string, object> dict = new Dictionary<string, object>(); | ||||
|                     int i = 0; | ||||
|                     foreach (GroupRolesData r in roles) | ||||
|                         dict["r-" + i++] = GroupsDataUtils.GroupRolesData(r); | ||||
| 
 | ||||
|                     result["RESULT"] = dict; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleGetRoleMembers(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("AccessToken")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
|             else | ||||
|             { | ||||
|                 UUID groupID = new UUID(request["GroupID"].ToString()); | ||||
|                 string requestingAgentID = request["RequestingAgentID"].ToString(); | ||||
|                 string token = request["AccessToken"].ToString(); | ||||
| 
 | ||||
|                 List<ExtendedGroupRoleMembersData> rmembers = m_GroupsService.GetGroupRoleMembers(requestingAgentID, groupID, token); | ||||
|                 if (rmembers == null || (rmembers != null && rmembers.Count == 0)) | ||||
|                 { | ||||
|                     NullResult(result, "No members"); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     Dictionary<string, object> dict = new Dictionary<string, object>(); | ||||
|                     int i = 0; | ||||
|                     foreach (ExtendedGroupRoleMembersData rm in rmembers) | ||||
|                         dict["rm-" + i++] = GroupsDataUtils.GroupRoleMembersData(rm); | ||||
| 
 | ||||
|                     result["RESULT"] = dict; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleAddNotice(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("NoticeID") || | ||||
|                 !request.ContainsKey("FromName") || !request.ContainsKey("Subject") || !request.ContainsKey("Message") || | ||||
|                 !request.ContainsKey("HasAttachment")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
| 
 | ||||
|             else | ||||
|             { | ||||
| 
 | ||||
|                 bool hasAtt = bool.Parse(request["HasAttachment"].ToString()); | ||||
|                 byte attType = 0; | ||||
|                 string attName = string.Empty; | ||||
|                 string attOwner = string.Empty; | ||||
|                 UUID attItem = UUID.Zero; | ||||
|                 if (request.ContainsKey("AttachmentType")) | ||||
|                     attType = byte.Parse(request["AttachmentType"].ToString()); | ||||
|                 if (request.ContainsKey("AttachmentName")) | ||||
|                     attName = request["AttachmentType"].ToString(); | ||||
|                 if (request.ContainsKey("AttachmentItemID")) | ||||
|                     attItem = new UUID(request["AttachmentItemID"].ToString()); | ||||
|                 if (request.ContainsKey("AttachmentOwnerID")) | ||||
|                     attOwner = request["AttachmentOwnerID"].ToString(); | ||||
| 
 | ||||
|                 bool success = m_GroupsService.AddNotice(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()), | ||||
|                         new UUID(request["NoticeID"].ToString()), request["FromName"].ToString(), request["Subject"].ToString(), | ||||
|                         request["Message"].ToString(), hasAtt, attType, attName, attItem, attOwner); | ||||
| 
 | ||||
|                 result["RESULT"] = success.ToString(); | ||||
|             } | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleVerifyNotice(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("NoticeID") || !request.ContainsKey("GroupID")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
| 
 | ||||
|             else | ||||
|             { | ||||
|                 UUID noticeID = new UUID(request["NoticeID"].ToString()); | ||||
|                 UUID groupID = new UUID(request["GroupID"].ToString()); | ||||
| 
 | ||||
|                 bool success = m_GroupsService.VerifyNotice(noticeID, groupID); | ||||
|                 //m_log.DebugFormat("[XXX]: VerifyNotice returned {0}", success); | ||||
|                 result["RESULT"] = success.ToString(); | ||||
|             } | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         // | ||||
|         // | ||||
|         // | ||||
|         // | ||||
|         // | ||||
| 
 | ||||
|         #region Helpers | ||||
| 
 | ||||
|         private void NullResult(Dictionary<string, object> result, string reason) | ||||
|         { | ||||
|             result["RESULT"] = "NULL"; | ||||
|             result["REASON"] = reason; | ||||
|         } | ||||
| 
 | ||||
|         private byte[] FailureResult() | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
|             NullResult(result, "Unknown method"); | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
|     } | ||||
| } | ||||
|  | @ -1,112 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Framework; | ||||
| 
 | ||||
| namespace OpenSim.Groups | ||||
| { | ||||
|     public interface IGroupsServicesConnector | ||||
|     { | ||||
|         UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, | ||||
|             bool openEnrollment, bool allowPublish, bool maturePublish, UUID founderID, out string reason); | ||||
|         bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, | ||||
|             bool openEnrollment, bool allowPublish, bool maturePublish, out string reason); | ||||
|         ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName); | ||||
|         List<DirGroupsReplyData> FindGroups(string RequestingAgentIDstr, string search); | ||||
|         List<GroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID); | ||||
| 
 | ||||
|         bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason); | ||||
|         bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers); | ||||
|         void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID); | ||||
|         List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID); | ||||
|         List<GroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID); | ||||
| 
 | ||||
|         bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason); | ||||
|         void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID); | ||||
| 
 | ||||
|         bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID); | ||||
|         GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID); | ||||
|         void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID); | ||||
| 
 | ||||
|         void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID); | ||||
|         void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID); | ||||
|         List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID); | ||||
| 
 | ||||
|         void SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID); | ||||
|         ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID); | ||||
| 
 | ||||
|         void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID); | ||||
|         void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile); | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Get information about a specific group to which the user belongs. | ||||
|         /// </summary> | ||||
|         /// <param name="RequestingAgentID">The agent requesting the information.</param> | ||||
|         /// <param name="AgentID">The agent requested.</param> | ||||
|         /// <param name="GroupID">The group requested.</param> | ||||
|         /// <returns> | ||||
|         /// If the user is a member of the group then the data structure is returned.  If not, then null is returned. | ||||
|         /// </returns> | ||||
|         ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID); | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Get information about the groups to which a user belongs. | ||||
|         /// </summary> | ||||
|         /// <param name="RequestingAgentID">The agent requesting the information.</param> | ||||
|         /// <param name="AgentID">The agent requested.</param> | ||||
|         /// <returns> | ||||
|         /// Information about the groups to which the user belongs.  If the user belongs to no groups then an empty | ||||
|         /// list is returned. | ||||
|         /// </returns> | ||||
|         List<GroupMembershipData> GetAgentGroupMemberships(string RequestingAgentID, string AgentID); | ||||
| 
 | ||||
|         bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, | ||||
|             bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID); | ||||
|         GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID); | ||||
|         List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public class GroupInviteInfo | ||||
|     { | ||||
|         public UUID GroupID  = UUID.Zero; | ||||
|         public UUID RoleID   = UUID.Zero; | ||||
|         public string AgentID  = string.Empty; | ||||
|         public UUID InviteID = UUID.Zero; | ||||
|     } | ||||
| 
 | ||||
|     public class GroupNoticeInfo | ||||
|     { | ||||
|         public ExtendedGroupNoticeData noticeData = new ExtendedGroupNoticeData(); | ||||
|         public UUID GroupID = UUID.Zero; | ||||
|         public string Message = string.Empty; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -1,326 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Reflection; | ||||
| using System.Text; | ||||
| 
 | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Region.Framework.Scenes; | ||||
| using OpenSim.Region.Framework.Interfaces; | ||||
| using OpenSim.Services.Interfaces; | ||||
| 
 | ||||
| using OpenMetaverse; | ||||
| using Mono.Addins; | ||||
| using log4net; | ||||
| using Nini.Config; | ||||
| 
 | ||||
| namespace OpenSim.Groups | ||||
| { | ||||
|     [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsServiceLocalConnectorModule")] | ||||
|     public class GroupsServiceLocalConnectorModule : ISharedRegionModule, IGroupsServicesConnector | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private bool m_Enabled = false; | ||||
|         private GroupsService m_GroupsService; | ||||
|         private IUserManagement m_UserManagement; | ||||
|         private List<Scene> m_Scenes; | ||||
|         private ForeignImporter m_ForeignImporter; | ||||
| 
 | ||||
|         #region constructors | ||||
|         public GroupsServiceLocalConnectorModule() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         public GroupsServiceLocalConnectorModule(IConfigSource config, IUserManagement uman) | ||||
|         { | ||||
|             Init(config); | ||||
|             m_UserManagement = uman; | ||||
|             m_ForeignImporter = new ForeignImporter(uman); | ||||
|         } | ||||
|         #endregion | ||||
| 
 | ||||
|         private void Init(IConfigSource config) | ||||
|         { | ||||
|             m_GroupsService = new GroupsService(config); | ||||
|             m_Scenes = new List<Scene>(); | ||||
|         } | ||||
| 
 | ||||
|         #region ISharedRegionModule | ||||
| 
 | ||||
|         public void Initialise(IConfigSource config) | ||||
|         { | ||||
|             IConfig groupsConfig = config.Configs["Groups"]; | ||||
|             if (groupsConfig == null) | ||||
|                 return; | ||||
| 
 | ||||
|             if ((groupsConfig.GetBoolean("Enabled", false) == false) | ||||
|                     || (groupsConfig.GetString("ServicesConnectorModule", string.Empty) != Name)) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             Init(config); | ||||
|             m_Enabled = true; | ||||
| 
 | ||||
|             m_log.DebugFormat("[Groups]: Initializing {0}", this.Name); | ||||
|         } | ||||
| 
 | ||||
|         public string Name | ||||
|         { | ||||
|             get { return "Groups Local Service Connector"; } | ||||
|         } | ||||
| 
 | ||||
|         public Type ReplaceableInterface | ||||
|         { | ||||
|             get { return null; } | ||||
|         } | ||||
| 
 | ||||
|         public void AddRegion(Scene scene) | ||||
|         { | ||||
|             if (!m_Enabled) | ||||
|                 return; | ||||
| 
 | ||||
|             m_log.DebugFormat("[Groups]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName); | ||||
|             scene.RegisterModuleInterface<IGroupsServicesConnector>(this); | ||||
|             m_Scenes.Add(scene); | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveRegion(Scene scene) | ||||
|         { | ||||
|             if (!m_Enabled) | ||||
|                 return; | ||||
| 
 | ||||
|             scene.UnregisterModuleInterface<IGroupsServicesConnector>(this); | ||||
|             m_Scenes.Remove(scene); | ||||
|         } | ||||
| 
 | ||||
|         public void RegionLoaded(Scene scene) | ||||
|         { | ||||
|             if (!m_Enabled) | ||||
|                 return; | ||||
| 
 | ||||
|             if (m_UserManagement == null) | ||||
|             { | ||||
|                 m_UserManagement = scene.RequestModuleInterface<IUserManagement>(); | ||||
|                 m_ForeignImporter = new ForeignImporter(m_UserManagement); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void PostInitialise() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         public void Close() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
|         #region IGroupsServicesConnector | ||||
| 
 | ||||
|         public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, | ||||
|             bool allowPublish, bool maturePublish, UUID founderID, out string reason) | ||||
|         { | ||||
|             m_log.DebugFormat("[Groups]: Creating group {0}", name); | ||||
|             reason = string.Empty; | ||||
|             return m_GroupsService.CreateGroup(RequestingAgentID.ToString(), name, charter, showInList, insigniaID, | ||||
|                     membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out reason); | ||||
|         } | ||||
| 
 | ||||
|         public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, | ||||
|             bool openEnrollment, bool allowPublish, bool maturePublish, out string reason) | ||||
|         { | ||||
|             reason = string.Empty; | ||||
|             m_GroupsService.UpdateGroup(RequestingAgentID, groupID, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish); | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName) | ||||
|         { | ||||
|             if (GroupID != UUID.Zero) | ||||
|                 return m_GroupsService.GetGroupRecord(RequestingAgentID, GroupID); | ||||
|             else if (GroupName != null) | ||||
|                 return m_GroupsService.GetGroupRecord(RequestingAgentID, GroupName); | ||||
| 
 | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|         public List<DirGroupsReplyData> FindGroups(string RequestingAgentIDstr, string search) | ||||
|         { | ||||
|             return m_GroupsService.FindGroups(RequestingAgentIDstr, search); | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID) | ||||
|         { | ||||
|             List<ExtendedGroupMembersData> _members = m_GroupsService.GetGroupMembers(RequestingAgentID, GroupID); | ||||
|             if (_members != null && _members.Count > 0) | ||||
|             { | ||||
|                 List<GroupMembersData> members = _members.ConvertAll<GroupMembersData>(new Converter<ExtendedGroupMembersData, GroupMembersData>(m_ForeignImporter.ConvertGroupMembersData)); | ||||
|                 return members; | ||||
|             } | ||||
| 
 | ||||
|             return new List<GroupMembersData>(); | ||||
|         } | ||||
| 
 | ||||
|         public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason) | ||||
|         { | ||||
|             return m_GroupsService.AddGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers, out reason); | ||||
|         } | ||||
| 
 | ||||
|         public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers) | ||||
|         { | ||||
|             return m_GroupsService.UpdateGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers); | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID) | ||||
|         { | ||||
|             m_GroupsService.RemoveGroupRole(RequestingAgentID, groupID, roleID); | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID) | ||||
|         { | ||||
|             return m_GroupsService.GetGroupRoles(RequestingAgentID, GroupID); | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID) | ||||
|         { | ||||
|             List<ExtendedGroupRoleMembersData> _rm = m_GroupsService.GetGroupRoleMembers(RequestingAgentID, GroupID); | ||||
|             if (_rm != null && _rm.Count > 0) | ||||
|             { | ||||
|                 List<GroupRoleMembersData> rm = _rm.ConvertAll<GroupRoleMembersData>(new Converter<ExtendedGroupRoleMembersData, GroupRoleMembersData>(m_ForeignImporter.ConvertGroupRoleMembersData)); | ||||
|                 return rm; | ||||
|             } | ||||
| 
 | ||||
|             return new List<GroupRoleMembersData>(); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason) | ||||
|         { | ||||
|             return m_GroupsService.AddAgentToGroup(RequestingAgentID, AgentID, GroupID, RoleID, token, out reason); | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID) | ||||
|         { | ||||
|             m_GroupsService.RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID); | ||||
|         } | ||||
| 
 | ||||
|         public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID) | ||||
|         { | ||||
|             return m_GroupsService.AddAgentToGroupInvite(RequestingAgentID, inviteID, groupID, roleID, agentID); | ||||
|         } | ||||
| 
 | ||||
|         public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID) | ||||
|         { | ||||
|             return m_GroupsService.GetAgentToGroupInvite(RequestingAgentID, inviteID); ; | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID) | ||||
|         { | ||||
|             m_GroupsService.RemoveAgentToGroupInvite(RequestingAgentID, inviteID); | ||||
|         } | ||||
| 
 | ||||
|         public void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) | ||||
|         { | ||||
|             m_GroupsService.AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID); | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) | ||||
|         { | ||||
|             m_GroupsService.RemoveAgentFromGroupRole(RequestingAgentID, AgentID, GroupID, RoleID); | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID) | ||||
|         { | ||||
|             return m_GroupsService.GetAgentGroupRoles(RequestingAgentID, AgentID, GroupID); | ||||
|         } | ||||
| 
 | ||||
|         public void SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID) | ||||
|         { | ||||
|             m_GroupsService.SetAgentActiveGroup(RequestingAgentID, AgentID, GroupID); | ||||
|         } | ||||
| 
 | ||||
|         public ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID) | ||||
|         { | ||||
|             return m_GroupsService.GetAgentActiveMembership(RequestingAgentID, AgentID); | ||||
|         } | ||||
| 
 | ||||
|         public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) | ||||
|         { | ||||
|             m_GroupsService.SetAgentActiveGroupRole(RequestingAgentID, AgentID, GroupID, RoleID); | ||||
|         } | ||||
| 
 | ||||
|         public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile) | ||||
|         { | ||||
|             m_GroupsService.UpdateMembership(RequestingAgentID, AgentID, GroupID, AcceptNotices, ListInProfile); | ||||
|         } | ||||
| 
 | ||||
|         public ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID) | ||||
|         { | ||||
|             return m_GroupsService.GetAgentGroupMembership(RequestingAgentID, AgentID, GroupID); ; | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupMembershipData> GetAgentGroupMemberships(string RequestingAgentID, string AgentID) | ||||
|         { | ||||
|             return m_GroupsService.GetAgentGroupMemberships(RequestingAgentID, AgentID); | ||||
|         } | ||||
| 
 | ||||
|         public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, | ||||
|             bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID) | ||||
|         { | ||||
|             return m_GroupsService.AddGroupNotice(RequestingAgentID, groupID, noticeID, fromName, subject, message, | ||||
|                 hasAttachment, attType, attName, attItemID, attOwnerID); | ||||
|         } | ||||
| 
 | ||||
|         public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID) | ||||
|         { | ||||
|             GroupNoticeInfo notice = m_GroupsService.GetGroupNotice(RequestingAgentID, noticeID); | ||||
| 
 | ||||
|             //if (notice != null && notice.noticeData.HasAttachment && notice.noticeData.AttachmentOwnerID != null) | ||||
|             //{ | ||||
|             //    UUID userID = UUID.Zero; | ||||
|             //    string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty; | ||||
|             //    Util.ParseUniversalUserIdentifier(notice.noticeData.AttachmentOwnerID, out userID, out url, out first, out last, out tmp); | ||||
|             //    if (url != string.Empty) | ||||
|             //        m_UserManagement.AddUser(userID, first, last, url); | ||||
|             //} | ||||
| 
 | ||||
|             return notice; | ||||
|         } | ||||
| 
 | ||||
|         public List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID) | ||||
|         { | ||||
|             return m_GroupsService.GetGroupNotices(RequestingAgentID, GroupID); | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
|     } | ||||
| } | ||||
|  | @ -1,36 +0,0 @@ | |||
| using System.Reflection; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Runtime.InteropServices; | ||||
| using Mono.Addins; | ||||
| 
 | ||||
| // General Information about an assembly is controlled through the following | ||||
| // set of attributes. Change these attribute values to modify the information | ||||
| // associated with an assembly. | ||||
| [assembly: AssemblyTitle("OpenSim.Addons.Groups")] | ||||
| [assembly: AssemblyDescription("")] | ||||
| [assembly: AssemblyConfiguration("")] | ||||
| [assembly: AssemblyCompany("http://opensimulator.org")] | ||||
| [assembly: AssemblyProduct("OpenSim.Addons.Groups")] | ||||
| [assembly: AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")] | ||||
| [assembly: AssemblyTrademark("")] | ||||
| [assembly: AssemblyCulture("")] | ||||
| 
 | ||||
| // Setting ComVisible to false makes the types in this assembly not visible | ||||
| // to COM components.  If you need to access a type in this assembly from | ||||
| // COM, set the ComVisible attribute to true on that type. | ||||
| [assembly: ComVisible(false)] | ||||
| 
 | ||||
| // The following GUID is for the ID of the typelib if this project is exposed to COM | ||||
| [assembly: Guid("313d4865-d179-4735-9b5a-fe74885878b2")] | ||||
| 
 | ||||
| // Version information for an assembly consists of the following four values: | ||||
| // | ||||
| //      Major Version | ||||
| //      Minor Version | ||||
| //      Build Number | ||||
| //      Revision | ||||
| // | ||||
| [assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)] | ||||
| 
 | ||||
| [assembly: Addin("OpenSim.Groups", OpenSim.VersionInfo.VersionNumber)] | ||||
| [assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] | ||||
|  | @ -1,696 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Reflection; | ||||
| using System.Text; | ||||
| 
 | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.ServiceAuth; | ||||
| using OpenSim.Server.Base; | ||||
| 
 | ||||
| using OpenMetaverse; | ||||
| using log4net; | ||||
| using Nini.Config; | ||||
| 
 | ||||
| namespace OpenSim.Groups | ||||
| { | ||||
|     public class GroupsServiceRemoteConnector | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private string m_ServerURI; | ||||
|         private IServiceAuth m_Auth; | ||||
|         private object m_Lock = new object(); | ||||
| 
 | ||||
|         public GroupsServiceRemoteConnector(IConfigSource config) | ||||
|         { | ||||
|             IConfig groupsConfig = config.Configs["Groups"]; | ||||
|             string url = groupsConfig.GetString("GroupsServerURI", string.Empty); | ||||
|             if (!Uri.IsWellFormedUriString(url, UriKind.Absolute)) | ||||
|                 throw new Exception(string.Format("[Groups.RemoteConnector]: Malformed groups server URL {0}. Fix it or disable the Groups feature.", url)); | ||||
| 
 | ||||
|             m_ServerURI = url; | ||||
|             if (!m_ServerURI.EndsWith("/")) | ||||
|                 m_ServerURI += "/"; | ||||
| 
 | ||||
|             /// This is from BaseServiceConnector | ||||
|             string authType = Util.GetConfigVarFromSections<string>(config, "AuthType", new string[] { "Network", "Groups" }, "None"); | ||||
| 
 | ||||
|             switch (authType) | ||||
|             { | ||||
|                 case "BasicHttpAuthentication": | ||||
|                     m_Auth = new BasicHttpAuthentication(config, "Groups"); | ||||
|                     break; | ||||
|             } | ||||
|             /// | ||||
| 
 | ||||
|             m_log.DebugFormat("[Groups.RemoteConnector]: Groups server at {0}, authentication {1}", | ||||
|                 m_ServerURI, (m_Auth == null ? "None" : m_Auth.GetType().ToString())); | ||||
|         } | ||||
| 
 | ||||
|         public ExtendedGroupRecord CreateGroup(string RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, | ||||
|                                 bool allowPublish, bool maturePublish, UUID founderID, out string reason) | ||||
|         { | ||||
|             reason = string.Empty; | ||||
| 
 | ||||
|             ExtendedGroupRecord rec = new ExtendedGroupRecord(); | ||||
|             rec.AllowPublish = allowPublish; | ||||
|             rec.Charter = charter; | ||||
|             rec.FounderID = founderID; | ||||
|             rec.GroupName = name; | ||||
|             rec.GroupPicture = insigniaID; | ||||
|             rec.MaturePublish = maturePublish; | ||||
|             rec.MembershipFee = membershipFee; | ||||
|             rec.OpenEnrollment = openEnrollment; | ||||
|             rec.ShowInList = showInList; | ||||
| 
 | ||||
|             Dictionary<string, object> sendData = GroupsDataUtils.GroupRecord(rec); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             sendData["OP"] = "ADD"; | ||||
|             Dictionary<string, object> ret = MakeRequest("PUTGROUP", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return null; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString() == "NULL") | ||||
|             { | ||||
|                 reason = ret["REASON"].ToString(); | ||||
|                 return null; | ||||
|             } | ||||
| 
 | ||||
|             return GroupsDataUtils.GroupRecord((Dictionary<string, object>)ret["RESULT"]); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         public ExtendedGroupRecord UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish) | ||||
|         { | ||||
|             ExtendedGroupRecord rec = new ExtendedGroupRecord(); | ||||
|             rec.AllowPublish = allowPublish; | ||||
|             rec.Charter = charter; | ||||
|             rec.GroupPicture = insigniaID; | ||||
|             rec.MaturePublish = maturePublish; | ||||
|             rec.GroupID = groupID; | ||||
|             rec.MembershipFee = membershipFee; | ||||
|             rec.OpenEnrollment = openEnrollment; | ||||
|             rec.ShowInList = showInList; | ||||
| 
 | ||||
|             Dictionary<string, object> sendData = GroupsDataUtils.GroupRecord(rec); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             sendData["OP"] = "UPDATE"; | ||||
|             Dictionary<string, object> ret = MakeRequest("PUTGROUP", sendData); | ||||
| 
 | ||||
|             if (ret == null || (ret != null && (!ret.ContainsKey("RESULT") || ret["RESULT"].ToString() == "NULL"))) | ||||
|                 return null; | ||||
| 
 | ||||
|             return GroupsDataUtils.GroupRecord((Dictionary<string, object>)ret["RESULT"]); | ||||
|         } | ||||
| 
 | ||||
|         public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName) | ||||
|         { | ||||
|             if (GroupID == UUID.Zero && (GroupName == null || (GroupName != null && GroupName == string.Empty))) | ||||
|                 return null; | ||||
| 
 | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             if (GroupID != UUID.Zero) | ||||
|                 sendData["GroupID"] = GroupID.ToString(); | ||||
|             if (!string.IsNullOrEmpty(GroupName)) | ||||
|                 sendData["Name"] = GroupsDataUtils.Sanitize(GroupName); | ||||
| 
 | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
| 
 | ||||
|             Dictionary<string, object> ret = MakeRequest("GETGROUP", sendData); | ||||
| 
 | ||||
|             if (ret == null || (ret != null && (!ret.ContainsKey("RESULT") || ret["RESULT"].ToString() == "NULL"))) | ||||
|                 return null; | ||||
| 
 | ||||
|             return GroupsDataUtils.GroupRecord((Dictionary<string, object>)ret["RESULT"]); | ||||
|         } | ||||
| 
 | ||||
|         public List<DirGroupsReplyData> FindGroups(string RequestingAgentIDstr, string query) | ||||
|         { | ||||
|             List<DirGroupsReplyData> hits = new List<DirGroupsReplyData>(); | ||||
|             if (string.IsNullOrEmpty(query)) | ||||
|                 return hits; | ||||
| 
 | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["Query"] = query; | ||||
|             sendData["RequestingAgentID"] = RequestingAgentIDstr; | ||||
| 
 | ||||
|             Dictionary<string, object> ret = MakeRequest("FINDGROUPS", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return hits; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return hits; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString() == "NULL") | ||||
|                 return hits; | ||||
| 
 | ||||
|             foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values) | ||||
|             { | ||||
|                 DirGroupsReplyData m = GroupsDataUtils.DirGroupsReplyData((Dictionary<string, object>)v); | ||||
|                 hits.Add(m); | ||||
|             } | ||||
| 
 | ||||
|             return hits; | ||||
|         } | ||||
| 
 | ||||
|         public GroupMembershipData AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason) | ||||
|         { | ||||
|             reason = string.Empty; | ||||
| 
 | ||||
|             Dictionary<string, object> sendData = new Dictionary<string,object>(); | ||||
|             sendData["AgentID"] = AgentID; | ||||
|             sendData["GroupID"] = GroupID.ToString(); | ||||
|             sendData["RoleID"] = RoleID.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             sendData["AccessToken"] = token; | ||||
|             Dictionary<string, object> ret = MakeRequest("ADDAGENTTOGROUP", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return null; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return null; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString() == "NULL") | ||||
|             { | ||||
|                 reason = ret["REASON"].ToString(); | ||||
|                 return null; | ||||
|             } | ||||
| 
 | ||||
|             return GroupsDataUtils.GroupMembershipData((Dictionary<string, object>)ret["RESULT"]); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID) | ||||
|         { | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["AgentID"] = AgentID; | ||||
|             sendData["GroupID"] = GroupID.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             MakeRequest("REMOVEAGENTFROMGROUP", sendData); | ||||
|         } | ||||
| 
 | ||||
|         public ExtendedGroupMembershipData GetMembership(string RequestingAgentID, string AgentID, UUID GroupID) | ||||
|         { | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["AgentID"] = AgentID; | ||||
|             if (GroupID != UUID.Zero) | ||||
|                 sendData["GroupID"] = GroupID.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             Dictionary<string, object> ret = MakeRequest("GETMEMBERSHIP", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return null; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return null; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString() == "NULL") | ||||
|                 return null; | ||||
| 
 | ||||
|             return GroupsDataUtils.GroupMembershipData((Dictionary<string, object>)ret["RESULT"]); | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupMembershipData> GetMemberships(string RequestingAgentID, string AgentID) | ||||
|         { | ||||
|             List<GroupMembershipData> memberships = new List<GroupMembershipData>(); | ||||
| 
 | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["AgentID"] = AgentID; | ||||
|             sendData["ALL"] = "true"; | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             Dictionary<string, object> ret = MakeRequest("GETMEMBERSHIP", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return memberships; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return memberships; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString() == "NULL") | ||||
|                 return memberships; | ||||
| 
 | ||||
|             foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values) | ||||
|             { | ||||
|                 GroupMembershipData m = GroupsDataUtils.GroupMembershipData((Dictionary<string, object>)v); | ||||
|                 memberships.Add(m); | ||||
|             } | ||||
| 
 | ||||
|             return memberships; | ||||
|         } | ||||
| 
 | ||||
|         public List<ExtendedGroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID) | ||||
|         { | ||||
|             List<ExtendedGroupMembersData> members = new List<ExtendedGroupMembersData>(); | ||||
| 
 | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["GroupID"] = GroupID.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
| 
 | ||||
|             Dictionary<string, object> ret = MakeRequest("GETGROUPMEMBERS", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return members; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return members; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString() == "NULL") | ||||
|                 return members; | ||||
| 
 | ||||
|             foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values) | ||||
|             { | ||||
|                 ExtendedGroupMembersData m = GroupsDataUtils.GroupMembersData((Dictionary<string, object>)v); | ||||
|                 members.Add(m); | ||||
|             } | ||||
| 
 | ||||
|             return members; | ||||
|         } | ||||
| 
 | ||||
|         public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason) | ||||
|         { | ||||
|             reason = string.Empty; | ||||
| 
 | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["GroupID"] = groupID.ToString(); | ||||
|             sendData["RoleID"] = roleID.ToString(); | ||||
|             sendData["Name"] = GroupsDataUtils.Sanitize(name); | ||||
|             sendData["Description"] = GroupsDataUtils.Sanitize(description); | ||||
|             sendData["Title"] = GroupsDataUtils.Sanitize(title); | ||||
|             sendData["Powers"] = powers.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             sendData["OP"] = "ADD"; | ||||
|             Dictionary<string, object> ret = MakeRequest("PUTROLE", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString().ToLower() != "true") | ||||
|             { | ||||
|                 reason = ret["REASON"].ToString(); | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers) | ||||
|         { | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["GroupID"] = groupID.ToString(); | ||||
|             sendData["RoleID"] = roleID.ToString(); | ||||
|             sendData["Name"] = GroupsDataUtils.Sanitize(name); | ||||
|             sendData["Description"] = GroupsDataUtils.Sanitize(description); | ||||
|             sendData["Title"] = GroupsDataUtils.Sanitize(title); | ||||
|             sendData["Powers"] = powers.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             sendData["OP"] = "UPDATE"; | ||||
|             Dictionary<string, object> ret = MakeRequest("PUTROLE", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString().ToLower() != "true") | ||||
|                 return false; | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID) | ||||
|         { | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["GroupID"] = groupID.ToString(); | ||||
|             sendData["RoleID"] = roleID.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             MakeRequest("REMOVEROLE", sendData); | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID) | ||||
|         { | ||||
|             List<GroupRolesData> roles = new List<GroupRolesData>(); | ||||
| 
 | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["GroupID"] = GroupID.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             Dictionary<string, object> ret = MakeRequest("GETGROUPROLES", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return roles; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return roles; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString() == "NULL") | ||||
|                 return roles; | ||||
| 
 | ||||
|             foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values) | ||||
|             { | ||||
|                 GroupRolesData m = GroupsDataUtils.GroupRolesData((Dictionary<string, object>)v); | ||||
|                 roles.Add(m); | ||||
|             } | ||||
| 
 | ||||
|             return roles; | ||||
|         } | ||||
| 
 | ||||
|         public List<ExtendedGroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID) | ||||
|         { | ||||
|             List<ExtendedGroupRoleMembersData> rmembers = new List<ExtendedGroupRoleMembersData>(); | ||||
| 
 | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["GroupID"] = GroupID.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             Dictionary<string, object> ret = MakeRequest("GETROLEMEMBERS", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return rmembers; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return rmembers; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString() == "NULL") | ||||
|                 return rmembers; | ||||
| 
 | ||||
|             foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values) | ||||
|             { | ||||
|                 ExtendedGroupRoleMembersData m = GroupsDataUtils.GroupRoleMembersData((Dictionary<string, object>)v); | ||||
|                 rmembers.Add(m); | ||||
|             } | ||||
| 
 | ||||
|             return rmembers; | ||||
|         } | ||||
| 
 | ||||
|         public bool AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) | ||||
|         { | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["AgentID"] = AgentID.ToString(); | ||||
|             sendData["GroupID"] = GroupID.ToString(); | ||||
|             sendData["RoleID"] = RoleID.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             sendData["OP"] = "ADD"; | ||||
| 
 | ||||
|             Dictionary<string, object> ret = MakeRequest("AGENTROLE", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString().ToLower() != "true") | ||||
|                 return false; | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         public bool RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) | ||||
|         { | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["AgentID"] = AgentID.ToString(); | ||||
|             sendData["GroupID"] = GroupID.ToString(); | ||||
|             sendData["RoleID"] = RoleID.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             sendData["OP"] = "DELETE"; | ||||
| 
 | ||||
|             Dictionary<string, object> ret = MakeRequest("AGENTROLE", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString().ToLower() != "true") | ||||
|                 return false; | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID) | ||||
|         { | ||||
|             List<GroupRolesData> roles = new List<GroupRolesData>(); | ||||
| 
 | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["AgentID"] = AgentID.ToString(); | ||||
|             sendData["GroupID"] = GroupID.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             Dictionary<string, object> ret = MakeRequest("GETAGENTROLES", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return roles; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return roles; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString() == "NULL") | ||||
|                 return roles; | ||||
| 
 | ||||
|             foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values) | ||||
|             { | ||||
|                 GroupRolesData m = GroupsDataUtils.GroupRolesData((Dictionary<string, object>)v); | ||||
|                 roles.Add(m); | ||||
|             } | ||||
| 
 | ||||
|             return roles; | ||||
|         } | ||||
| 
 | ||||
|         public GroupMembershipData SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID) | ||||
|         { | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["AgentID"] = AgentID.ToString(); | ||||
|             sendData["GroupID"] = GroupID.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             sendData["OP"] = "GROUP"; | ||||
| 
 | ||||
|             Dictionary<string, object> ret = MakeRequest("SETACTIVE", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return null; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return null; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString() == "NULL") | ||||
|                 return null; | ||||
| 
 | ||||
|             return GroupsDataUtils.GroupMembershipData((Dictionary<string, object>)ret["RESULT"]); | ||||
|         } | ||||
| 
 | ||||
|         public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) | ||||
|         { | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["AgentID"] = AgentID.ToString(); | ||||
|             sendData["GroupID"] = GroupID.ToString(); | ||||
|             sendData["RoleID"] = RoleID.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             sendData["OP"] = "ROLE"; | ||||
| 
 | ||||
|             MakeRequest("SETACTIVE", sendData); | ||||
|         } | ||||
| 
 | ||||
|         public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile) | ||||
|         { | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["AgentID"] = AgentID.ToString(); | ||||
|             sendData["GroupID"] = GroupID.ToString(); | ||||
|             sendData["AcceptNotices"] = AcceptNotices.ToString(); | ||||
|             sendData["ListInProfile"] = ListInProfile.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             MakeRequest("UPDATEMEMBERSHIP", sendData); | ||||
|         } | ||||
| 
 | ||||
|         public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID) | ||||
|         { | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["InviteID"] = inviteID.ToString(); | ||||
|             sendData["GroupID"] = groupID.ToString(); | ||||
|             sendData["RoleID"] = roleID.ToString(); | ||||
|             sendData["AgentID"] = agentID.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             sendData["OP"] = "ADD"; | ||||
| 
 | ||||
|             Dictionary<string, object> ret = MakeRequest("INVITE", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString().ToLower() != "true") // it may return "NULL" | ||||
|                 return false; | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID) | ||||
|         { | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["InviteID"] = inviteID.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             sendData["OP"] = "GET"; | ||||
| 
 | ||||
|             Dictionary<string, object> ret = MakeRequest("INVITE", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return null; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return null; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString() == "NULL") | ||||
|                 return null; | ||||
| 
 | ||||
|             return GroupsDataUtils.GroupInviteInfo((Dictionary<string, object>)ret["RESULT"]); | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID) | ||||
|         { | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["InviteID"] = inviteID.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             sendData["OP"] = "DELETE"; | ||||
| 
 | ||||
|             MakeRequest("INVITE", sendData); | ||||
|         } | ||||
| 
 | ||||
|         public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, | ||||
|             bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID) | ||||
|         { | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["GroupID"] = groupID.ToString(); | ||||
|             sendData["NoticeID"] = noticeID.ToString(); | ||||
|             sendData["FromName"] = GroupsDataUtils.Sanitize(fromName); | ||||
|             sendData["Subject"] = GroupsDataUtils.Sanitize(subject); | ||||
|             sendData["Message"] = GroupsDataUtils.Sanitize(message); | ||||
|             sendData["HasAttachment"] = hasAttachment.ToString(); | ||||
|             if (hasAttachment) | ||||
|             { | ||||
|                 sendData["AttachmentType"] = attType.ToString(); | ||||
|                 sendData["AttachmentName"] = attName.ToString(); | ||||
|                 sendData["AttachmentItemID"] = attItemID.ToString(); | ||||
|                 sendData["AttachmentOwnerID"] = attOwnerID; | ||||
|             } | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
| 
 | ||||
|             Dictionary<string, object> ret = MakeRequest("ADDNOTICE", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString().ToLower() != "true") | ||||
|                 return false; | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID) | ||||
|         { | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["NoticeID"] = noticeID.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
| 
 | ||||
|             Dictionary<string, object> ret = MakeRequest("GETNOTICES", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return null; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return null; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString() == "NULL") | ||||
|                 return null; | ||||
| 
 | ||||
|             return GroupsDataUtils.GroupNoticeInfo((Dictionary<string, object>)ret["RESULT"]); | ||||
|         } | ||||
| 
 | ||||
|         public List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID) | ||||
|         { | ||||
|             List<ExtendedGroupNoticeData> notices = new List<ExtendedGroupNoticeData>(); | ||||
| 
 | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["GroupID"] = GroupID.ToString(); | ||||
|             sendData["RequestingAgentID"] = RequestingAgentID; | ||||
|             Dictionary<string, object> ret = MakeRequest("GETNOTICES", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return notices; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return notices; | ||||
| 
 | ||||
|             if (ret["RESULT"].ToString() == "NULL") | ||||
|                 return notices; | ||||
| 
 | ||||
|             foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values) | ||||
|             { | ||||
|                 ExtendedGroupNoticeData m = GroupsDataUtils.GroupNoticeData((Dictionary<string, object>)v); | ||||
|                 notices.Add(m); | ||||
|             } | ||||
| 
 | ||||
|             return notices; | ||||
|         } | ||||
| 
 | ||||
|         #region Make Request | ||||
| 
 | ||||
|         private Dictionary<string, object> MakeRequest(string method, Dictionary<string, object> sendData) | ||||
|         { | ||||
|             sendData["METHOD"] = method; | ||||
| 
 | ||||
|             string reply = string.Empty; | ||||
|             lock (m_Lock) | ||||
|                 reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||||
|                          m_ServerURI + "groups", | ||||
|                          ServerUtils.BuildQueryString(sendData), | ||||
|                          m_Auth); | ||||
| 
 | ||||
|             if (reply == string.Empty) | ||||
|                 return null; | ||||
| 
 | ||||
|             Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse( | ||||
|                     reply); | ||||
| 
 | ||||
|             return replyData; | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
|     } | ||||
| } | ||||
|  | @ -1,408 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Reflection; | ||||
| using System.Threading; | ||||
| using System.Text; | ||||
| 
 | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Region.Framework.Scenes; | ||||
| using OpenSim.Region.Framework.Interfaces; | ||||
| using OpenSim.Server.Base; | ||||
| using OpenSim.Services.Interfaces; | ||||
| 
 | ||||
| using OpenMetaverse; | ||||
| using Mono.Addins; | ||||
| using log4net; | ||||
| using Nini.Config; | ||||
| 
 | ||||
| namespace OpenSim.Groups | ||||
| { | ||||
|     [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsServiceRemoteConnectorModule")] | ||||
|     public class GroupsServiceRemoteConnectorModule : ISharedRegionModule, IGroupsServicesConnector | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private bool m_Enabled = false; | ||||
|         private GroupsServiceRemoteConnector m_GroupsService; | ||||
|         private IUserManagement m_UserManagement; | ||||
|         private List<Scene> m_Scenes; | ||||
| 
 | ||||
|         private RemoteConnectorCacheWrapper m_CacheWrapper; | ||||
| 
 | ||||
|         #region constructors | ||||
|         public GroupsServiceRemoteConnectorModule() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         public GroupsServiceRemoteConnectorModule(IConfigSource config, IUserManagement uman) | ||||
|         { | ||||
|             Init(config); | ||||
|             m_UserManagement = uman; | ||||
|             m_CacheWrapper = new RemoteConnectorCacheWrapper(m_UserManagement); | ||||
| 
 | ||||
|         } | ||||
|         #endregion | ||||
| 
 | ||||
|         private void Init(IConfigSource config) | ||||
|         { | ||||
|             m_GroupsService = new GroupsServiceRemoteConnector(config); | ||||
|             m_Scenes = new List<Scene>(); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         #region ISharedRegionModule | ||||
| 
 | ||||
|         public void Initialise(IConfigSource config) | ||||
|         { | ||||
|             IConfig groupsConfig = config.Configs["Groups"]; | ||||
|             if (groupsConfig == null) | ||||
|                 return; | ||||
| 
 | ||||
|             if ((groupsConfig.GetBoolean("Enabled", false) == false) | ||||
|                     || (groupsConfig.GetString("ServicesConnectorModule", string.Empty) != Name)) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             Init(config); | ||||
| 
 | ||||
|             m_Enabled = true; | ||||
|             m_log.DebugFormat("[Groups.RemoteConnector]: Initializing {0}", this.Name); | ||||
|         } | ||||
| 
 | ||||
|         public string Name | ||||
|         { | ||||
|             get { return "Groups Remote Service Connector"; } | ||||
|         } | ||||
| 
 | ||||
|         public Type ReplaceableInterface | ||||
|         { | ||||
|             get { return null; } | ||||
|         } | ||||
| 
 | ||||
|         public void AddRegion(Scene scene) | ||||
|         { | ||||
|             if (!m_Enabled) | ||||
|                 return; | ||||
| 
 | ||||
|             m_log.DebugFormat("[Groups.RemoteConnector]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName); | ||||
|             scene.RegisterModuleInterface<IGroupsServicesConnector>(this); | ||||
|             m_Scenes.Add(scene); | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveRegion(Scene scene) | ||||
|         { | ||||
|             if (!m_Enabled) | ||||
|                 return; | ||||
| 
 | ||||
|             scene.UnregisterModuleInterface<IGroupsServicesConnector>(this); | ||||
|             m_Scenes.Remove(scene); | ||||
|         } | ||||
| 
 | ||||
|         public void RegionLoaded(Scene scene) | ||||
|         { | ||||
|             if (!m_Enabled) | ||||
|                 return; | ||||
| 
 | ||||
|             if (m_UserManagement == null) | ||||
|             { | ||||
|                 m_UserManagement = scene.RequestModuleInterface<IUserManagement>(); | ||||
|                 m_CacheWrapper = new RemoteConnectorCacheWrapper(m_UserManagement); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void PostInitialise() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         public void Close() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
|         #region IGroupsServicesConnector | ||||
| 
 | ||||
|         public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, | ||||
|             bool allowPublish, bool maturePublish, UUID founderID, out string reason) | ||||
|         { | ||||
|             m_log.DebugFormat("[Groups.RemoteConnector]: Creating group {0}", name); | ||||
|             string r = string.Empty; | ||||
| 
 | ||||
|             UUID groupID = m_CacheWrapper.CreateGroup(RequestingAgentID, delegate | ||||
|             { | ||||
|                 return m_GroupsService.CreateGroup(RequestingAgentID.ToString(), name, charter, showInList, insigniaID, | ||||
|                     membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out r); | ||||
|             }); | ||||
| 
 | ||||
|             reason = r; | ||||
|             return groupID; | ||||
|         } | ||||
| 
 | ||||
|         public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, | ||||
|             bool openEnrollment, bool allowPublish, bool maturePublish, out string reason) | ||||
|         { | ||||
|             string r = string.Empty; | ||||
| 
 | ||||
|             bool success = m_CacheWrapper.UpdateGroup(groupID, delegate | ||||
|             { | ||||
|                 return m_GroupsService.UpdateGroup(RequestingAgentID, groupID, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish); | ||||
|             }); | ||||
| 
 | ||||
|             reason = r; | ||||
|             return success; | ||||
|         } | ||||
| 
 | ||||
|         public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName) | ||||
|         { | ||||
|             if (GroupID == UUID.Zero && (GroupName == null || GroupName != null && GroupName == string.Empty)) | ||||
|                 return null; | ||||
| 
 | ||||
|             return m_CacheWrapper.GetGroupRecord(RequestingAgentID,GroupID,GroupName, delegate | ||||
|             { | ||||
|                 return m_GroupsService.GetGroupRecord(RequestingAgentID, GroupID, GroupName); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         public List<DirGroupsReplyData> FindGroups(string RequestingAgentIDstr, string search) | ||||
|         { | ||||
|             // TODO! | ||||
|             return m_GroupsService.FindGroups(RequestingAgentIDstr, search); | ||||
|         } | ||||
| 
 | ||||
|         public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason) | ||||
|         { | ||||
|             string agentFullID = AgentID; | ||||
|             m_log.DebugFormat("[Groups.RemoteConnector]: Add agent {0} to group {1}", agentFullID, GroupID); | ||||
|             string r = string.Empty; | ||||
| 
 | ||||
|             bool success = m_CacheWrapper.AddAgentToGroup(RequestingAgentID, AgentID, GroupID, delegate | ||||
|             { | ||||
|                 return m_GroupsService.AddAgentToGroup(RequestingAgentID, agentFullID, GroupID, RoleID, token, out r); | ||||
|             }); | ||||
| 
 | ||||
|             reason = r; | ||||
|             return success; | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID) | ||||
|         { | ||||
|             m_CacheWrapper.RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID, delegate | ||||
|             { | ||||
|                 m_GroupsService.RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID); | ||||
|             }); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         public void SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID) | ||||
|         { | ||||
|             m_CacheWrapper.SetAgentActiveGroup(AgentID, delegate | ||||
|             { | ||||
|                 return m_GroupsService.SetAgentActiveGroup(RequestingAgentID, AgentID, GroupID); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         public ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID) | ||||
|         { | ||||
|             return m_CacheWrapper.GetAgentActiveMembership(AgentID, delegate | ||||
|             { | ||||
|                 return m_GroupsService.GetMembership(RequestingAgentID, AgentID, UUID.Zero); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         public ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID) | ||||
|         { | ||||
|             return m_CacheWrapper.GetAgentGroupMembership(AgentID, GroupID, delegate | ||||
|             { | ||||
|                 return m_GroupsService.GetMembership(RequestingAgentID, AgentID, GroupID); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupMembershipData> GetAgentGroupMemberships(string RequestingAgentID, string AgentID) | ||||
|         { | ||||
|             return m_CacheWrapper.GetAgentGroupMemberships(AgentID, delegate | ||||
|             { | ||||
|                 return m_GroupsService.GetMemberships(RequestingAgentID, AgentID); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         public List<GroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID) | ||||
|         { | ||||
|             return m_CacheWrapper.GetGroupMembers(RequestingAgentID, GroupID, delegate | ||||
|             { | ||||
|                 return m_GroupsService.GetGroupMembers(RequestingAgentID, GroupID); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason) | ||||
|         { | ||||
|             string r = string.Empty; | ||||
|             bool success = m_CacheWrapper.AddGroupRole(groupID, roleID, description, name, powers, title, delegate | ||||
|             { | ||||
|                 return m_GroupsService.AddGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers, out r); | ||||
|             }); | ||||
| 
 | ||||
|             reason = r; | ||||
|             return success; | ||||
|         } | ||||
| 
 | ||||
|         public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers) | ||||
|         { | ||||
|             return m_CacheWrapper.UpdateGroupRole(groupID, roleID, name, description, title, powers, delegate | ||||
|             { | ||||
|                 return m_GroupsService.UpdateGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID) | ||||
|         { | ||||
|             m_CacheWrapper.RemoveGroupRole(RequestingAgentID, groupID, roleID, delegate | ||||
|             { | ||||
|                 m_GroupsService.RemoveGroupRole(RequestingAgentID, groupID, roleID); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID) | ||||
|         { | ||||
|             return m_CacheWrapper.GetGroupRoles(RequestingAgentID, GroupID, delegate | ||||
|             { | ||||
|                 return m_GroupsService.GetGroupRoles(RequestingAgentID, GroupID); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID) | ||||
|         { | ||||
|             return m_CacheWrapper.GetGroupRoleMembers(RequestingAgentID, GroupID, delegate | ||||
|             { | ||||
|                 return m_GroupsService.GetGroupRoleMembers(RequestingAgentID, GroupID); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         public void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) | ||||
|         { | ||||
|             m_CacheWrapper.AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID, delegate | ||||
|             { | ||||
|                 return m_GroupsService.AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) | ||||
|         { | ||||
|             m_CacheWrapper.RemoveAgentFromGroupRole(RequestingAgentID, AgentID, GroupID, RoleID, delegate | ||||
|             { | ||||
|                 return m_GroupsService.RemoveAgentFromGroupRole(RequestingAgentID, AgentID, GroupID, RoleID); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID) | ||||
|         { | ||||
|             return m_CacheWrapper.GetAgentGroupRoles(RequestingAgentID, AgentID, GroupID, delegate | ||||
|             { | ||||
|                 return m_GroupsService.GetAgentGroupRoles(RequestingAgentID, AgentID, GroupID); ; | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) | ||||
|         { | ||||
|             m_CacheWrapper.SetAgentActiveGroupRole(AgentID, GroupID, delegate | ||||
|             { | ||||
|                 m_GroupsService.SetAgentActiveGroupRole(RequestingAgentID, AgentID, GroupID, RoleID); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile) | ||||
|         { | ||||
|             m_CacheWrapper.UpdateMembership(AgentID, GroupID, AcceptNotices, ListInProfile, delegate | ||||
|             { | ||||
|                 m_GroupsService.UpdateMembership(RequestingAgentID, AgentID, GroupID, AcceptNotices, ListInProfile); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID) | ||||
|         { | ||||
|             return m_GroupsService.AddAgentToGroupInvite(RequestingAgentID, inviteID, groupID, roleID, agentID); | ||||
|         } | ||||
| 
 | ||||
|         public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID) | ||||
|         { | ||||
|             return m_GroupsService.GetAgentToGroupInvite(RequestingAgentID, inviteID); | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID) | ||||
|         { | ||||
|             m_GroupsService.RemoveAgentToGroupInvite(RequestingAgentID, inviteID); | ||||
|         } | ||||
| 
 | ||||
|         public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, | ||||
|             bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID) | ||||
|         { | ||||
|             GroupNoticeInfo notice = new GroupNoticeInfo(); | ||||
|             notice.GroupID = groupID; | ||||
|             notice.Message = message; | ||||
|             notice.noticeData = new ExtendedGroupNoticeData(); | ||||
|             notice.noticeData.AttachmentItemID = attItemID; | ||||
|             notice.noticeData.AttachmentName = attName; | ||||
|             notice.noticeData.AttachmentOwnerID = attOwnerID.ToString(); | ||||
|             notice.noticeData.AttachmentType = attType; | ||||
|             notice.noticeData.FromName = fromName; | ||||
|             notice.noticeData.HasAttachment = hasAttachment; | ||||
|             notice.noticeData.NoticeID = noticeID; | ||||
|             notice.noticeData.Subject = subject; | ||||
|             notice.noticeData.Timestamp = (uint)Util.UnixTimeSinceEpoch(); | ||||
| 
 | ||||
|             return m_CacheWrapper.AddGroupNotice(groupID, noticeID, notice, delegate | ||||
|             { | ||||
|                 return m_GroupsService.AddGroupNotice(RequestingAgentID, groupID, noticeID, fromName, subject, message, | ||||
|                             hasAttachment, attType, attName, attItemID, attOwnerID); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID) | ||||
|         { | ||||
|             return m_CacheWrapper.GetGroupNotice(noticeID, delegate | ||||
|             { | ||||
|                 return m_GroupsService.GetGroupNotice(RequestingAgentID, noticeID); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         public List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID) | ||||
|         { | ||||
|             return m_CacheWrapper.GetGroupNotices(GroupID, delegate | ||||
|             { | ||||
|                 return m_GroupsService.GetGroupNotices(RequestingAgentID, GroupID); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -1,817 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Reflection; | ||||
| using System.Text; | ||||
| using System.Xml; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using Nini.Config; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Server.Base; | ||||
| using OpenSim.Services.Interfaces; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Framework.ServiceAuth; | ||||
| using OpenSim.Server.Handlers.Base; | ||||
| using log4net; | ||||
| using OpenMetaverse; | ||||
| 
 | ||||
| namespace OpenSim.Groups | ||||
| { | ||||
|     public class GroupsServiceRobustConnector : ServiceConnector | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private GroupsService m_GroupsService; | ||||
|         private string m_ConfigName = "Groups"; | ||||
| 
 | ||||
|         public GroupsServiceRobustConnector(IConfigSource config, IHttpServer server, string configName) : | ||||
|             base(config, server, configName) | ||||
|         { | ||||
|             string key = string.Empty; | ||||
|             if (configName != String.Empty) | ||||
|                 m_ConfigName = configName; | ||||
| 
 | ||||
|             m_log.DebugFormat("[Groups.RobustConnector]: Starting with config name {0}", m_ConfigName); | ||||
| 
 | ||||
|             IConfig groupsConfig = config.Configs[m_ConfigName]; | ||||
|             if (groupsConfig != null) | ||||
|             { | ||||
|                 key = groupsConfig.GetString("SecretKey", string.Empty); | ||||
|                 m_log.DebugFormat("[Groups.RobustConnector]: Starting with secret key {0}", key); | ||||
|             } | ||||
| //            else | ||||
| //                m_log.DebugFormat("[Groups.RobustConnector]: Unable to find {0} section in configuration", m_ConfigName); | ||||
| 
 | ||||
|             m_GroupsService = new GroupsService(config); | ||||
| 
 | ||||
|             IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName); | ||||
| 
 | ||||
|             server.AddStreamHandler(new GroupsServicePostHandler(m_GroupsService, auth)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public class GroupsServicePostHandler : BaseStreamHandler | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private GroupsService m_GroupsService; | ||||
| 
 | ||||
|         public GroupsServicePostHandler(GroupsService service, IServiceAuth auth) : | ||||
|             base("POST", "/groups", auth) | ||||
|         { | ||||
|             m_GroupsService = service; | ||||
|         } | ||||
| 
 | ||||
|         protected override byte[] ProcessRequest(string path, Stream requestData, | ||||
|                 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||||
|         { | ||||
|             string body; | ||||
|             using(StreamReader sr = new StreamReader(requestData)) | ||||
|                 body = sr.ReadToEnd(); | ||||
| 
 | ||||
|             body = body.Trim(); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: query String: {0}", body); | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 Dictionary<string, object> request = | ||||
|                         ServerUtils.ParseQueryString(body); | ||||
| 
 | ||||
|                 if (!request.ContainsKey("METHOD")) | ||||
|                     return FailureResult(); | ||||
| 
 | ||||
|                 string method = request["METHOD"].ToString(); | ||||
|                 request.Remove("METHOD"); | ||||
| 
 | ||||
| //                m_log.DebugFormat("[Groups.Handler]: {0}", method); | ||||
|                 switch (method) | ||||
|                 { | ||||
|                     case "PUTGROUP": | ||||
|                         return HandleAddOrUpdateGroup(request); | ||||
|                     case "GETGROUP": | ||||
|                         return HandleGetGroup(request); | ||||
|                     case "ADDAGENTTOGROUP": | ||||
|                         return HandleAddAgentToGroup(request); | ||||
|                     case "REMOVEAGENTFROMGROUP": | ||||
|                         return HandleRemoveAgentFromGroup(request); | ||||
|                     case "GETMEMBERSHIP": | ||||
|                         return HandleGetMembership(request); | ||||
|                     case "GETGROUPMEMBERS": | ||||
|                         return HandleGetGroupMembers(request); | ||||
|                     case "PUTROLE": | ||||
|                         return HandlePutRole(request); | ||||
|                     case "REMOVEROLE": | ||||
|                         return HandleRemoveRole(request); | ||||
|                     case "GETGROUPROLES": | ||||
|                         return HandleGetGroupRoles(request); | ||||
|                     case "GETROLEMEMBERS": | ||||
|                         return HandleGetRoleMembers(request); | ||||
|                     case "AGENTROLE": | ||||
|                         return HandleAgentRole(request); | ||||
|                     case "GETAGENTROLES": | ||||
|                         return HandleGetAgentRoles(request); | ||||
|                     case "SETACTIVE": | ||||
|                         return HandleSetActive(request); | ||||
|                     case "UPDATEMEMBERSHIP": | ||||
|                         return HandleUpdateMembership(request); | ||||
|                     case "INVITE": | ||||
|                         return HandleInvite(request); | ||||
|                     case "ADDNOTICE": | ||||
|                         return HandleAddNotice(request); | ||||
|                     case "GETNOTICES": | ||||
|                         return HandleGetNotices(request); | ||||
|                     case "FINDGROUPS": | ||||
|                         return HandleFindGroups(request); | ||||
|                 } | ||||
|                 m_log.DebugFormat("[GROUPS HANDLER]: unknown method request: {0}", method); | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 m_log.Error(string.Format("[GROUPS HANDLER]: Exception {0} ", e.Message), e); | ||||
|             } | ||||
| 
 | ||||
|             return FailureResult(); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleAddOrUpdateGroup(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             ExtendedGroupRecord grec = GroupsDataUtils.GroupRecord(request); | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("OP")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
| 
 | ||||
|             else | ||||
|             { | ||||
|                 string RequestingAgentID = request["RequestingAgentID"].ToString(); | ||||
|                 string reason = string.Empty; | ||||
|                 string op = request["OP"].ToString(); | ||||
|                 if (op == "ADD") | ||||
|                 { | ||||
|                     grec.GroupID = m_GroupsService.CreateGroup(RequestingAgentID, grec.GroupName, grec.Charter, grec.ShowInList, grec.GroupPicture, grec.MembershipFee, | ||||
|                         grec.OpenEnrollment, grec.AllowPublish, grec.MaturePublish, grec.FounderID, out reason); | ||||
| 
 | ||||
|                 } | ||||
|                 else if (op == "UPDATE") | ||||
|                 { | ||||
|                     m_GroupsService.UpdateGroup(RequestingAgentID, grec.GroupID, grec.Charter, grec.ShowInList, grec.GroupPicture, grec.MembershipFee, | ||||
|                         grec.OpenEnrollment, grec.AllowPublish, grec.MaturePublish); | ||||
| 
 | ||||
|                 } | ||||
| 
 | ||||
|                 if (grec.GroupID != UUID.Zero) | ||||
|                 { | ||||
|                     grec = m_GroupsService.GetGroupRecord(RequestingAgentID, grec.GroupID); | ||||
|                     if (grec == null) | ||||
|                         NullResult(result, "Internal Error"); | ||||
|                     else | ||||
|                         result["RESULT"] = GroupsDataUtils.GroupRecord(grec); | ||||
|                 } | ||||
|                 else | ||||
|                     NullResult(result, reason); | ||||
|             } | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleGetGroup(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
|             else | ||||
|             { | ||||
|                 string RequestingAgentID = request["RequestingAgentID"].ToString(); | ||||
|                 ExtendedGroupRecord grec = null; | ||||
|                 if (request.ContainsKey("GroupID")) | ||||
|                 { | ||||
|                     UUID groupID = new UUID(request["GroupID"].ToString()); | ||||
|                     grec = m_GroupsService.GetGroupRecord(RequestingAgentID, groupID); | ||||
|                 } | ||||
|                 else if (request.ContainsKey("Name")) | ||||
|                 { | ||||
|                     string name = request["Name"].ToString(); | ||||
|                     grec = m_GroupsService.GetGroupRecord(RequestingAgentID, name); | ||||
|                 } | ||||
| 
 | ||||
|                 if (grec == null) | ||||
|                     NullResult(result, "Group not found"); | ||||
|                 else | ||||
|                     result["RESULT"] = GroupsDataUtils.GroupRecord(grec); | ||||
|             } | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleAddAgentToGroup(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AgentID") || | ||||
|                 !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
|             else | ||||
|             { | ||||
|                 UUID groupID = new UUID(request["GroupID"].ToString()); | ||||
|                 UUID roleID = new UUID(request["RoleID"].ToString()); | ||||
|                 string agentID = request["AgentID"].ToString(); | ||||
|                 string requestingAgentID = request["RequestingAgentID"].ToString(); | ||||
|                 string token = string.Empty; | ||||
|                 string reason = string.Empty; | ||||
| 
 | ||||
|                 if (request.ContainsKey("AccessToken")) | ||||
|                     token = request["AccessToken"].ToString(); | ||||
| 
 | ||||
|                 if (!m_GroupsService.AddAgentToGroup(requestingAgentID, agentID, groupID, roleID, token, out reason)) | ||||
|                     NullResult(result, reason); | ||||
|                 else | ||||
|                 { | ||||
|                     GroupMembershipData membership = m_GroupsService.GetAgentGroupMembership(requestingAgentID, agentID, groupID); | ||||
|                     if (membership == null) | ||||
|                         NullResult(result, "Internal error"); | ||||
|                     else | ||||
|                         result["RESULT"] = GroupsDataUtils.GroupMembershipData((ExtendedGroupMembershipData)membership); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleRemoveAgentFromGroup(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AgentID") || !request.ContainsKey("GroupID")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
|             else | ||||
|             { | ||||
|                 UUID groupID = new UUID(request["GroupID"].ToString()); | ||||
|                 string agentID = request["AgentID"].ToString(); | ||||
|                 string requestingAgentID = request["RequestingAgentID"].ToString(); | ||||
| 
 | ||||
|                 if (!m_GroupsService.RemoveAgentFromGroup(requestingAgentID, agentID, groupID)) | ||||
|                     NullResult(result, string.Format("Insufficient permissions. {0}", agentID)); | ||||
|                 else | ||||
|                     result["RESULT"] = "true"; | ||||
|             } | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result)); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleGetMembership(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AgentID")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
|             else | ||||
|             { | ||||
|                 string agentID = request["AgentID"].ToString(); | ||||
|                 UUID groupID = UUID.Zero; | ||||
|                 if (request.ContainsKey("GroupID")) | ||||
|                     groupID = new UUID(request["GroupID"].ToString()); | ||||
|                 string requestingAgentID = request["RequestingAgentID"].ToString(); | ||||
|                 bool all = request.ContainsKey("ALL"); | ||||
| 
 | ||||
|                 if (!all) | ||||
|                 { | ||||
|                     ExtendedGroupMembershipData membership = null; | ||||
|                     if (groupID == UUID.Zero) | ||||
|                     { | ||||
|                         membership = m_GroupsService.GetAgentActiveMembership(requestingAgentID, agentID); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         membership = m_GroupsService.GetAgentGroupMembership(requestingAgentID, agentID, groupID); | ||||
|                     } | ||||
| 
 | ||||
|                     if (membership == null) | ||||
|                         NullResult(result, "No such membership"); | ||||
|                     else | ||||
|                         result["RESULT"] = GroupsDataUtils.GroupMembershipData(membership); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     List<GroupMembershipData> memberships = m_GroupsService.GetAgentGroupMemberships(requestingAgentID, agentID); | ||||
|                     if (memberships == null || (memberships != null && memberships.Count == 0)) | ||||
|                     { | ||||
|                         NullResult(result, "No memberships"); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         Dictionary<string, object> dict = new Dictionary<string, object>(); | ||||
|                         int i = 0; | ||||
|                         foreach (GroupMembershipData m in memberships) | ||||
|                             dict["m-" + i++] = GroupsDataUtils.GroupMembershipData((ExtendedGroupMembershipData)m); | ||||
| 
 | ||||
|                         result["RESULT"] = dict; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleGetGroupMembers(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
|             else | ||||
|             { | ||||
|                 UUID groupID = new UUID(request["GroupID"].ToString()); | ||||
|                 string requestingAgentID = request["RequestingAgentID"].ToString(); | ||||
| 
 | ||||
|                 List<ExtendedGroupMembersData> members = m_GroupsService.GetGroupMembers(requestingAgentID, groupID); | ||||
|                 if (members == null || (members != null && members.Count == 0)) | ||||
|                 { | ||||
|                     NullResult(result, "No members"); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     Dictionary<string, object> dict = new Dictionary<string, object>(); | ||||
|                     int i = 0; | ||||
|                     foreach (ExtendedGroupMembersData m in members) | ||||
|                     { | ||||
|                         dict["m-" + i++] = GroupsDataUtils.GroupMembersData(m); | ||||
|                     } | ||||
| 
 | ||||
|                     result["RESULT"] = dict; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandlePutRole(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID") || | ||||
|                 !request.ContainsKey("Name") || !request.ContainsKey("Description") || !request.ContainsKey("Title") || | ||||
|                 !request.ContainsKey("Powers") || !request.ContainsKey("OP")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
| 
 | ||||
|             else | ||||
|             { | ||||
|                 string op = request["OP"].ToString(); | ||||
|                 string reason = string.Empty; | ||||
| 
 | ||||
|                 bool success = false; | ||||
|                 if (op == "ADD") | ||||
|                     success = m_GroupsService.AddGroupRole(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()), | ||||
|                         new UUID(request["RoleID"].ToString()), request["Name"].ToString(), request["Description"].ToString(), | ||||
|                         request["Title"].ToString(), UInt64.Parse(request["Powers"].ToString()), out reason); | ||||
| 
 | ||||
|                 else if (op == "UPDATE") | ||||
|                     success = m_GroupsService.UpdateGroupRole(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()), | ||||
|                         new UUID(request["RoleID"].ToString()), request["Name"].ToString(), request["Description"].ToString(), | ||||
|                         request["Title"].ToString(), UInt64.Parse(request["Powers"].ToString())); | ||||
| 
 | ||||
|                 result["RESULT"] = success.ToString(); | ||||
|             } | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleRemoveRole(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
| 
 | ||||
|             else | ||||
|             { | ||||
|                 m_GroupsService.RemoveGroupRole(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()), | ||||
|                     new UUID(request["RoleID"].ToString())); | ||||
|                 result["RESULT"] = "true"; | ||||
|             } | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result)); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleGetGroupRoles(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
|             else | ||||
|             { | ||||
|                 UUID groupID = new UUID(request["GroupID"].ToString()); | ||||
|                 string requestingAgentID = request["RequestingAgentID"].ToString(); | ||||
| 
 | ||||
|                 List<GroupRolesData> roles = m_GroupsService.GetGroupRoles(requestingAgentID, groupID); | ||||
|                 if (roles == null || (roles != null && roles.Count == 0)) | ||||
|                 { | ||||
|                     NullResult(result, "No members"); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     Dictionary<string, object> dict = new Dictionary<string, object>(); | ||||
|                     int i = 0; | ||||
|                     foreach (GroupRolesData r in roles) | ||||
|                         dict["r-" + i++] = GroupsDataUtils.GroupRolesData(r); | ||||
| 
 | ||||
|                     result["RESULT"] = dict; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleGetRoleMembers(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
|             else | ||||
|             { | ||||
|                 UUID groupID = new UUID(request["GroupID"].ToString()); | ||||
|                 string requestingAgentID = request["RequestingAgentID"].ToString(); | ||||
| 
 | ||||
|                 List<ExtendedGroupRoleMembersData> rmembers = m_GroupsService.GetGroupRoleMembers(requestingAgentID, groupID); | ||||
|                 if (rmembers == null || (rmembers != null && rmembers.Count == 0)) | ||||
|                 { | ||||
|                     NullResult(result, "No members"); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     Dictionary<string, object> dict = new Dictionary<string, object>(); | ||||
|                     int i = 0; | ||||
|                     foreach (ExtendedGroupRoleMembersData rm in rmembers) | ||||
|                         dict["rm-" + i++] = GroupsDataUtils.GroupRoleMembersData(rm); | ||||
| 
 | ||||
|                     result["RESULT"] = dict; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleAgentRole(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID") || | ||||
|                 !request.ContainsKey("AgentID") || !request.ContainsKey("OP")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
| 
 | ||||
|             else | ||||
|             { | ||||
|                 string op = request["OP"].ToString(); | ||||
| 
 | ||||
|                 bool success = false; | ||||
|                 if (op == "ADD") | ||||
|                     success = m_GroupsService.AddAgentToGroupRole(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(), | ||||
|                         new UUID(request["GroupID"].ToString()), new UUID(request["RoleID"].ToString())); | ||||
| 
 | ||||
|                 else if (op == "DELETE") | ||||
|                     success = m_GroupsService.RemoveAgentFromGroupRole(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(), | ||||
|                         new UUID(request["GroupID"].ToString()), new UUID(request["RoleID"].ToString())); | ||||
| 
 | ||||
|                 result["RESULT"] = success.ToString(); | ||||
|             } | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleGetAgentRoles(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("AgentID")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
|             else | ||||
|             { | ||||
|                 UUID groupID = new UUID(request["GroupID"].ToString()); | ||||
|                 string agentID = request["AgentID"].ToString(); | ||||
|                 string requestingAgentID = request["RequestingAgentID"].ToString(); | ||||
| 
 | ||||
|                 List<GroupRolesData> roles = m_GroupsService.GetAgentGroupRoles(requestingAgentID, agentID, groupID); | ||||
|                 if (roles == null || (roles != null && roles.Count == 0)) | ||||
|                 { | ||||
|                     NullResult(result, "No members"); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     Dictionary<string, object> dict = new Dictionary<string, object>(); | ||||
|                     int i = 0; | ||||
|                     foreach (GroupRolesData r in roles) | ||||
|                         dict["r-" + i++] = GroupsDataUtils.GroupRolesData(r); | ||||
| 
 | ||||
|                     result["RESULT"] = dict; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleSetActive(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || | ||||
|                 !request.ContainsKey("AgentID") || !request.ContainsKey("OP")) | ||||
|             { | ||||
|                 NullResult(result, "Bad network data"); | ||||
|                 string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
|                 return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 string op = request["OP"].ToString(); | ||||
| 
 | ||||
|                 if (op == "GROUP") | ||||
|                 { | ||||
|                     ExtendedGroupMembershipData group = m_GroupsService.SetAgentActiveGroup(request["RequestingAgentID"].ToString(), | ||||
|                         request["AgentID"].ToString(), new UUID(request["GroupID"].ToString())); | ||||
| 
 | ||||
|                     if (group == null) | ||||
|                         NullResult(result, "Internal error"); | ||||
|                     else | ||||
|                         result["RESULT"] = GroupsDataUtils.GroupMembershipData(group); | ||||
| 
 | ||||
|                     string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|                     //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|                     return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
| 
 | ||||
|                 } | ||||
|                 else if (op == "ROLE" && request.ContainsKey("RoleID")) | ||||
|                 { | ||||
|                     m_GroupsService.SetAgentActiveGroupRole(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(), | ||||
|                         new UUID(request["GroupID"].ToString()), new UUID(request["RoleID"].ToString())); | ||||
|                     result["RESULT"] = "true"; | ||||
|                 } | ||||
| 
 | ||||
|                 return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result)); | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleUpdateMembership(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AgentID") || !request.ContainsKey("GroupID") || | ||||
|                 !request.ContainsKey("AcceptNotices") || !request.ContainsKey("ListInProfile")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
| 
 | ||||
|             else | ||||
|             { | ||||
|                 m_GroupsService.UpdateMembership(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(), new UUID(request["GroupID"].ToString()), | ||||
|                     bool.Parse(request["AcceptNotices"].ToString()), bool.Parse(request["ListInProfile"].ToString())); | ||||
| 
 | ||||
|                 result["RESULT"] = "true"; | ||||
|             } | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result)); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleInvite(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("InviteID")) | ||||
|             { | ||||
|                 NullResult(result, "Bad network data"); | ||||
|                 string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
|                 return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 string op = request["OP"].ToString(); | ||||
| 
 | ||||
|                 if (op == "ADD" && request.ContainsKey("GroupID") && request.ContainsKey("RoleID") && request.ContainsKey("AgentID")) | ||||
|                 { | ||||
|                     bool success = m_GroupsService.AddAgentToGroupInvite(request["RequestingAgentID"].ToString(), | ||||
|                         new UUID(request["InviteID"].ToString()), new UUID(request["GroupID"].ToString()), | ||||
|                         new UUID(request["RoleID"].ToString()), request["AgentID"].ToString()); | ||||
| 
 | ||||
|                     result["RESULT"] = success.ToString(); | ||||
|                     return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result)); | ||||
| 
 | ||||
|                 } | ||||
|                 else if (op == "DELETE") | ||||
|                 { | ||||
|                     m_GroupsService.RemoveAgentToGroupInvite(request["RequestingAgentID"].ToString(), new UUID(request["InviteID"].ToString())); | ||||
|                     result["RESULT"] = "true"; | ||||
|                     return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result)); | ||||
|                 } | ||||
|                 else if (op == "GET") | ||||
|                 { | ||||
|                     GroupInviteInfo invite = m_GroupsService.GetAgentToGroupInvite(request["RequestingAgentID"].ToString(), | ||||
|                         new UUID(request["InviteID"].ToString())); | ||||
| 
 | ||||
|                     if (invite != null) | ||||
|                         result["RESULT"] = GroupsDataUtils.GroupInviteInfo(invite); | ||||
|                     else | ||||
|                         result["RESULT"] = "NULL"; | ||||
| 
 | ||||
|                     return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result)); | ||||
|                 } | ||||
| 
 | ||||
|                 NullResult(result, "Bad OP in request"); | ||||
|                 return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result)); | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleAddNotice(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("NoticeID") || | ||||
|                 !request.ContainsKey("FromName") || !request.ContainsKey("Subject") || !request.ContainsKey("Message") || | ||||
|                 !request.ContainsKey("HasAttachment")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
| 
 | ||||
|             else | ||||
|             { | ||||
| 
 | ||||
|                 bool hasAtt = bool.Parse(request["HasAttachment"].ToString()); | ||||
|                 byte attType = 0; | ||||
|                 string attName = string.Empty; | ||||
|                 string attOwner = string.Empty; | ||||
|                 UUID attItem = UUID.Zero; | ||||
|                 if (request.ContainsKey("AttachmentType")) | ||||
|                     attType = byte.Parse(request["AttachmentType"].ToString()); | ||||
|                 if (request.ContainsKey("AttachmentName")) | ||||
|                     attName = request["AttachmentName"].ToString(); | ||||
|                 if (request.ContainsKey("AttachmentItemID")) | ||||
|                     attItem = new UUID(request["AttachmentItemID"].ToString()); | ||||
|                 if (request.ContainsKey("AttachmentOwnerID")) | ||||
|                     attOwner = request["AttachmentOwnerID"].ToString(); | ||||
| 
 | ||||
|                 bool success = m_GroupsService.AddGroupNotice(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()), | ||||
|                         new UUID(request["NoticeID"].ToString()), request["FromName"].ToString(), request["Subject"].ToString(), | ||||
|                         request["Message"].ToString(), hasAtt, attType, attName, attItem, attOwner); | ||||
| 
 | ||||
|                 result["RESULT"] = success.ToString(); | ||||
|             } | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleGetNotices(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
| 
 | ||||
|             else if (request.ContainsKey("NoticeID")) // just one | ||||
|             { | ||||
|                 GroupNoticeInfo notice =  m_GroupsService.GetGroupNotice(request["RequestingAgentID"].ToString(), new UUID(request["NoticeID"].ToString())); | ||||
| 
 | ||||
|                 if (notice == null) | ||||
|                     NullResult(result, "NO such notice"); | ||||
|                 else | ||||
|                     result["RESULT"] = GroupsDataUtils.GroupNoticeInfo(notice); | ||||
| 
 | ||||
|             } | ||||
|             else if (request.ContainsKey("GroupID")) // all notices for group | ||||
|             { | ||||
|                 List<ExtendedGroupNoticeData> notices = m_GroupsService.GetGroupNotices(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString())); | ||||
| 
 | ||||
|                 if (notices == null || (notices != null && notices.Count == 0)) | ||||
|                     NullResult(result, "No notices"); | ||||
|                 else | ||||
|                 { | ||||
|                     Dictionary<string, object> dict = new Dictionary<string, object>(); | ||||
|                     int i = 0; | ||||
|                     foreach (ExtendedGroupNoticeData n in notices) | ||||
|                         dict["n-" + i++] = GroupsDataUtils.GroupNoticeData(n); | ||||
| 
 | ||||
|                     result["RESULT"] = dict; | ||||
|                 } | ||||
| 
 | ||||
|             } | ||||
|             else | ||||
|                 NullResult(result, "Bad OP in request"); | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleFindGroups(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("Query")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
| 
 | ||||
|             List<DirGroupsReplyData> hits = m_GroupsService.FindGroups(request["RequestingAgentID"].ToString(), request["Query"].ToString()); | ||||
| 
 | ||||
|             if (hits == null || (hits != null && hits.Count == 0)) | ||||
|                 NullResult(result, "No hits"); | ||||
|             else | ||||
|             { | ||||
|                 Dictionary<string, object> dict = new Dictionary<string, object>(); | ||||
|                 int i = 0; | ||||
|                 foreach (DirGroupsReplyData n in hits) | ||||
|                     dict["n-" + i++] = GroupsDataUtils.DirGroupsReplyData(n); | ||||
| 
 | ||||
|                 result["RESULT"] = dict; | ||||
|             } | ||||
| 
 | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         #region Helpers | ||||
| 
 | ||||
|         private void NullResult(Dictionary<string, object> result, string reason) | ||||
|         { | ||||
|             result["RESULT"] = "NULL"; | ||||
|             result["REASON"] = reason; | ||||
|         } | ||||
| 
 | ||||
|         private byte[] FailureResult() | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
|             NullResult(result, "Unknown method"); | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         private byte[] FailureResult(string reason) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
|             NullResult(result, reason); | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
|         #endregion | ||||
|     } | ||||
| } | ||||
|  | @ -1,888 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Reflection; | ||||
| using System.Threading; | ||||
| 
 | ||||
| using OpenSim.Framework; | ||||
| //using OpenSim.Region.Framework.Interfaces; | ||||
| using OpenSim.Services.Interfaces; | ||||
| 
 | ||||
| using OpenMetaverse; | ||||
| 
 | ||||
| namespace OpenSim.Groups | ||||
| { | ||||
|     public delegate ExtendedGroupRecord GroupRecordDelegate(); | ||||
|     public delegate GroupMembershipData GroupMembershipDelegate(); | ||||
|     public delegate List<GroupMembershipData> GroupMembershipListDelegate(); | ||||
|     public delegate List<ExtendedGroupMembersData> GroupMembersListDelegate(); | ||||
|     public delegate List<GroupRolesData> GroupRolesListDelegate(); | ||||
|     public delegate List<ExtendedGroupRoleMembersData> RoleMembersListDelegate(); | ||||
|     public delegate GroupNoticeInfo NoticeDelegate(); | ||||
|     public delegate List<ExtendedGroupNoticeData> NoticeListDelegate(); | ||||
|     public delegate void VoidDelegate(); | ||||
|     public delegate bool BooleanDelegate(); | ||||
| 
 | ||||
|     public class RemoteConnectorCacheWrapper | ||||
|     { | ||||
|         private ForeignImporter m_ForeignImporter; | ||||
| 
 | ||||
|         private Dictionary<string, bool> m_ActiveRequests = new Dictionary<string, bool>(); | ||||
|         private const int GROUPS_CACHE_TIMEOUT = 1 * 60; // 1 minutes | ||||
| 
 | ||||
|         // This all important cache cahces objects of different types: | ||||
|         // group-<GroupID> or group-<Name>          => ExtendedGroupRecord | ||||
|         // active-<AgentID>                         => GroupMembershipData | ||||
|         // membership-<AgentID>-<GroupID>           => GroupMembershipData | ||||
|         // memberships-<AgentID>                    => List<GroupMembershipData> | ||||
|         // members-<RequestingAgentID>-<GroupID>    => List<ExtendedGroupMembersData> | ||||
|         // role-<RoleID>                            => GroupRolesData | ||||
|         // roles-<GroupID>                          => List<GroupRolesData> ; all roles in the group | ||||
|         // roles-<GroupID>-<AgentID>                => List<GroupRolesData> ; roles that the agent has | ||||
|         // rolemembers-<RequestingAgentID>-<GroupID> => List<ExtendedGroupRoleMembersData> | ||||
|         // notice-<noticeID>                        => GroupNoticeInfo | ||||
|         // notices-<GroupID>                        => List<ExtendedGroupNoticeData> | ||||
|         private ExpiringCache<string, object> m_Cache = new ExpiringCache<string, object>(); | ||||
| 
 | ||||
|         public RemoteConnectorCacheWrapper(IUserManagement uman) | ||||
|         { | ||||
|             m_ForeignImporter = new ForeignImporter(uman); | ||||
|         } | ||||
| 
 | ||||
|         public UUID CreateGroup(UUID RequestingAgentID, GroupRecordDelegate d) | ||||
|         { | ||||
|             //m_log.DebugFormat("[Groups.RemoteConnector]: Creating group {0}", name); | ||||
|             //reason = string.Empty; | ||||
| 
 | ||||
|             //ExtendedGroupRecord group = m_GroupsService.CreateGroup(RequestingAgentID.ToString(), name, charter, showInList, insigniaID, | ||||
|             //    membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out reason); | ||||
|             ExtendedGroupRecord group = d(); | ||||
| 
 | ||||
|             if (group == null) | ||||
|                 return UUID.Zero; | ||||
| 
 | ||||
|             if (group.GroupID != UUID.Zero) | ||||
|                 lock (m_Cache) | ||||
|                 { | ||||
|                     m_Cache.Add("group-" + group.GroupID.ToString(), group, GROUPS_CACHE_TIMEOUT); | ||||
|                     if (m_Cache.Contains("memberships-" + RequestingAgentID.ToString())) | ||||
|                         m_Cache.Remove("memberships-" + RequestingAgentID.ToString()); | ||||
|                 } | ||||
| 
 | ||||
|             return group.GroupID; | ||||
|         } | ||||
| 
 | ||||
|         public bool UpdateGroup(UUID groupID, GroupRecordDelegate d) | ||||
|         { | ||||
|             //reason = string.Empty; | ||||
|             //ExtendedGroupRecord group = m_GroupsService.UpdateGroup(RequestingAgentID, groupID, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish); | ||||
|             ExtendedGroupRecord group = d(); | ||||
| 
 | ||||
|             if (group != null && group.GroupID != UUID.Zero) | ||||
|                 lock (m_Cache) | ||||
|                     m_Cache.AddOrUpdate("group-" + group.GroupID.ToString(), group, GROUPS_CACHE_TIMEOUT); | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName, GroupRecordDelegate d) | ||||
|         { | ||||
|             //if (GroupID == UUID.Zero && (GroupName == null || GroupName != null && GroupName == string.Empty)) | ||||
|             //    return null; | ||||
| 
 | ||||
|             object group = null; | ||||
|             bool firstCall = false; | ||||
|             string cacheKey = "group-"; | ||||
|             if (GroupID != UUID.Zero) | ||||
|                 cacheKey += GroupID.ToString(); | ||||
|             else | ||||
|                 cacheKey += GroupName; | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: GetGroupRecord {0}", cacheKey); | ||||
| 
 | ||||
|             while (true) | ||||
|             { | ||||
|                 lock (m_Cache) | ||||
|                 { | ||||
|                     if (m_Cache.TryGetValue(cacheKey, out group)) | ||||
|                     { | ||||
|                         //m_log.DebugFormat("[XXX]: GetGroupRecord {0} cached!", cacheKey); | ||||
|                         return (ExtendedGroupRecord)group; | ||||
|                     } | ||||
| 
 | ||||
|                     // not cached | ||||
|                     if (!m_ActiveRequests.ContainsKey(cacheKey)) | ||||
|                     { | ||||
|                         m_ActiveRequests.Add(cacheKey, true); | ||||
|                         firstCall = true; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (firstCall) | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         //group = m_GroupsService.GetGroupRecord(RequestingAgentID, GroupID, GroupName); | ||||
|                         group = d(); | ||||
| 
 | ||||
|                         lock (m_Cache) | ||||
|                         { | ||||
|                             m_Cache.AddOrUpdate(cacheKey, group, GROUPS_CACHE_TIMEOUT); | ||||
|                             return (ExtendedGroupRecord)group; | ||||
|                         } | ||||
|                     } | ||||
|                     finally | ||||
|                     { | ||||
|                         m_ActiveRequests.Remove(cacheKey); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                     Thread.Sleep(50); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, GroupMembershipDelegate d) | ||||
|         { | ||||
|             GroupMembershipData membership = d(); | ||||
|             if (membership == null) | ||||
|                 return false; | ||||
| 
 | ||||
|             lock (m_Cache) | ||||
|             { | ||||
|                 // first, remove everything! add a user is a heavy-duty op | ||||
|                 m_Cache.Clear(); | ||||
| 
 | ||||
|                 m_Cache.AddOrUpdate("active-" + AgentID.ToString(), membership, GROUPS_CACHE_TIMEOUT); | ||||
|                 m_Cache.AddOrUpdate("membership-" + AgentID.ToString() + "-" + GroupID.ToString(), membership, GROUPS_CACHE_TIMEOUT); | ||||
|             } | ||||
| 
 | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID, VoidDelegate d) | ||||
|         { | ||||
|             d(); | ||||
| 
 | ||||
|             lock (m_Cache) | ||||
|             { | ||||
|                 string cacheKey = "active-" + AgentID.ToString(); | ||||
|                 if (m_Cache.Contains(cacheKey)) | ||||
|                     m_Cache.Remove(cacheKey); | ||||
| 
 | ||||
|                 cacheKey = "memberships-" + AgentID.ToString(); | ||||
|                 if (m_Cache.Contains(cacheKey)) | ||||
|                     m_Cache.Remove(cacheKey); | ||||
| 
 | ||||
|                 cacheKey = "membership-" + AgentID.ToString() + "-" + GroupID.ToString(); | ||||
|                 if (m_Cache.Contains(cacheKey)) | ||||
|                     m_Cache.Remove(cacheKey); | ||||
| 
 | ||||
|                 cacheKey = "members-" + RequestingAgentID.ToString() + "-" + GroupID.ToString(); | ||||
|                 if (m_Cache.Contains(cacheKey)) | ||||
|                     m_Cache.Remove(cacheKey); | ||||
| 
 | ||||
|                 cacheKey = "roles-" + "-" + GroupID.ToString() + "-" + AgentID.ToString(); | ||||
|                 if (m_Cache.Contains(cacheKey)) | ||||
|                     m_Cache.Remove(cacheKey); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void SetAgentActiveGroup(string AgentID, GroupMembershipDelegate d) | ||||
|         { | ||||
|             GroupMembershipData activeGroup = d(); | ||||
|             string cacheKey = "active-" + AgentID.ToString(); | ||||
|             lock (m_Cache) | ||||
|                 if (m_Cache.Contains(cacheKey)) | ||||
|                     m_Cache.AddOrUpdate(cacheKey, activeGroup, GROUPS_CACHE_TIMEOUT); | ||||
|         } | ||||
| 
 | ||||
|         public ExtendedGroupMembershipData GetAgentActiveMembership(string AgentID, GroupMembershipDelegate d) | ||||
|         { | ||||
|             object membership = null; | ||||
|             bool firstCall = false; | ||||
|             string cacheKey = "active-" + AgentID.ToString(); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: GetAgentActiveMembership {0}", cacheKey); | ||||
| 
 | ||||
|             while (true) | ||||
|             { | ||||
|                 lock (m_Cache) | ||||
|                 { | ||||
|                     if (m_Cache.TryGetValue(cacheKey, out membership)) | ||||
|                     { | ||||
|                         //m_log.DebugFormat("[XXX]: GetAgentActiveMembership {0} cached!", cacheKey); | ||||
|                         return (ExtendedGroupMembershipData)membership; | ||||
|                     } | ||||
| 
 | ||||
|                     // not cached | ||||
|                     if (!m_ActiveRequests.ContainsKey(cacheKey)) | ||||
|                     { | ||||
|                         m_ActiveRequests.Add(cacheKey, true); | ||||
|                         firstCall = true; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (firstCall) | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         membership = d(); | ||||
| 
 | ||||
|                         lock (m_Cache) | ||||
|                         { | ||||
|                             m_Cache.AddOrUpdate(cacheKey, membership, GROUPS_CACHE_TIMEOUT); | ||||
|                             return (ExtendedGroupMembershipData)membership; | ||||
|                         } | ||||
|                     } | ||||
|                     finally | ||||
|                     { | ||||
|                         m_ActiveRequests.Remove(cacheKey); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                     Thread.Sleep(50); | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         public ExtendedGroupMembershipData GetAgentGroupMembership(string AgentID, UUID GroupID, GroupMembershipDelegate d) | ||||
|         { | ||||
|             object membership = null; | ||||
|             bool firstCall = false; | ||||
|             string cacheKey = "membership-" + AgentID.ToString() + "-" + GroupID.ToString(); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: GetAgentGroupMembership {0}", cacheKey); | ||||
| 
 | ||||
|             while (true) | ||||
|             { | ||||
|                 lock (m_Cache) | ||||
|                 { | ||||
|                     if (m_Cache.TryGetValue(cacheKey, out membership)) | ||||
|                     { | ||||
|                         //m_log.DebugFormat("[XXX]: GetAgentGroupMembership {0}", cacheKey); | ||||
|                         return (ExtendedGroupMembershipData)membership; | ||||
|                     } | ||||
| 
 | ||||
|                     // not cached | ||||
|                     if (!m_ActiveRequests.ContainsKey(cacheKey)) | ||||
|                     { | ||||
|                         m_ActiveRequests.Add(cacheKey, true); | ||||
|                         firstCall = true; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (firstCall) | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         membership = d(); | ||||
|                         lock (m_Cache) | ||||
|                         { | ||||
|                             m_Cache.AddOrUpdate(cacheKey, membership, GROUPS_CACHE_TIMEOUT); | ||||
|                             return (ExtendedGroupMembershipData)membership; | ||||
|                         } | ||||
|                     } | ||||
|                     finally | ||||
|                     { | ||||
|                         m_ActiveRequests.Remove(cacheKey); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                     Thread.Sleep(50); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupMembershipData> GetAgentGroupMemberships(string AgentID, GroupMembershipListDelegate d) | ||||
|         { | ||||
|             object memberships = null; | ||||
|             bool firstCall = false; | ||||
|             string cacheKey = "memberships-" + AgentID.ToString(); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: GetAgentGroupMemberships {0}", cacheKey); | ||||
| 
 | ||||
|             while (true) | ||||
|             { | ||||
|                 lock (m_Cache) | ||||
|                 { | ||||
|                     if (m_Cache.TryGetValue(cacheKey, out memberships)) | ||||
|                     { | ||||
|                         //m_log.DebugFormat("[XXX]: GetAgentGroupMemberships {0} cached!", cacheKey); | ||||
|                         return (List<GroupMembershipData>)memberships; | ||||
|                     } | ||||
| 
 | ||||
|                     // not cached | ||||
|                     if (!m_ActiveRequests.ContainsKey(cacheKey)) | ||||
|                     { | ||||
|                         m_ActiveRequests.Add(cacheKey, true); | ||||
|                         firstCall = true; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (firstCall) | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         memberships = d(); | ||||
|                         lock (m_Cache) | ||||
|                         { | ||||
|                             m_Cache.AddOrUpdate(cacheKey, memberships, GROUPS_CACHE_TIMEOUT); | ||||
|                             return (List<GroupMembershipData>)memberships; | ||||
|                         } | ||||
|                     } | ||||
|                     finally | ||||
|                     { | ||||
|                         m_ActiveRequests.Remove(cacheKey); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                     Thread.Sleep(50); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID, GroupMembersListDelegate d) | ||||
|         { | ||||
|             object members = null; | ||||
|             bool firstCall = false; | ||||
|             // we need to key in also on the requester, because different ppl have different view privileges | ||||
|             string cacheKey = "members-" + RequestingAgentID.ToString() + "-" + GroupID.ToString(); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: GetGroupMembers {0}", cacheKey); | ||||
| 
 | ||||
|             while (true) | ||||
|             { | ||||
|                 lock (m_Cache) | ||||
|                 { | ||||
|                     if (m_Cache.TryGetValue(cacheKey, out members)) | ||||
|                     { | ||||
|                         List<ExtendedGroupMembersData> xx = (List<ExtendedGroupMembersData>)members; | ||||
|                         return xx.ConvertAll<GroupMembersData>(new Converter<ExtendedGroupMembersData, GroupMembersData>(m_ForeignImporter.ConvertGroupMembersData)); | ||||
|                     } | ||||
| 
 | ||||
|                     // not cached | ||||
|                     if (!m_ActiveRequests.ContainsKey(cacheKey)) | ||||
|                     { | ||||
|                         m_ActiveRequests.Add(cacheKey, true); | ||||
|                         firstCall = true; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (firstCall) | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         List<ExtendedGroupMembersData> _members = d(); | ||||
| 
 | ||||
|                         if (_members != null && _members.Count > 0) | ||||
|                             members = _members.ConvertAll<GroupMembersData>(new Converter<ExtendedGroupMembersData, GroupMembersData>(m_ForeignImporter.ConvertGroupMembersData)); | ||||
|                         else | ||||
|                             members = new List<GroupMembersData>(); | ||||
| 
 | ||||
|                         lock (m_Cache) | ||||
|                         { | ||||
|                             //m_Cache.AddOrUpdate(cacheKey, members, GROUPS_CACHE_TIMEOUT); | ||||
|                             m_Cache.AddOrUpdate(cacheKey, _members, GROUPS_CACHE_TIMEOUT); | ||||
| 
 | ||||
|                             return (List<GroupMembersData>)members; | ||||
|                         } | ||||
|                     } | ||||
|                     finally | ||||
|                     { | ||||
|                         m_ActiveRequests.Remove(cacheKey); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                     Thread.Sleep(50); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public bool AddGroupRole(UUID groupID, UUID roleID, string description, string name, ulong powers, string title, BooleanDelegate d) | ||||
|         { | ||||
|             if (d()) | ||||
|             { | ||||
|                 GroupRolesData role = new GroupRolesData(); | ||||
|                 role.Description = description; | ||||
|                 role.Members = 0; | ||||
|                 role.Name = name; | ||||
|                 role.Powers = powers; | ||||
|                 role.RoleID = roleID; | ||||
|                 role.Title = title; | ||||
| 
 | ||||
|                 lock (m_Cache) | ||||
|                 { | ||||
|                     m_Cache.AddOrUpdate("role-" + roleID.ToString(), role, GROUPS_CACHE_TIMEOUT); | ||||
| 
 | ||||
|                     // also remove this list | ||||
|                     if (m_Cache.Contains("roles-" + groupID.ToString())) | ||||
|                         m_Cache.Remove("roles-" + groupID.ToString()); | ||||
| 
 | ||||
|                 } | ||||
| 
 | ||||
|                 return true; | ||||
|             } | ||||
| 
 | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         public bool UpdateGroupRole(UUID groupID, UUID roleID, string name, string description, string title, ulong powers, BooleanDelegate d) | ||||
|         { | ||||
|             if (d()) | ||||
|             { | ||||
|                 object role; | ||||
|                 lock (m_Cache) | ||||
|                     if (m_Cache.TryGetValue("role-" + roleID.ToString(), out role)) | ||||
|                     { | ||||
|                         GroupRolesData r = (GroupRolesData)role; | ||||
|                         r.Description = description; | ||||
|                         r.Name = name; | ||||
|                         r.Powers = powers; | ||||
|                         r.Title = title; | ||||
| 
 | ||||
|                         m_Cache.Update("role-" + roleID.ToString(), r, GROUPS_CACHE_TIMEOUT); | ||||
|                     } | ||||
|                 return true; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 lock (m_Cache) | ||||
|                 { | ||||
|                     if (m_Cache.Contains("role-" + roleID.ToString())) | ||||
|                         m_Cache.Remove("role-" + roleID.ToString()); | ||||
| 
 | ||||
|                     // also remove these lists, because they will have an outdated role | ||||
|                     if (m_Cache.Contains("roles-" + groupID.ToString())) | ||||
|                         m_Cache.Remove("roles-" + groupID.ToString()); | ||||
| 
 | ||||
|                 } | ||||
| 
 | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, VoidDelegate d) | ||||
|         { | ||||
|             d(); | ||||
| 
 | ||||
|             lock (m_Cache) | ||||
|             { | ||||
|                 if (m_Cache.Contains("role-" + roleID.ToString())) | ||||
|                     m_Cache.Remove("role-" + roleID.ToString()); | ||||
| 
 | ||||
|                 // also remove the list, because it will have an removed role | ||||
|                 if (m_Cache.Contains("roles-" + groupID.ToString())) | ||||
|                     m_Cache.Remove("roles-" + groupID.ToString()); | ||||
| 
 | ||||
|                 if (m_Cache.Contains("roles-" + groupID.ToString() + "-" + RequestingAgentID.ToString())) | ||||
|                     m_Cache.Remove("roles-" + groupID.ToString() + "-" + RequestingAgentID.ToString()); | ||||
| 
 | ||||
|                 if (m_Cache.Contains("rolemembers-" + RequestingAgentID.ToString() + "-" + groupID.ToString())) | ||||
|                     m_Cache.Remove("rolemembers-" + RequestingAgentID.ToString() + "-" + groupID.ToString()); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID, GroupRolesListDelegate d) | ||||
|         { | ||||
|             object roles = null; | ||||
|             bool firstCall = false; | ||||
|             string cacheKey = "roles-" + GroupID.ToString(); | ||||
| 
 | ||||
|             while (true) | ||||
|             { | ||||
|                 lock (m_Cache) | ||||
|                 { | ||||
|                     if (m_Cache.TryGetValue(cacheKey, out roles)) | ||||
|                         return (List<GroupRolesData>)roles; | ||||
| 
 | ||||
|                     // not cached | ||||
|                     if (!m_ActiveRequests.ContainsKey(cacheKey)) | ||||
|                     { | ||||
|                         m_ActiveRequests.Add(cacheKey, true); | ||||
|                         firstCall = true; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (firstCall) | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         roles = d(); | ||||
|                         if (roles != null) | ||||
|                         { | ||||
|                             lock (m_Cache) | ||||
|                             { | ||||
|                                 m_Cache.AddOrUpdate(cacheKey, roles, GROUPS_CACHE_TIMEOUT); | ||||
|                                 return (List<GroupRolesData>)roles; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     finally | ||||
|                     { | ||||
|                         m_ActiveRequests.Remove(cacheKey); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                     Thread.Sleep(50); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID, RoleMembersListDelegate d) | ||||
|         { | ||||
|             object rmembers = null; | ||||
|             bool firstCall = false; | ||||
|             // we need to key in also on the requester, because different ppl have different view privileges | ||||
|             string cacheKey = "rolemembers-" + RequestingAgentID.ToString() + "-" + GroupID.ToString(); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: GetGroupRoleMembers {0}", cacheKey); | ||||
|             while (true) | ||||
|             { | ||||
|                 lock (m_Cache) | ||||
|                 { | ||||
|                     if (m_Cache.TryGetValue(cacheKey, out rmembers)) | ||||
|                     { | ||||
|                         List<ExtendedGroupRoleMembersData> xx = (List<ExtendedGroupRoleMembersData>)rmembers; | ||||
|                         return xx.ConvertAll<GroupRoleMembersData>(m_ForeignImporter.ConvertGroupRoleMembersData); | ||||
|                     } | ||||
| 
 | ||||
|                     // not cached | ||||
|                     if (!m_ActiveRequests.ContainsKey(cacheKey)) | ||||
|                     { | ||||
|                         m_ActiveRequests.Add(cacheKey, true); | ||||
|                         firstCall = true; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (firstCall) | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         List<ExtendedGroupRoleMembersData> _rmembers = d(); | ||||
| 
 | ||||
|                         if (_rmembers != null && _rmembers.Count > 0) | ||||
|                             rmembers = _rmembers.ConvertAll<GroupRoleMembersData>(new Converter<ExtendedGroupRoleMembersData, GroupRoleMembersData>(m_ForeignImporter.ConvertGroupRoleMembersData)); | ||||
|                         else | ||||
|                             rmembers = new List<GroupRoleMembersData>(); | ||||
| 
 | ||||
|                         lock (m_Cache) | ||||
|                         { | ||||
|                             // For some strange reason, when I cache the list of GroupRoleMembersData, | ||||
|                             // it gets emptied out. The TryGet gets an empty list... | ||||
|                             //m_Cache.AddOrUpdate(cacheKey, rmembers, GROUPS_CACHE_TIMEOUT); | ||||
|                             // Caching the list of ExtendedGroupRoleMembersData doesn't show that issue | ||||
|                             // I don't get it. | ||||
|                             m_Cache.AddOrUpdate(cacheKey, _rmembers, GROUPS_CACHE_TIMEOUT); | ||||
|                             return (List<GroupRoleMembersData>)rmembers; | ||||
|                         } | ||||
|                     } | ||||
|                     finally | ||||
|                     { | ||||
|                         m_ActiveRequests.Remove(cacheKey); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                     Thread.Sleep(50); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, BooleanDelegate d) | ||||
|         { | ||||
|             if (d()) | ||||
|             { | ||||
|                 lock (m_Cache) | ||||
|                 { | ||||
|                     // update the cached role | ||||
|                     string cacheKey = "role-" + RoleID.ToString(); | ||||
|                     object obj; | ||||
|                     if (m_Cache.TryGetValue(cacheKey, out obj)) | ||||
|                     { | ||||
|                         GroupRolesData r = (GroupRolesData)obj; | ||||
|                         r.Members++; | ||||
|                     } | ||||
| 
 | ||||
|                     // add this agent to the list of role members | ||||
|                     cacheKey = "rolemembers-" + RequestingAgentID.ToString() + "-" + GroupID.ToString(); | ||||
|                     if (m_Cache.TryGetValue(cacheKey, out obj)) | ||||
|                     { | ||||
|                         try | ||||
|                         { | ||||
|                             // This may throw an exception, in which case the agentID is not a UUID but a full ID | ||||
|                             // In that case, let's just remove the whoe things from the cache | ||||
|                             UUID id = new UUID(AgentID); | ||||
|                             List<ExtendedGroupRoleMembersData> xx = (List<ExtendedGroupRoleMembersData>)obj; | ||||
|                             List<GroupRoleMembersData> rmlist = xx.ConvertAll<GroupRoleMembersData>(m_ForeignImporter.ConvertGroupRoleMembersData); | ||||
|                             GroupRoleMembersData rm = new GroupRoleMembersData(); | ||||
|                             rm.MemberID = id; | ||||
|                             rm.RoleID = RoleID; | ||||
|                             rmlist.Add(rm); | ||||
|                         } | ||||
|                         catch | ||||
|                         { | ||||
|                             m_Cache.Remove(cacheKey); | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     // Remove the cached info about this agent's roles | ||||
|                     // because we don't have enough local info about the new role | ||||
|                     cacheKey = "roles-" + GroupID.ToString() + "-" + AgentID.ToString(); | ||||
|                     if (m_Cache.Contains(cacheKey)) | ||||
|                         m_Cache.Remove(cacheKey); | ||||
| 
 | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, BooleanDelegate d) | ||||
|         { | ||||
|             if (d()) | ||||
|             { | ||||
|                 lock (m_Cache) | ||||
|                 { | ||||
|                     // update the cached role | ||||
|                     string cacheKey = "role-" + RoleID.ToString(); | ||||
|                     object obj; | ||||
|                     if (m_Cache.TryGetValue(cacheKey, out obj)) | ||||
|                     { | ||||
|                         GroupRolesData r = (GroupRolesData)obj; | ||||
|                         r.Members--; | ||||
|                     } | ||||
| 
 | ||||
|                     cacheKey = "roles-" + GroupID.ToString() + "-" + AgentID.ToString(); | ||||
|                     if (m_Cache.Contains(cacheKey)) | ||||
|                         m_Cache.Remove(cacheKey); | ||||
| 
 | ||||
|                     cacheKey = "rolemembers-" + RequestingAgentID.ToString() + "-" + GroupID.ToString(); | ||||
|                     if (m_Cache.Contains(cacheKey)) | ||||
|                         m_Cache.Remove(cacheKey); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID, GroupRolesListDelegate d) | ||||
|         { | ||||
|             object roles = null; | ||||
|             bool firstCall = false; | ||||
|             string cacheKey = "roles-" + GroupID.ToString() + "-" + AgentID.ToString(); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: GetAgentGroupRoles {0}", cacheKey); | ||||
| 
 | ||||
|             while (true) | ||||
|             { | ||||
|                 lock (m_Cache) | ||||
|                 { | ||||
|                     if (m_Cache.TryGetValue(cacheKey, out roles)) | ||||
|                     { | ||||
|                         //m_log.DebugFormat("[XXX]: GetAgentGroupRoles {0} cached!", cacheKey); | ||||
|                         return (List<GroupRolesData>)roles; | ||||
|                     } | ||||
| 
 | ||||
|                     // not cached | ||||
|                     if (!m_ActiveRequests.ContainsKey(cacheKey)) | ||||
|                     { | ||||
|                         m_ActiveRequests.Add(cacheKey, true); | ||||
|                         firstCall = true; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (firstCall) | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         roles = d(); | ||||
|                         lock (m_Cache) | ||||
|                         { | ||||
|                             m_Cache.AddOrUpdate(cacheKey, roles, GROUPS_CACHE_TIMEOUT); | ||||
|                             m_ActiveRequests.Remove(cacheKey); | ||||
|                             return (List<GroupRolesData>)roles; | ||||
|                         } | ||||
|                     } | ||||
|                     finally | ||||
|                     { | ||||
|                         m_ActiveRequests.Remove(cacheKey); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                     Thread.Sleep(50); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void SetAgentActiveGroupRole(string AgentID, UUID GroupID, VoidDelegate d) | ||||
|         { | ||||
|             d(); | ||||
| 
 | ||||
|             lock (m_Cache) | ||||
|             { | ||||
|                 // Invalidate cached info, because it has ActiveRoleID and Powers | ||||
|                 string cacheKey = "membership-" + AgentID.ToString() + "-" + GroupID.ToString(); | ||||
|                 if (m_Cache.Contains(cacheKey)) | ||||
|                     m_Cache.Remove(cacheKey); | ||||
| 
 | ||||
|                 cacheKey = "memberships-" + AgentID.ToString(); | ||||
|                 if (m_Cache.Contains(cacheKey)) | ||||
|                     m_Cache.Remove(cacheKey); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void UpdateMembership(string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile, VoidDelegate d) | ||||
|         { | ||||
|             d(); | ||||
| 
 | ||||
|             lock (m_Cache) | ||||
|             { | ||||
|                 string cacheKey = "membership-" + AgentID.ToString() + "-" + GroupID.ToString(); | ||||
|                 if (m_Cache.Contains(cacheKey)) | ||||
|                     m_Cache.Remove(cacheKey); | ||||
| 
 | ||||
|                 cacheKey = "memberships-" + AgentID.ToString(); | ||||
|                 if (m_Cache.Contains(cacheKey)) | ||||
|                     m_Cache.Remove(cacheKey); | ||||
| 
 | ||||
|                 cacheKey = "active-" + AgentID.ToString(); | ||||
|                 object m = null; | ||||
|                 if (m_Cache.TryGetValue(cacheKey, out m)) | ||||
|                 { | ||||
|                     GroupMembershipData membership = (GroupMembershipData)m; | ||||
|                     membership.ListInProfile = ListInProfile; | ||||
|                     membership.AcceptNotices = AcceptNotices; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public bool AddGroupNotice(UUID groupID, UUID noticeID, GroupNoticeInfo notice, BooleanDelegate d) | ||||
|         { | ||||
|             if (d()) | ||||
|             { | ||||
|                 lock (m_Cache) | ||||
|                 { | ||||
|                     m_Cache.AddOrUpdate("notice-" + noticeID.ToString(), notice, GROUPS_CACHE_TIMEOUT); | ||||
|                     string cacheKey = "notices-" + groupID.ToString(); | ||||
|                     if (m_Cache.Contains(cacheKey)) | ||||
|                         m_Cache.Remove(cacheKey); | ||||
| 
 | ||||
|                 } | ||||
| 
 | ||||
|                 return true; | ||||
|             } | ||||
| 
 | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         public GroupNoticeInfo GetGroupNotice(UUID noticeID, NoticeDelegate d) | ||||
|         { | ||||
|             object notice = null; | ||||
|             bool firstCall = false; | ||||
|             string cacheKey = "notice-" + noticeID.ToString(); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: GetAgentGroupRoles {0}", cacheKey); | ||||
| 
 | ||||
|             while (true) | ||||
|             { | ||||
|                 lock (m_Cache) | ||||
|                 { | ||||
|                     if (m_Cache.TryGetValue(cacheKey, out notice)) | ||||
|                     { | ||||
|                         return (GroupNoticeInfo)notice; | ||||
|                     } | ||||
| 
 | ||||
|                     // not cached | ||||
|                     if (!m_ActiveRequests.ContainsKey(cacheKey)) | ||||
|                     { | ||||
|                         m_ActiveRequests.Add(cacheKey, true); | ||||
|                         firstCall = true; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (firstCall) | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         GroupNoticeInfo _notice = d(); | ||||
| 
 | ||||
|                         lock (m_Cache) | ||||
|                         { | ||||
|                             m_Cache.AddOrUpdate(cacheKey, _notice, GROUPS_CACHE_TIMEOUT); | ||||
|                             return _notice; | ||||
|                         } | ||||
|                     } | ||||
|                     finally | ||||
|                     { | ||||
|                         m_ActiveRequests.Remove(cacheKey); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                     Thread.Sleep(50); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public List<ExtendedGroupNoticeData> GetGroupNotices(UUID GroupID, NoticeListDelegate d) | ||||
|         { | ||||
|             object notices = null; | ||||
|             bool firstCall = false; | ||||
|             string cacheKey = "notices-" + GroupID.ToString(); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: GetGroupNotices {0}", cacheKey); | ||||
| 
 | ||||
|             while (true) | ||||
|             { | ||||
|                 lock (m_Cache) | ||||
|                 { | ||||
|                     if (m_Cache.TryGetValue(cacheKey, out notices)) | ||||
|                     { | ||||
|                         //m_log.DebugFormat("[XXX]: GetGroupNotices {0} cached!", cacheKey); | ||||
|                         return (List<ExtendedGroupNoticeData>)notices; | ||||
|                     } | ||||
| 
 | ||||
|                     // not cached | ||||
|                     if (!m_ActiveRequests.ContainsKey(cacheKey)) | ||||
|                     { | ||||
|                         m_ActiveRequests.Add(cacheKey, true); | ||||
|                         firstCall = true; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (firstCall) | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         notices = d(); | ||||
| 
 | ||||
|                         lock (m_Cache) | ||||
|                         { | ||||
|                             m_Cache.AddOrUpdate(cacheKey, notices, GROUPS_CACHE_TIMEOUT); | ||||
|                             return (List<ExtendedGroupNoticeData>)notices; | ||||
|                         } | ||||
|                     } | ||||
|                     finally | ||||
|                     { | ||||
|                         m_ActiveRequests.Remove(cacheKey); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                     Thread.Sleep(50); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -1,101 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Reflection; | ||||
| using Nini.Config; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Data; | ||||
| using OpenSim.Services.Interfaces; | ||||
| using OpenSim.Services.Base; | ||||
| 
 | ||||
| namespace OpenSim.Groups | ||||
| { | ||||
|     public class GroupsServiceBase : ServiceBase | ||||
|     { | ||||
|         protected IGroupsData m_Database = null; | ||||
|         protected IGridUserData m_GridUserService = null; | ||||
| 
 | ||||
|         public GroupsServiceBase(IConfigSource config, string cName) | ||||
|             : base(config) | ||||
|         { | ||||
|             string dllName = String.Empty; | ||||
|             string connString = String.Empty; | ||||
|             string realm = "os_groups"; | ||||
|             string usersRealm = "GridUser"; | ||||
|             string configName = (cName == string.Empty) ? "Groups" : cName; | ||||
| 
 | ||||
|             // | ||||
|             // Try reading the [DatabaseService] section, if it exists | ||||
|             // | ||||
|             IConfig dbConfig = config.Configs["DatabaseService"]; | ||||
|             if (dbConfig != null) | ||||
|             { | ||||
|                 if (dllName == String.Empty) | ||||
|                     dllName = dbConfig.GetString("StorageProvider", String.Empty); | ||||
|                 if (connString == String.Empty) | ||||
|                     connString = dbConfig.GetString("ConnectionString", String.Empty); | ||||
|             } | ||||
| 
 | ||||
|             // | ||||
|             // [Groups] section overrides [DatabaseService], if it exists | ||||
|             // | ||||
|             IConfig groupsConfig = config.Configs[configName]; | ||||
|             if (groupsConfig != null) | ||||
|             { | ||||
|                 dllName = groupsConfig.GetString("StorageProvider", dllName); | ||||
|                 connString = groupsConfig.GetString("ConnectionString", connString); | ||||
|                 realm = groupsConfig.GetString("Realm", realm); | ||||
|             } | ||||
| 
 | ||||
|             // | ||||
|             // We tried, but this doesn't exist. We can't proceed. | ||||
|             // | ||||
|             if (dllName.Equals(String.Empty)) | ||||
|                 throw new Exception("No StorageProvider configured"); | ||||
| 
 | ||||
|             m_Database = LoadPlugin<IGroupsData>(dllName, new Object[] { connString, realm }); | ||||
|             if (m_Database == null) | ||||
|                 throw new Exception("Could not find a storage interface in the given module " + dllName); | ||||
| 
 | ||||
|             // | ||||
|             // [GridUserService] section overrides [DatabaseService], if it exists | ||||
|             // | ||||
|             IConfig usersConfig = config.Configs["GridUserService"]; | ||||
|             if (usersConfig != null) | ||||
|             { | ||||
|                 dllName = usersConfig.GetString("StorageProvider", dllName); | ||||
|                 connString = usersConfig.GetString("ConnectionString", connString); | ||||
|                 usersRealm = usersConfig.GetString("Realm", usersRealm); | ||||
|             } | ||||
| 
 | ||||
|             m_GridUserService = LoadPlugin<IGridUserData>(dllName, new Object[] { connString, usersRealm }); | ||||
|             if (m_GridUserService == null) | ||||
|                 throw new Exception("Could not find a storage inferface for the given users module " + dllName); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -1,361 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Reflection; | ||||
| using System.Timers; | ||||
| using log4net; | ||||
| using Nini.Config; | ||||
| 
 | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Data; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Services.Interfaces; | ||||
| 
 | ||||
| namespace OpenSim.Groups | ||||
| { | ||||
|     public class HGGroupsService : GroupsService | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private IOfflineIMService m_OfflineIM; | ||||
|         private IUserAccountService m_UserAccounts; | ||||
|         private string m_HomeURI; | ||||
| 
 | ||||
|         public HGGroupsService(IConfigSource config, IOfflineIMService im, IUserAccountService users, string homeURI) | ||||
|             : base(config, string.Empty) | ||||
|         { | ||||
|             m_OfflineIM = im; | ||||
|             m_UserAccounts = users; | ||||
|             m_HomeURI = homeURI; | ||||
|             if (!m_HomeURI.EndsWith("/")) | ||||
|                 m_HomeURI += "/"; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         #region HG specific operations | ||||
| 
 | ||||
|         public bool CreateGroupProxy(string RequestingAgentID, string agentID,  string accessToken, UUID groupID, string serviceLocation, string name, out string reason) | ||||
|         { | ||||
|             reason = string.Empty; | ||||
|             Uri uri = null; | ||||
|             try | ||||
|             { | ||||
|                 uri = new Uri(serviceLocation); | ||||
|             } | ||||
|             catch (UriFormatException) | ||||
|             { | ||||
|                 reason = "Bad location for group proxy"; | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             // Check if it already exists | ||||
|             GroupData grec = m_Database.RetrieveGroup(groupID); | ||||
|             if (grec == null || | ||||
|                 (grec != null && grec.Data["Location"] != string.Empty && grec.Data["Location"].ToLower() != serviceLocation.ToLower())) | ||||
|             { | ||||
|                 // Create the group | ||||
|                 grec = new GroupData(); | ||||
|                 grec.GroupID = groupID; | ||||
|                 grec.Data = new Dictionary<string, string>(); | ||||
|                 grec.Data["Name"] = name + " @ " + uri.Authority; | ||||
|                 grec.Data["Location"] = serviceLocation; | ||||
|                 grec.Data["Charter"] = string.Empty; | ||||
|                 grec.Data["InsigniaID"] = UUID.Zero.ToString(); | ||||
|                 grec.Data["FounderID"] = UUID.Zero.ToString(); | ||||
|                 grec.Data["MembershipFee"] = "0"; | ||||
|                 grec.Data["OpenEnrollment"] = "0"; | ||||
|                 grec.Data["ShowInList"] = "0"; | ||||
|                 grec.Data["AllowPublish"] = "0"; | ||||
|                 grec.Data["MaturePublish"] = "0"; | ||||
|                 grec.Data["OwnerRoleID"] = UUID.Zero.ToString(); | ||||
| 
 | ||||
| 
 | ||||
|                 if (!m_Database.StoreGroup(grec)) | ||||
|                     return false; | ||||
|             } | ||||
| 
 | ||||
|             if (grec.Data["Location"] == string.Empty) | ||||
|             { | ||||
|                 reason = "Cannot add proxy membership to non-proxy group"; | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             UUID uid = UUID.Zero; | ||||
|             string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty; | ||||
|             Util.ParseUniversalUserIdentifier(RequestingAgentID, out uid, out url, out first, out last, out tmp); | ||||
|             string fromName = first + "." + last + "@" + url; | ||||
| 
 | ||||
|             // Invite to group again | ||||
|             InviteToGroup(fromName, groupID, new UUID(agentID), grec.Data["Name"]); | ||||
| 
 | ||||
|             // Stick the proxy membership in the DB already | ||||
|             // we'll delete it if the agent declines the invitation | ||||
|             MembershipData membership = new MembershipData(); | ||||
|             membership.PrincipalID = agentID; | ||||
|             membership.GroupID = groupID; | ||||
|             membership.Data = new Dictionary<string, string>(); | ||||
|             membership.Data["SelectedRoleID"] = UUID.Zero.ToString(); | ||||
|             membership.Data["Contribution"] = "0"; | ||||
|             membership.Data["ListInProfile"] = "1"; | ||||
|             membership.Data["AcceptNotices"] = "1"; | ||||
|             membership.Data["AccessToken"] = accessToken; | ||||
| 
 | ||||
|             m_Database.StoreMember(membership); | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         public bool RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID, string token) | ||||
|         { | ||||
|             // check the token | ||||
|             MembershipData membership = m_Database.RetrieveMember(GroupID, AgentID); | ||||
|             if (membership != null) | ||||
|             { | ||||
|                 if (token != string.Empty && token.Equals(membership.Data["AccessToken"])) | ||||
|                 { | ||||
|                     return RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     m_log.DebugFormat("[Groups.HGGroupsService]: access token {0} did not match stored one {1}", token, membership.Data["AccessToken"]); | ||||
|                     return false; | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 m_log.DebugFormat("[Groups.HGGroupsService]: membership not found for {0}", AgentID); | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string groupName, string token) | ||||
|         { | ||||
|             // check the token | ||||
|             if (!VerifyToken(GroupID, RequestingAgentID, token)) | ||||
|                 return null; | ||||
| 
 | ||||
|             ExtendedGroupRecord grec; | ||||
|             if (GroupID == UUID.Zero) | ||||
|                 grec = GetGroupRecord(RequestingAgentID, groupName); | ||||
|             else | ||||
|                 grec = GetGroupRecord(RequestingAgentID, GroupID); | ||||
| 
 | ||||
|             if (grec != null) | ||||
|                 FillFounderUUI(grec); | ||||
| 
 | ||||
|             return grec; | ||||
|         } | ||||
| 
 | ||||
|         public List<ExtendedGroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID, string token) | ||||
|         { | ||||
|             if (!VerifyToken(GroupID, RequestingAgentID, token)) | ||||
|                 return new List<ExtendedGroupMembersData>(); | ||||
| 
 | ||||
|             List<ExtendedGroupMembersData> members = GetGroupMembers(RequestingAgentID, GroupID); | ||||
| 
 | ||||
|             // convert UUIDs to UUIs | ||||
|             members.ForEach(delegate (ExtendedGroupMembersData m) | ||||
|             { | ||||
|                 if (m.AgentID.ToString().Length == 36) // UUID | ||||
|                 { | ||||
|                     UserAccount account = m_UserAccounts.GetUserAccount(UUID.Zero, new UUID(m.AgentID)); | ||||
|                     if (account != null) | ||||
|                         m.AgentID = Util.UniversalIdentifier(account.PrincipalID, account.FirstName, account.LastName, m_HomeURI); | ||||
|                 } | ||||
|             }); | ||||
| 
 | ||||
|             return members; | ||||
|         } | ||||
| 
 | ||||
|         public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID, string token) | ||||
|         { | ||||
|             if (!VerifyToken(GroupID, RequestingAgentID, token)) | ||||
|                 return new List<GroupRolesData>(); | ||||
| 
 | ||||
|             return GetGroupRoles(RequestingAgentID, GroupID); | ||||
|         } | ||||
| 
 | ||||
|         public List<ExtendedGroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID, string token) | ||||
|         { | ||||
|             if (!VerifyToken(GroupID, RequestingAgentID, token)) | ||||
|                 return new List<ExtendedGroupRoleMembersData>(); | ||||
| 
 | ||||
|             List<ExtendedGroupRoleMembersData> rolemembers = GetGroupRoleMembers(RequestingAgentID, GroupID); | ||||
| 
 | ||||
|             // convert UUIDs to UUIs | ||||
|             rolemembers.ForEach(delegate(ExtendedGroupRoleMembersData m) | ||||
|             { | ||||
|                 if (m.MemberID.ToString().Length == 36) // UUID | ||||
|                 { | ||||
|                     UserAccount account = m_UserAccounts.GetUserAccount(UUID.Zero, new UUID(m.MemberID)); | ||||
|                     if (account != null) | ||||
|                         m.MemberID = Util.UniversalIdentifier(account.PrincipalID, account.FirstName, account.LastName, m_HomeURI); | ||||
|                 } | ||||
|             }); | ||||
| 
 | ||||
|             return rolemembers; | ||||
|         } | ||||
| 
 | ||||
|         public bool AddNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, | ||||
|             bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID) | ||||
|         { | ||||
|             // check that the group proxy exists | ||||
|             ExtendedGroupRecord grec = GetGroupRecord(RequestingAgentID, groupID); | ||||
|             if (grec == null) | ||||
|             { | ||||
|                 m_log.DebugFormat("[Groups.HGGroupsService]: attempt at adding notice to non-existent group proxy"); | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             // check that the group is remote | ||||
|             if (grec.ServiceLocation == string.Empty) | ||||
|             { | ||||
|                 m_log.DebugFormat("[Groups.HGGroupsService]: attempt at adding notice to local (non-proxy) group"); | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             // check that there isn't already a notice with the same ID | ||||
|             if (GetGroupNotice(RequestingAgentID, noticeID) != null) | ||||
|             { | ||||
|                 m_log.DebugFormat("[Groups.HGGroupsService]: a notice with the same ID already exists", grec.ServiceLocation); | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             // This has good intentions (security) but it will potentially DDS the origin... | ||||
|             // We'll need to send a proof along with the message. Maybe encrypt the message | ||||
|             // using key pairs | ||||
|             // | ||||
|             //// check that the notice actually exists in the origin | ||||
|             //GroupsServiceHGConnector c = new GroupsServiceHGConnector(grec.ServiceLocation); | ||||
|             //if (!c.VerifyNotice(noticeID, groupID)) | ||||
|             //{ | ||||
|             //    m_log.DebugFormat("[Groups.HGGroupsService]: notice does not exist at origin {0}", grec.ServiceLocation); | ||||
|             //    return false; | ||||
|             //} | ||||
| 
 | ||||
|             // ok, we're good! | ||||
|             return _AddNotice(groupID, noticeID, fromName, subject, message, hasAttachment, attType, attName, attItemID, attOwnerID); | ||||
|         } | ||||
| 
 | ||||
|         public bool VerifyNotice(UUID noticeID, UUID groupID) | ||||
|         { | ||||
|             GroupNoticeInfo notice = GetGroupNotice(string.Empty, noticeID); | ||||
| 
 | ||||
|             if (notice == null) | ||||
|                 return false; | ||||
| 
 | ||||
|             if (notice.GroupID != groupID) | ||||
|                 return false; | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
|         private void InviteToGroup(string fromName, UUID groupID, UUID invitedAgentID, string groupName) | ||||
|         { | ||||
|             // Todo: Security check, probably also want to send some kind of notification | ||||
|             UUID InviteID = UUID.Random(); | ||||
| 
 | ||||
|             if (AddAgentToGroupInvite(InviteID, groupID, invitedAgentID.ToString())) | ||||
|             { | ||||
|                 Guid inviteUUID = InviteID.Guid; | ||||
| 
 | ||||
|                 GridInstantMessage msg = new GridInstantMessage(); | ||||
| 
 | ||||
|                 msg.imSessionID = inviteUUID; | ||||
| 
 | ||||
|                 // msg.fromAgentID = agentID.Guid; | ||||
|                 msg.fromAgentID = groupID.Guid; | ||||
|                 msg.toAgentID = invitedAgentID.Guid; | ||||
|                 //msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); | ||||
|                 msg.timestamp = 0; | ||||
|                 msg.fromAgentName = fromName; | ||||
|                 msg.message = string.Format("Please confirm your acceptance to join group {0}.", groupName); | ||||
|                 msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupInvitation; | ||||
|                 msg.fromGroup = true; | ||||
|                 msg.offline = (byte)0; | ||||
|                 msg.ParentEstateID = 0; | ||||
|                 msg.Position = Vector3.Zero; | ||||
|                 msg.RegionID = UUID.Zero.Guid; | ||||
|                 msg.binaryBucket = new byte[20]; | ||||
| 
 | ||||
|                 string reason = string.Empty; | ||||
|                 m_OfflineIM.StoreMessage(msg, out reason); | ||||
| 
 | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private bool AddAgentToGroupInvite(UUID inviteID, UUID groupID, string agentID) | ||||
|         { | ||||
|             // Check whether the invitee is already a member of the group | ||||
|             MembershipData m = m_Database.RetrieveMember(groupID, agentID); | ||||
|             if (m != null) | ||||
|                 return false; | ||||
| 
 | ||||
|             // Check whether there are pending invitations and delete them | ||||
|             InvitationData invite = m_Database.RetrieveInvitation(groupID, agentID); | ||||
|             if (invite != null) | ||||
|                 m_Database.DeleteInvite(invite.InviteID); | ||||
| 
 | ||||
|             invite = new InvitationData(); | ||||
|             invite.InviteID = inviteID; | ||||
|             invite.PrincipalID = agentID; | ||||
|             invite.GroupID = groupID; | ||||
|             invite.RoleID = UUID.Zero; | ||||
|             invite.Data = new Dictionary<string, string>(); | ||||
| 
 | ||||
|             return m_Database.StoreInvitation(invite); | ||||
|         } | ||||
| 
 | ||||
|         private void FillFounderUUI(ExtendedGroupRecord grec) | ||||
|         { | ||||
|             UserAccount account = m_UserAccounts.GetUserAccount(UUID.Zero, grec.FounderID); | ||||
|             if (account != null) | ||||
|                 grec.FounderUUI = Util.UniversalIdentifier(account.PrincipalID, account.FirstName, account.LastName, m_HomeURI); | ||||
|         } | ||||
| 
 | ||||
|         private bool VerifyToken(UUID groupID, string agentID, string token) | ||||
|         { | ||||
|             // check the token | ||||
|             MembershipData membership = m_Database.RetrieveMember(groupID, agentID); | ||||
|             if (membership != null) | ||||
|             { | ||||
|                 if (token != string.Empty && token.Equals(membership.Data["AccessToken"])) | ||||
|                     return true; | ||||
|                 else | ||||
|                     m_log.DebugFormat("[Groups.HGGroupsService]: access token {0} did not match stored one {1}", token, membership.Data["AccessToken"]); | ||||
|             } | ||||
|             else | ||||
|                 m_log.DebugFormat("[Groups.HGGroupsService]: membership not found for {0}", agentID); | ||||
| 
 | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -1,252 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Reflection; | ||||
| using log4net; | ||||
| using Mono.Addins; | ||||
| using Nini.Config; | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Servers; | ||||
| using OpenSim.Framework.Client; | ||||
| using OpenSim.Region.Framework.Interfaces; | ||||
| using OpenSim.Region.Framework.Scenes; | ||||
| using OpenSim.Services.Interfaces; | ||||
| 
 | ||||
| namespace OpenSim.OfflineIM | ||||
| { | ||||
|     [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "OfflineIMConnectorModule")] | ||||
|     public class OfflineIMRegionModule : ISharedRegionModule, IOfflineIMService | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private bool m_Enabled = false; | ||||
|         private List<Scene> m_SceneList = new List<Scene>(); | ||||
|         IMessageTransferModule m_TransferModule = null; | ||||
|         private bool m_ForwardOfflineGroupMessages = true; | ||||
| 
 | ||||
|         private IOfflineIMService m_OfflineIMService; | ||||
| 
 | ||||
|         public void Initialise(IConfigSource config) | ||||
|         { | ||||
|             IConfig cnf = config.Configs["Messaging"]; | ||||
|             if (cnf == null) | ||||
|                 return; | ||||
|             if (cnf != null && cnf.GetString("OfflineMessageModule", string.Empty) != Name) | ||||
|                 return; | ||||
| 
 | ||||
|             m_Enabled = true; | ||||
| 
 | ||||
|             string serviceLocation = cnf.GetString("OfflineMessageURL", string.Empty); | ||||
|             if (serviceLocation == string.Empty) | ||||
|                 m_OfflineIMService = new OfflineIMService(config); | ||||
|             else | ||||
|                 m_OfflineIMService = new OfflineIMServiceRemoteConnector(config); | ||||
| 
 | ||||
|             m_ForwardOfflineGroupMessages = cnf.GetBoolean("ForwardOfflineGroupMessages", m_ForwardOfflineGroupMessages); | ||||
|             m_log.DebugFormat("[OfflineIM.V2]: Offline messages enabled by {0}", Name); | ||||
|         } | ||||
| 
 | ||||
|         public void AddRegion(Scene scene) | ||||
|         { | ||||
|             if (!m_Enabled) | ||||
|                 return; | ||||
| 
 | ||||
|             scene.RegisterModuleInterface<IOfflineIMService>(this); | ||||
|             m_SceneList.Add(scene); | ||||
|             scene.EventManager.OnNewClient += OnNewClient; | ||||
|         } | ||||
| 
 | ||||
|         public void RegionLoaded(Scene scene) | ||||
|         { | ||||
|             if (!m_Enabled) | ||||
|                 return; | ||||
| 
 | ||||
|             if (m_TransferModule == null) | ||||
|             { | ||||
|                 m_TransferModule = scene.RequestModuleInterface<IMessageTransferModule>(); | ||||
|                 if (m_TransferModule == null) | ||||
|                 { | ||||
|                     scene.EventManager.OnNewClient -= OnNewClient; | ||||
| 
 | ||||
|                     m_SceneList.Clear(); | ||||
| 
 | ||||
|                     m_log.Error("[OfflineIM.V2]: No message transfer module is enabled. Disabling offline messages"); | ||||
|                 } | ||||
|                 m_TransferModule.OnUndeliveredMessage += UndeliveredMessage; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveRegion(Scene scene) | ||||
|         { | ||||
|             if (!m_Enabled) | ||||
|                 return; | ||||
| 
 | ||||
|             m_SceneList.Remove(scene); | ||||
|             scene.EventManager.OnNewClient -= OnNewClient; | ||||
|             m_TransferModule.OnUndeliveredMessage -= UndeliveredMessage; | ||||
| 
 | ||||
|             scene.ForEachClient(delegate(IClientAPI client) | ||||
|             { | ||||
|                 client.OnRetrieveInstantMessages -= RetrieveInstantMessages; | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         public void PostInitialise() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         public string Name | ||||
|         { | ||||
|             get { return "Offline Message Module V2"; } | ||||
|         } | ||||
| 
 | ||||
|         public Type ReplaceableInterface | ||||
|         { | ||||
|             get { return null; } | ||||
|         } | ||||
| 
 | ||||
|         public void Close() | ||||
|         { | ||||
|             m_SceneList.Clear(); | ||||
|         } | ||||
| 
 | ||||
|         private Scene FindScene(UUID agentID) | ||||
|         { | ||||
|             foreach (Scene s in m_SceneList) | ||||
|             { | ||||
|                 ScenePresence presence = s.GetScenePresence(agentID); | ||||
|                 if (presence != null && !presence.IsChildAgent) | ||||
|                     return s; | ||||
|             } | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|         private IClientAPI FindClient(UUID agentID) | ||||
|         { | ||||
|             foreach (Scene s in m_SceneList) | ||||
|             { | ||||
|                 ScenePresence presence = s.GetScenePresence(agentID); | ||||
|                 if (presence != null && !presence.IsChildAgent) | ||||
|                     return presence.ControllingClient; | ||||
|             } | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|         private void OnNewClient(IClientAPI client) | ||||
|         { | ||||
|             client.OnRetrieveInstantMessages += RetrieveInstantMessages; | ||||
|         } | ||||
| 
 | ||||
|         private void RetrieveInstantMessages(IClientAPI client) | ||||
|         { | ||||
|             m_log.DebugFormat("[OfflineIM.V2]: Retrieving stored messages for {0}", client.AgentId); | ||||
| 
 | ||||
|             List<GridInstantMessage> msglist = m_OfflineIMService.GetMessages(client.AgentId); | ||||
| 
 | ||||
|             if (msglist == null) | ||||
|                 m_log.DebugFormat("[OfflineIM.V2]: WARNING null message list."); | ||||
| 
 | ||||
|             foreach (GridInstantMessage im in msglist) | ||||
|             { | ||||
|                 if (im.dialog == (byte)InstantMessageDialog.InventoryOffered) | ||||
|                     // send it directly or else the item will be given twice | ||||
|                     client.SendInstantMessage(im); | ||||
|                 else | ||||
|                 { | ||||
|                     // Send through scene event manager so all modules get a chance | ||||
|                     // to look at this message before it gets delivered. | ||||
|                     // | ||||
|                     // Needed for proper state management for stored group | ||||
|                     // invitations | ||||
|                     // | ||||
|                     Scene s = FindScene(client.AgentId); | ||||
|                     if (s != null) | ||||
|                         s.EventManager.TriggerIncomingInstantMessage(im); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private void UndeliveredMessage(GridInstantMessage im) | ||||
|         { | ||||
|             if (im.dialog != (byte)InstantMessageDialog.MessageFromObject && | ||||
|                 im.dialog != (byte)InstantMessageDialog.MessageFromAgent && | ||||
|                 im.dialog != (byte)InstantMessageDialog.GroupNotice && | ||||
|                 im.dialog != (byte)InstantMessageDialog.GroupInvitation && | ||||
|                 im.dialog != (byte)InstantMessageDialog.InventoryOffered) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (!m_ForwardOfflineGroupMessages) | ||||
|             { | ||||
|                 if (im.dialog == (byte)InstantMessageDialog.GroupNotice || | ||||
|                     im.dialog == (byte)InstantMessageDialog.GroupInvitation) | ||||
|                     return; | ||||
|             } | ||||
| 
 | ||||
|             string reason = string.Empty; | ||||
|             bool success = m_OfflineIMService.StoreMessage(im, out reason); | ||||
| 
 | ||||
|             if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent) | ||||
|             { | ||||
|                 IClientAPI client = FindClient(new UUID(im.fromAgentID)); | ||||
|                 if (client == null) | ||||
|                     return; | ||||
| 
 | ||||
|                 client.SendInstantMessage(new GridInstantMessage( | ||||
|                         null, new UUID(im.toAgentID), | ||||
|                         "System", new UUID(im.fromAgentID), | ||||
|                         (byte)InstantMessageDialog.MessageFromAgent, | ||||
|                         "User is not logged in. " + | ||||
|                         (success ? "Message saved." : "Message not saved: " + reason), | ||||
|                         false, new Vector3())); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #region IOfflineIM | ||||
| 
 | ||||
|         public List<GridInstantMessage> GetMessages(UUID principalID) | ||||
|         { | ||||
|             return m_OfflineIMService.GetMessages(principalID); | ||||
|         } | ||||
| 
 | ||||
|         public bool StoreMessage(GridInstantMessage im, out string reason) | ||||
|         { | ||||
|             return m_OfflineIMService.StoreMessage(im, out reason); | ||||
|         } | ||||
| 
 | ||||
|         public void DeleteMessages(UUID userID) | ||||
|         { | ||||
|             m_OfflineIMService.DeleteMessages(userID); | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -1,36 +0,0 @@ | |||
| using System.Reflection; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Runtime.InteropServices; | ||||
| using Mono.Addins; | ||||
| 
 | ||||
| // General Information about an assembly is controlled through the following | ||||
| // set of attributes. Change these attribute values to modify the information | ||||
| // associated with an assembly. | ||||
| [assembly: AssemblyTitle("OpenSim.Addons.OfflineIM")] | ||||
| [assembly: AssemblyDescription("")] | ||||
| [assembly: AssemblyConfiguration("")] | ||||
| [assembly: AssemblyCompany("http://opensimulator.org")] | ||||
| [assembly: AssemblyProduct("OpenSim.Addons.OfflineIM")] | ||||
| [assembly: AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")] | ||||
| [assembly: AssemblyTrademark("")] | ||||
| [assembly: AssemblyCulture("")] | ||||
| 
 | ||||
| // Setting ComVisible to false makes the types in this assembly not visible | ||||
| // to COM components.  If you need to access a type in this assembly from | ||||
| // COM, set the ComVisible attribute to true on that type. | ||||
| [assembly: ComVisible(false)] | ||||
| 
 | ||||
| // The following GUID is for the ID of the typelib if this project is exposed to COM | ||||
| [assembly: Guid("a16a9905-4393-4872-9fca-4c81bedbd9f2")] | ||||
| 
 | ||||
| // Version information for an assembly consists of the following four values: | ||||
| // | ||||
| //      Major Version | ||||
| //      Minor Version | ||||
| //      Build Number | ||||
| //      Revision | ||||
| // | ||||
| [assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)] | ||||
| 
 | ||||
| [assembly: Addin("OpenSim.OfflineIM", OpenSim.VersionInfo.VersionNumber)] | ||||
| [assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] | ||||
|  | @ -1,171 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Reflection; | ||||
| using System.Text; | ||||
| 
 | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.ServiceAuth; | ||||
| using OpenSim.Server.Base; | ||||
| using OpenSim.Services.Interfaces; | ||||
| 
 | ||||
| using OpenMetaverse; | ||||
| using log4net; | ||||
| using Nini.Config; | ||||
| 
 | ||||
| namespace OpenSim.OfflineIM | ||||
| { | ||||
|     public class OfflineIMServiceRemoteConnector : IOfflineIMService | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private string m_ServerURI = string.Empty; | ||||
|         private IServiceAuth m_Auth; | ||||
|         private object m_Lock = new object(); | ||||
| 
 | ||||
|         public OfflineIMServiceRemoteConnector(string url) | ||||
|         { | ||||
|             m_ServerURI = url; | ||||
|             m_log.DebugFormat("[OfflineIM.V2.RemoteConnector]: Offline IM server at {0}", m_ServerURI); | ||||
|         } | ||||
| 
 | ||||
|         public OfflineIMServiceRemoteConnector(IConfigSource config) | ||||
|         { | ||||
|             IConfig cnf = config.Configs["Messaging"]; | ||||
|             if (cnf == null) | ||||
|             { | ||||
|                 m_log.WarnFormat("[OfflineIM.V2.RemoteConnector]: Missing Messaging configuration"); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             m_ServerURI = cnf.GetString("OfflineMessageURL", string.Empty); | ||||
| 
 | ||||
|             /// This is from BaseServiceConnector | ||||
|             string authType = Util.GetConfigVarFromSections<string>(config, "AuthType", new string[] { "Network", "Messaging" }, "None"); | ||||
| 
 | ||||
|             switch (authType) | ||||
|             { | ||||
|                 case "BasicHttpAuthentication": | ||||
|                     m_Auth = new BasicHttpAuthentication(config, "Messaging"); | ||||
|                     break; | ||||
|             } | ||||
|             /// | ||||
|             m_log.DebugFormat("[OfflineIM.V2.RemoteConnector]: Offline IM server at {0} with auth {1}", | ||||
|                 m_ServerURI, (m_Auth == null ? "None" : m_Auth.GetType().ToString())); | ||||
|         } | ||||
| 
 | ||||
|         #region IOfflineIMService | ||||
|         public List<GridInstantMessage> GetMessages(UUID principalID) | ||||
|         { | ||||
|             List<GridInstantMessage> ims = new List<GridInstantMessage>(); | ||||
| 
 | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["PrincipalID"] = principalID; | ||||
|             Dictionary<string, object> ret = MakeRequest("GET", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|                 return ims; | ||||
| 
 | ||||
|             if (!ret.ContainsKey("RESULT")) | ||||
|                 return ims; | ||||
| 
 | ||||
|             string result = ret["RESULT"].ToString(); | ||||
|             if (result == "NULL" || result.ToLower() == "false") | ||||
|             { | ||||
|                 string reason = ret.ContainsKey("REASON") ? ret["REASON"].ToString() : "Unknown error"; | ||||
|                 m_log.DebugFormat("[OfflineIM.V2.RemoteConnector]: GetMessages for {0} failed: {1}", principalID, reason); | ||||
|                 return ims; | ||||
|             } | ||||
| 
 | ||||
|             foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values) | ||||
|             { | ||||
|                 GridInstantMessage m = OfflineIMDataUtils.GridInstantMessage((Dictionary<string, object>)v); | ||||
|                 ims.Add(m); | ||||
|             } | ||||
| 
 | ||||
|             return ims; | ||||
|         } | ||||
| 
 | ||||
|         public bool StoreMessage(GridInstantMessage im, out string reason) | ||||
|         { | ||||
|             reason = string.Empty; | ||||
|             Dictionary<string, object> sendData = OfflineIMDataUtils.GridInstantMessage(im); | ||||
| 
 | ||||
|             Dictionary<string, object> ret = MakeRequest("STORE", sendData); | ||||
| 
 | ||||
|             if (ret == null) | ||||
|             { | ||||
|                 reason = "Bad response from server"; | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             string result = ret["RESULT"].ToString(); | ||||
|             if (result == "NULL" || result.ToLower() == "false") | ||||
|             { | ||||
|                 reason = ret.ContainsKey("REASON") ? ret["REASON"].ToString() : "Unknown error"; | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         public void DeleteMessages(UUID userID) | ||||
|         { | ||||
|             Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||||
|             sendData["UserID"] = userID; | ||||
| 
 | ||||
|             MakeRequest("DELETE", sendData); | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|         #region Make Request | ||||
| 
 | ||||
|         private Dictionary<string, object> MakeRequest(string method, Dictionary<string, object> sendData) | ||||
|         { | ||||
|             sendData["METHOD"] = method; | ||||
| 
 | ||||
|             string reply = string.Empty; | ||||
|             lock (m_Lock) | ||||
|                 reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||||
|                          m_ServerURI + "/offlineim", | ||||
|                          ServerUtils.BuildQueryString(sendData), | ||||
|                          m_Auth); | ||||
| 
 | ||||
|             Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse( | ||||
|                     reply); | ||||
| 
 | ||||
|             return replyData; | ||||
|         } | ||||
|         #endregion | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | @ -1,223 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Reflection; | ||||
| using System.Text; | ||||
| using System.Xml; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using Nini.Config; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Server.Base; | ||||
| using OpenSim.Services.Interfaces; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Framework.ServiceAuth; | ||||
| using OpenSim.Server.Handlers.Base; | ||||
| using log4net; | ||||
| using OpenMetaverse; | ||||
| 
 | ||||
| namespace OpenSim.OfflineIM | ||||
| { | ||||
|     public class OfflineIMServiceRobustConnector : ServiceConnector | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private IOfflineIMService m_OfflineIMService; | ||||
|         private string m_ConfigName = "Messaging"; | ||||
| 
 | ||||
|         public OfflineIMServiceRobustConnector(IConfigSource config, IHttpServer server, string configName) : | ||||
|             base(config, server, configName) | ||||
|         { | ||||
|             if (configName != String.Empty) | ||||
|                 m_ConfigName = configName; | ||||
| 
 | ||||
|             m_log.DebugFormat("[OfflineIM.V2.RobustConnector]: Starting with config name {0}", m_ConfigName); | ||||
| 
 | ||||
|             m_OfflineIMService = new OfflineIMService(config); | ||||
| 
 | ||||
|             IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName); | ||||
| 
 | ||||
|             server.AddStreamHandler(new OfflineIMServicePostHandler(m_OfflineIMService, auth)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public class OfflineIMServicePostHandler : BaseStreamHandler | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private IOfflineIMService m_OfflineIMService; | ||||
| 
 | ||||
|         public OfflineIMServicePostHandler(IOfflineIMService service, IServiceAuth auth) : | ||||
|             base("POST", "/offlineim", auth) | ||||
|         { | ||||
|             m_OfflineIMService = service; | ||||
|         } | ||||
| 
 | ||||
|         protected override byte[] ProcessRequest(string path, Stream requestData, | ||||
|                 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||||
|         { | ||||
|             StreamReader sr = new StreamReader(requestData); | ||||
|             string body = sr.ReadToEnd(); | ||||
|             sr.Close(); | ||||
|             body = body.Trim(); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: query String: {0}", body); | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 Dictionary<string, object> request = | ||||
|                         ServerUtils.ParseQueryString(body); | ||||
| 
 | ||||
|                 if (!request.ContainsKey("METHOD")) | ||||
|                     return FailureResult(); | ||||
| 
 | ||||
|                 string method = request["METHOD"].ToString(); | ||||
|                 request.Remove("METHOD"); | ||||
| 
 | ||||
|                 switch (method) | ||||
|                 { | ||||
|                     case "GET": | ||||
|                         return HandleGet(request); | ||||
|                     case "STORE": | ||||
|                         return HandleStore(request); | ||||
|                     case "DELETE": | ||||
|                         return HandleDelete(request); | ||||
|                 } | ||||
|                 m_log.DebugFormat("[OFFLINE IM HANDLER]: unknown method request: {0}", method); | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 m_log.Error(string.Format("[OFFLINE IM HANDLER]: Exception {0} ", e.Message), e); | ||||
|             } | ||||
| 
 | ||||
|             return FailureResult(); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleStore(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             GridInstantMessage im = OfflineIMDataUtils.GridInstantMessage(request); | ||||
| 
 | ||||
|             string reason = string.Empty; | ||||
| 
 | ||||
|             bool success = m_OfflineIMService.StoreMessage(im, out reason); | ||||
| 
 | ||||
|             result["RESULT"] = success.ToString(); | ||||
|             if (!success) | ||||
|                 result["REASON"] = reason; | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleGet(Dictionary<string, object> request) | ||||
|         { | ||||
|             Dictionary<string, object> result = new Dictionary<string, object>(); | ||||
| 
 | ||||
|             if (!request.ContainsKey("PrincipalID")) | ||||
|                 NullResult(result, "Bad network data"); | ||||
|             else | ||||
|             { | ||||
|                 UUID principalID = new UUID(request["PrincipalID"].ToString()); | ||||
|                 List<GridInstantMessage> ims = m_OfflineIMService.GetMessages(principalID); | ||||
| 
 | ||||
|                 Dictionary<string, object> dict = new Dictionary<string, object>(); | ||||
|                 int i = 0; | ||||
|                 foreach (GridInstantMessage m in ims) | ||||
|                     dict["im-" + i++] = OfflineIMDataUtils.GridInstantMessage(m); | ||||
| 
 | ||||
|                 result["RESULT"] = dict; | ||||
|             } | ||||
| 
 | ||||
|             string xmlString = ServerUtils.BuildXmlResponse(result); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(xmlString); | ||||
|         } | ||||
| 
 | ||||
|         byte[] HandleDelete(Dictionary<string, object> request) | ||||
|         { | ||||
|             if (!request.ContainsKey("UserID")) | ||||
|             { | ||||
|                 return FailureResult(); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 UUID userID = new UUID(request["UserID"].ToString()); | ||||
|                 m_OfflineIMService.DeleteMessages(userID); | ||||
| 
 | ||||
|                 return SuccessResult(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #region Helpers | ||||
| 
 | ||||
|         private void NullResult(Dictionary<string, object> result, string reason) | ||||
|         { | ||||
|             result["RESULT"] = "NULL"; | ||||
|             result["REASON"] = reason; | ||||
|         } | ||||
| 
 | ||||
|         private byte[] FailureResult() | ||||
|         { | ||||
|             return BoolResult(false); | ||||
|         } | ||||
| 
 | ||||
|         private byte[] SuccessResult() | ||||
|         { | ||||
|             return BoolResult(true); | ||||
|         } | ||||
| 
 | ||||
|         private byte[] BoolResult(bool value) | ||||
|         { | ||||
|             XmlDocument doc = new XmlDocument(); | ||||
| 
 | ||||
|             XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration, | ||||
|                     "", ""); | ||||
| 
 | ||||
|             doc.AppendChild(xmlnode); | ||||
| 
 | ||||
|             XmlElement rootElement = doc.CreateElement("", "ServerResponse", | ||||
|                     ""); | ||||
| 
 | ||||
|             doc.AppendChild(rootElement); | ||||
| 
 | ||||
|             XmlElement result = doc.CreateElement("", "RESULT", ""); | ||||
|             result.AppendChild(doc.CreateTextNode(value.ToString())); | ||||
| 
 | ||||
|             rootElement.AppendChild(result); | ||||
| 
 | ||||
|             return Util.DocToBytes(doc); | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
|     } | ||||
| } | ||||
|  | @ -1,134 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Reflection; | ||||
| using System.Runtime.Serialization; | ||||
| using System.Text; | ||||
| using System.Timers; | ||||
| using System.Xml; | ||||
| using System.Xml.Serialization; | ||||
| using log4net; | ||||
| using Nini.Config; | ||||
| 
 | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Data; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Services.Interfaces; | ||||
| 
 | ||||
| namespace OpenSim.OfflineIM | ||||
| { | ||||
|     public class OfflineIMService : OfflineIMServiceBase, IOfflineIMService | ||||
|     { | ||||
| //        private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
|         private const int MAX_IM = 25; | ||||
| 
 | ||||
|         private XmlSerializer m_serializer; | ||||
|         private static bool m_Initialized = false; | ||||
| 
 | ||||
|         public OfflineIMService(IConfigSource config) | ||||
|             : base(config) | ||||
|         { | ||||
|             m_serializer = new XmlSerializer(typeof(GridInstantMessage)); | ||||
|             if (!m_Initialized) | ||||
|             { | ||||
|                 m_Database.DeleteOld(); | ||||
|                 m_Initialized = true; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public List<GridInstantMessage> GetMessages(UUID principalID) | ||||
|         { | ||||
|             List<GridInstantMessage> ims = new List<GridInstantMessage>(); | ||||
| 
 | ||||
|             OfflineIMData[] messages = m_Database.Get("PrincipalID", principalID.ToString()); | ||||
| 
 | ||||
|             if (messages == null || (messages != null && messages.Length == 0)) | ||||
|                 return ims; | ||||
| 
 | ||||
|             foreach (OfflineIMData m in messages) | ||||
|             { | ||||
|                 using (MemoryStream mstream = new MemoryStream(Encoding.UTF8.GetBytes(m.Data["Message"]))) | ||||
|                 { | ||||
|                     GridInstantMessage im = (GridInstantMessage)m_serializer.Deserialize(mstream); | ||||
|                     ims.Add(im); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // Then, delete them | ||||
|             m_Database.Delete("PrincipalID", principalID.ToString()); | ||||
| 
 | ||||
|             return ims; | ||||
|         } | ||||
| 
 | ||||
|         public bool StoreMessage(GridInstantMessage im, out string reason) | ||||
|         { | ||||
|             reason = string.Empty; | ||||
| 
 | ||||
|             // Check limits | ||||
|             UUID principalID = new UUID(im.toAgentID); | ||||
|             long count = m_Database.GetCount("PrincipalID", principalID.ToString()); | ||||
|             if (count >= MAX_IM) | ||||
|             { | ||||
|                 reason = "Number of offline IMs has maxed out"; | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             string imXml; | ||||
|             using (MemoryStream mstream = new MemoryStream()) | ||||
|             { | ||||
|                 XmlWriterSettings settings = new XmlWriterSettings(); | ||||
|                 settings.Encoding = Util.UTF8NoBomEncoding; | ||||
| 
 | ||||
|                 using (XmlWriter writer = XmlWriter.Create(mstream, settings)) | ||||
|                 { | ||||
|                     m_serializer.Serialize(writer, im); | ||||
|                     writer.Flush(); | ||||
|                     imXml = Util.UTF8NoBomEncoding.GetString(mstream.ToArray()); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             OfflineIMData data = new OfflineIMData(); | ||||
|             data.PrincipalID = principalID; | ||||
|             data.FromID = new UUID(im.fromAgentID); | ||||
|             data.Data = new Dictionary<string, string>(); | ||||
|             data.Data["Message"] = imXml; | ||||
| 
 | ||||
|             return m_Database.Store(data); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         public void DeleteMessages(UUID userID) | ||||
|         { | ||||
|             m_Database.Delete("PrincipalID", userID.ToString()); | ||||
|             m_Database.Delete("FromID", userID.ToString()); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | @ -32,17 +32,16 @@ using System.Threading; | |||
| using log4net; | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.RegionLoader.Filesystem; | ||||
| using OpenSim.Framework.RegionLoader.Web; | ||||
| using OpenSim.Region.CoreModules.Agent.AssetTransaction; | ||||
| using OpenSim.Region.CoreModules.Avatar.InstantMessage; | ||||
| using OpenSim.Region.CoreModules.Scripting.DynamicTexture; | ||||
| using OpenSim.Region.CoreModules.Scripting.LoadImageURL; | ||||
| using OpenSim.Region.CoreModules.Scripting.XMLRPC; | ||||
| using OpenSim.Services.Interfaces; | ||||
| using Mono.Addins; | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.LoadRegions | ||||
| { | ||||
|     [Extension(Path="/OpenSim/Startup", Id="LoadRegions", NodeName="Plugin")] | ||||
|     public class LoadRegionsPlugin : IApplicationPlugin, IRegionCreator | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
|  | @ -100,12 +99,12 @@ namespace OpenSim.ApplicationPlugins.LoadRegions | |||
|             RegionInfo[] regionsToLoad = regionLoader.LoadRegions(); | ||||
| 
 | ||||
|             m_log.Info("[LOAD REGIONS PLUGIN]: Loading specific shared modules..."); | ||||
|             //m_log.Info("[LOAD REGIONS PLUGIN]: DynamicTextureModule..."); | ||||
|             //m_openSim.ModuleLoader.LoadDefaultSharedModule(new DynamicTextureModule()); | ||||
|             //m_log.Info("[LOAD REGIONS PLUGIN]: LoadImageURLModule..."); | ||||
|             //m_openSim.ModuleLoader.LoadDefaultSharedModule(new LoadImageURLModule()); | ||||
|             //m_log.Info("[LOAD REGIONS PLUGIN]: XMLRPCModule..."); | ||||
|             //m_openSim.ModuleLoader.LoadDefaultSharedModule(new XMLRPCModule()); | ||||
|             m_log.Info("[LOAD REGIONS PLUGIN]: DynamicTextureModule..."); | ||||
|             m_openSim.ModuleLoader.LoadDefaultSharedModule(new DynamicTextureModule()); | ||||
|             m_log.Info("[LOAD REGIONS PLUGIN]: LoadImageURLModule..."); | ||||
|             m_openSim.ModuleLoader.LoadDefaultSharedModule(new LoadImageURLModule()); | ||||
|             m_log.Info("[LOAD REGIONS PLUGIN]: XMLRPCModule..."); | ||||
|             m_openSim.ModuleLoader.LoadDefaultSharedModule(new XMLRPCModule()); | ||||
| //            m_log.Info("[LOADREGIONSPLUGIN]: AssetTransactionModule..."); | ||||
| //            m_openSim.ModuleLoader.LoadDefaultSharedModule(new AssetTransactionModule()); | ||||
|             m_log.Info("[LOAD REGIONS PLUGIN]: Done."); | ||||
|  | @ -116,34 +115,29 @@ namespace OpenSim.ApplicationPlugins.LoadRegions | |||
|                 Environment.Exit(1); | ||||
|             } | ||||
| 
 | ||||
|             List<IScene> createdScenes = new List<IScene>(); | ||||
| 
 | ||||
|             for (int i = 0; i < regionsToLoad.Length; i++) | ||||
|             { | ||||
|                 IScene scene; | ||||
|                 m_log.Debug("[LOAD REGIONS PLUGIN]: Creating Region: " + regionsToLoad[i].RegionName + " (ThreadID: " + | ||||
|                             Thread.CurrentThread.ManagedThreadId.ToString() + | ||||
|                             ")"); | ||||
| 
 | ||||
|                 bool changed = m_openSim.PopulateRegionEstateInfo(regionsToLoad[i]); | ||||
| 
 | ||||
|                  | ||||
|                 m_openSim.PopulateRegionEstateInfo(regionsToLoad[i]); | ||||
|                 m_openSim.CreateRegion(regionsToLoad[i], true, out scene); | ||||
|                 createdScenes.Add(scene); | ||||
| 
 | ||||
|                 if (changed) | ||||
|                     m_openSim.EstateDataService.StoreEstateSettings(regionsToLoad[i].EstateSettings); | ||||
|             } | ||||
| 
 | ||||
|             foreach (IScene scene in createdScenes) | ||||
|             { | ||||
|                 scene.Start(); | ||||
| 
 | ||||
|                 m_newRegionCreatedHandler = OnNewRegionCreated; | ||||
|                 if (m_newRegionCreatedHandler != null) | ||||
|                 regionsToLoad[i].EstateSettings.Save(); | ||||
|                  | ||||
|                 if (scene != null) | ||||
|                 { | ||||
|                     m_newRegionCreatedHandler(scene); | ||||
|                     m_newRegionCreatedHandler = OnNewRegionCreated; | ||||
|                     if (m_newRegionCreatedHandler != null) | ||||
|                     { | ||||
|                         m_newRegionCreatedHandler(scene); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             m_openSim.ModuleLoader.PostInitialise(); | ||||
|             m_openSim.ModuleLoader.ClearCache(); | ||||
|         } | ||||
| 
 | ||||
|         public void Dispose() | ||||
|  |  | |||
|  | @ -27,17 +27,16 @@ | |||
| 
 | ||||
| using System.Reflection; | ||||
| using System.Runtime.InteropServices; | ||||
| using Mono.Addins; | ||||
| 
 | ||||
| // General information about an assembly is controlled through the following | ||||
| // set of attributes. Change these attribute values to modify the information | ||||
| // associated with an assembly. | ||||
| 
 | ||||
| [assembly : AssemblyTitle("OpenSim.ApplicationPlugins.LoadRegions")] | ||||
| [assembly : AssemblyTitle("OpenSim.Addin")] | ||||
| [assembly : AssemblyDescription("")] | ||||
| [assembly : AssemblyConfiguration("")] | ||||
| [assembly : AssemblyCompany("http://opensimulator.org")] | ||||
| [assembly : AssemblyProduct("OpenSim")] | ||||
| [assembly : AssemblyProduct("OpenSim.Addin")] | ||||
| [assembly : AssemblyCopyright("Copyright © OpenSimulator.org Developers 2007-2009")] | ||||
| [assembly : AssemblyTrademark("")] | ||||
| [assembly : AssemblyCulture("")] | ||||
|  | @ -61,8 +60,7 @@ using Mono.Addins; | |||
| // | ||||
| // You can specify all the values or you can default the Build and Revision Numbers | ||||
| // by using the '*' as shown below: | ||||
| // [assembly: AssemblyVersion("0.6.5.*")] | ||||
| 
 | ||||
| [assembly : AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)] | ||||
| 
 | ||||
| [assembly: Addin("OpenSim.ApplicationPlugins.LoadRegions", OpenSim.VersionInfo.VersionNumber)] | ||||
| [assembly: AddinDependency("OpenSim", OpenSim.VersionInfo.VersionNumber)] | ||||
| [assembly : AssemblyVersion("0.6.5.*")] | ||||
| [assembly : AssemblyFileVersion("0.6.5.0")] | ||||
|  | @ -1,143 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.IO; | ||||
| using System.Net; | ||||
| using System.Reflection; | ||||
| using System.Xml; | ||||
| using log4net; | ||||
| using Nini.Config; | ||||
| using OpenSim.Framework; | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.LoadRegions | ||||
| { | ||||
|     public class RegionLoaderWebServer : IRegionLoader | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private IConfigSource m_configSource; | ||||
| 
 | ||||
|         public void SetIniConfigSource(IConfigSource configSource) | ||||
|         { | ||||
|             m_configSource = configSource; | ||||
|         } | ||||
| 
 | ||||
|         public RegionInfo[] LoadRegions() | ||||
|         { | ||||
|             int tries = 3; | ||||
|             int wait = 2000; | ||||
| 
 | ||||
|             if (m_configSource == null) | ||||
|             { | ||||
|                 m_log.Error("[WEBLOADER]: Unable to load configuration source!"); | ||||
|                 return null; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 IConfig startupConfig = (IConfig)m_configSource.Configs["Startup"]; | ||||
|                 string url = startupConfig.GetString("regionload_webserver_url", String.Empty).Trim(); | ||||
|                 bool allowRegionless = startupConfig.GetBoolean("allow_regionless", false); | ||||
| 
 | ||||
|                 if (url == String.Empty) | ||||
|                 { | ||||
|                     m_log.Error("[WEBLOADER]: Unable to load webserver URL - URL was empty."); | ||||
|                     return null; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     while (tries > 0) | ||||
|                     { | ||||
|                         RegionInfo[] regionInfos = new RegionInfo[] { }; | ||||
|                         int regionCount = 0; | ||||
|                         HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url); | ||||
|                         webRequest.Timeout = 30000; //30 Second Timeout | ||||
|                         m_log.DebugFormat("[WEBLOADER]: Sending download request to {0}", url); | ||||
| 
 | ||||
|                         try | ||||
|                         { | ||||
|                             HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse(); | ||||
|                             m_log.Debug("[WEBLOADER]: Downloading region information..."); | ||||
|                             StreamReader reader = new StreamReader(webResponse.GetResponseStream()); | ||||
|                             string xmlSource = String.Empty; | ||||
|                             string tempStr = reader.ReadLine(); | ||||
|                             while (tempStr != null) | ||||
|                             { | ||||
|                                 xmlSource = xmlSource + tempStr; | ||||
|                                 tempStr = reader.ReadLine(); | ||||
|                             } | ||||
|                             m_log.Debug("[WEBLOADER]: Done downloading region information from server. Total Bytes: " + | ||||
|                                         xmlSource.Length); | ||||
|                             XmlDocument xmlDoc = new XmlDocument(); | ||||
|                             xmlDoc.LoadXml(xmlSource); | ||||
|                             if (xmlDoc.FirstChild.Name == "Nini") | ||||
|                             { | ||||
|                                 regionCount = xmlDoc.FirstChild.ChildNodes.Count; | ||||
| 
 | ||||
|                                 if (regionCount > 0) | ||||
|                                 { | ||||
|                                     regionInfos = new RegionInfo[regionCount]; | ||||
|                                     int i; | ||||
|                                     for (i = 0; i < xmlDoc.FirstChild.ChildNodes.Count; i++) | ||||
|                                     { | ||||
|                                         m_log.Debug(xmlDoc.FirstChild.ChildNodes[i].OuterXml); | ||||
|                                         regionInfos[i] = | ||||
|                                             new RegionInfo("REGION CONFIG #" + (i + 1), xmlDoc.FirstChild.ChildNodes[i], false, m_configSource); | ||||
|                                     } | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                         catch (WebException ex) | ||||
|                         { | ||||
|                             if (((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.NotFound) | ||||
|                             { | ||||
|                                 if (!allowRegionless) | ||||
|                                     throw ex; | ||||
|                             } | ||||
|                             else | ||||
|                                 throw ex; | ||||
|                         } | ||||
| 
 | ||||
|                         if (regionCount > 0 || allowRegionless) | ||||
|                             return regionInfos; | ||||
| 
 | ||||
|                         m_log.Debug("[WEBLOADER]: Request yielded no regions."); | ||||
|                         tries--; | ||||
|                         if (tries > 0) | ||||
|                         { | ||||
|                             m_log.Debug("[WEBLOADER]: Retrying"); | ||||
|                             System.Threading.Thread.Sleep(wait); | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     m_log.Error("[WEBLOADER]: No region configs were available."); | ||||
|                     return null; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,11 @@ | |||
| <Addin id="OpenSim.ApplicationPlugins.LoadRegions" version="0.1"> | ||||
|     <Runtime> | ||||
|         <Import assembly="OpenSim.ApplicationPlugins.LoadRegions.dll"/> | ||||
|     </Runtime> | ||||
|     <Dependencies> | ||||
|         <Addin id="OpenSim" version="0.5" /> | ||||
|     </Dependencies> | ||||
|     <Extension path = "/OpenSim/Startup"> | ||||
|         <Plugin id="LoadRegions" type="OpenSim.ApplicationPlugins.LoadRegions.LoadRegionsPlugin" /> | ||||
|     </Extension> | ||||
| </Addin> | ||||
|  | @ -1,36 +0,0 @@ | |||
| using System.Reflection; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Runtime.InteropServices; | ||||
| using Mono.Addins; | ||||
| 
 | ||||
| // General Information about an assembly is controlled through the following | ||||
| // set of attributes. Change these attribute values to modify the information | ||||
| // associated with an assembly. | ||||
| [assembly: AssemblyTitle("OpenSim.ApplicationPlugins.RegionModulesController")] | ||||
| [assembly: AssemblyDescription("")] | ||||
| [assembly: AssemblyConfiguration("")] | ||||
| [assembly: AssemblyCompany("http://opensimulator.org")] | ||||
| [assembly: AssemblyProduct("OpenSim")] | ||||
| [assembly: AssemblyCopyright("OpenSimulator developers")] | ||||
| [assembly: AssemblyTrademark("")] | ||||
| [assembly: AssemblyCulture("")] | ||||
| 
 | ||||
| // Setting ComVisible to false makes the types in this assembly not visible | ||||
| // to COM components.  If you need to access a type in this assembly from | ||||
| // COM, set the ComVisible attribute to true on that type. | ||||
| [assembly: ComVisible(false)] | ||||
| 
 | ||||
| // The following GUID is for the ID of the typelib if this project is exposed to COM | ||||
| [assembly: Guid("c023816d-194e-40c1-9195-a0f281d4ac5d")] | ||||
| 
 | ||||
| // Version information for an assembly consists of the following four values: | ||||
| // | ||||
| //      Major Version | ||||
| //      Minor Version | ||||
| //      Build Number | ||||
| //      Revision | ||||
| // | ||||
| [assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)] | ||||
| 
 | ||||
| [assembly: Addin("OpenSim.ApplicationPlugins.RegionModulesController", OpenSim.VersionInfo.VersionNumber)] | ||||
| [assembly: AddinDependency("OpenSim", OpenSim.VersionInfo.VersionNumber)] | ||||
|  | @ -32,13 +32,11 @@ using log4net; | |||
| using Mono.Addins; | ||||
| using Nini.Config; | ||||
| using OpenSim; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Region.Framework.Interfaces; | ||||
| using OpenSim.Region.Framework.Scenes; | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.RegionModulesController | ||||
| { | ||||
|     [Extension(Path = "/OpenSim/Startup", Id = "LoadRegions", NodeName = "Plugin")] | ||||
|     public class RegionModulesControllerPlugin : IRegionModulesController, | ||||
|             IApplicationPlugin | ||||
|     { | ||||
|  | @ -47,12 +45,6 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
|                 LogManager.GetLogger( | ||||
|                 MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Controls whether we load modules from Mono.Addins. | ||||
|         /// </summary> | ||||
|         /// <remarks>For debug purposes.  Defaults to true.</remarks> | ||||
|         public bool LoadModulesFromAddins { get; set; } | ||||
| 
 | ||||
|         // Config access | ||||
|         private OpenSimBase m_openSim; | ||||
| 
 | ||||
|  | @ -69,22 +61,14 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
|         private List<ISharedRegionModule> m_sharedInstances = | ||||
|                 new List<ISharedRegionModule>(); | ||||
| 
 | ||||
|         public RegionModulesControllerPlugin() | ||||
|         { | ||||
|             LoadModulesFromAddins = true; | ||||
|         } | ||||
| 
 | ||||
| #region IApplicationPlugin implementation | ||||
| 
 | ||||
|          | ||||
|         public void Initialise (OpenSimBase openSim) | ||||
|         { | ||||
|             m_openSim = openSim; | ||||
|             m_openSim.ApplicationRegistry.RegisterInterface<IRegionModulesController>(this); | ||||
|             m_log.DebugFormat("[REGIONMODULES]: Initializing..."); | ||||
| 
 | ||||
|             if (!LoadModulesFromAddins) | ||||
|                 return; | ||||
| 
 | ||||
|             // Who we are | ||||
|             string id = AddinManager.CurrentAddin.Id; | ||||
| 
 | ||||
|  | @ -101,20 +85,30 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
|             if (modulesConfig == null) | ||||
|                 modulesConfig = m_openSim.ConfigSource.Source.AddConfig("Modules"); | ||||
| 
 | ||||
|             Dictionary<RuntimeAddin, IList<int>> loadedModules = new Dictionary<RuntimeAddin, IList<int>>(); | ||||
| 
 | ||||
|             // Scan modules and load all that aren't disabled | ||||
|             foreach (TypeExtensionNode node in AddinManager.GetExtensionNodes("/OpenSim/RegionModules")) | ||||
|                 AddNode(node, modulesConfig, loadedModules); | ||||
| 
 | ||||
|             foreach (KeyValuePair<RuntimeAddin, IList<int>> loadedModuleData in loadedModules) | ||||
|             foreach (TypeExtensionNode node in | ||||
|                     AddinManager.GetExtensionNodes("/OpenSim/RegionModules")) | ||||
|             { | ||||
|                 m_log.InfoFormat( | ||||
|                     "[REGIONMODULES]: From plugin {0}, (version {1}), loaded {2} modules, {3} shared, {4} non-shared {5} unknown", | ||||
|                     loadedModuleData.Key.Id, | ||||
|                     loadedModuleData.Key.Version, | ||||
|                     loadedModuleData.Value[0] + loadedModuleData.Value[1] + loadedModuleData.Value[2], | ||||
|                     loadedModuleData.Value[0], loadedModuleData.Value[1], loadedModuleData.Value[2]); | ||||
|                 if (node.Type.GetInterface(typeof(ISharedRegionModule).ToString()) != null) | ||||
|                 { | ||||
|                     if (CheckModuleEnabled(node, modulesConfig)) | ||||
|                     { | ||||
|                         m_log.DebugFormat("[REGIONMODULES]: Found shared region module {0}, class {1}", node.Id, node.Type); | ||||
|                         m_sharedModules.Add(node); | ||||
|                     } | ||||
|                 } | ||||
|                 else if (node.Type.GetInterface(typeof(INonSharedRegionModule).ToString()) != null) | ||||
|                 { | ||||
|                     if (CheckModuleEnabled(node, modulesConfig)) | ||||
|                     { | ||||
|                         m_log.DebugFormat("[REGIONMODULES]: Found non-shared region module {0}, class {1}", node.Id, node.Type); | ||||
|                         m_nonSharedModules.Add(node); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     m_log.DebugFormat("[REGIONMODULES]: Found unknown type of module {0}, class {1}", node.Id, node.Type); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // Load and init the module. We try a constructor with a port | ||||
|  | @ -131,9 +125,6 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
|                 // Read the config again | ||||
|                 string moduleString = | ||||
|                         modulesConfig.GetString("Setup_" + node.Id, String.Empty); | ||||
|                 // Test to see if we want this module | ||||
|                 if (moduleString == "disabled") | ||||
|                     continue; | ||||
| 
 | ||||
|                 // Get the port number, if there is one | ||||
|                 if (moduleString != String.Empty) | ||||
|  | @ -181,41 +172,6 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
| 
 | ||||
| #region IPlugin implementation | ||||
| 
 | ||||
|         private void AddNode( | ||||
|             TypeExtensionNode node, IConfig modulesConfig, Dictionary<RuntimeAddin, IList<int>> loadedModules) | ||||
|         { | ||||
|             IList<int> loadedModuleData; | ||||
| 
 | ||||
|             if (!loadedModules.ContainsKey(node.Addin)) | ||||
|                 loadedModules.Add(node.Addin, new List<int> { 0, 0, 0 }); | ||||
| 
 | ||||
|             loadedModuleData = loadedModules[node.Addin]; | ||||
| 
 | ||||
|             if (node.Type.GetInterface(typeof(ISharedRegionModule).ToString()) != null) | ||||
|             { | ||||
|                 if (CheckModuleEnabled(node, modulesConfig)) | ||||
|                 { | ||||
|                     m_log.DebugFormat("[REGIONMODULES]: Found shared region module {0}, class {1}", node.Id, node.Type); | ||||
|                     m_sharedModules.Add(node); | ||||
|                     loadedModuleData[0]++; | ||||
|                 } | ||||
|             } | ||||
|             else if (node.Type.GetInterface(typeof(INonSharedRegionModule).ToString()) != null) | ||||
|             { | ||||
|                 if (CheckModuleEnabled(node, modulesConfig)) | ||||
|                 { | ||||
|                     m_log.DebugFormat("[REGIONMODULES]: Found non-shared region module {0}, class {1}", node.Id, node.Type); | ||||
|                     m_nonSharedModules.Add(node); | ||||
|                     loadedModuleData[1]++; | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 m_log.WarnFormat("[REGIONMODULES]: Found unknown type of module {0}, class {1}", node.Id, node.Type); | ||||
|                 loadedModuleData[2]++; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // We don't do that here | ||||
|         // | ||||
|         public void Initialise () | ||||
|  | @ -237,7 +193,6 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
|                 m_sharedInstances[0].Close(); | ||||
|                 m_sharedInstances.RemoveAt(0); | ||||
|             } | ||||
| 
 | ||||
|             m_sharedModules.Clear(); | ||||
|             m_nonSharedModules.Clear(); | ||||
|         } | ||||
|  | @ -260,8 +215,8 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
|             } | ||||
|         } | ||||
| 
 | ||||
| #region Region Module interfacesController implementation | ||||
| 
 | ||||
| #region IRegionModulesController implementation | ||||
|          | ||||
|         /// <summary> | ||||
|         /// Check that the given module is no disabled in the [Modules] section of the config files. | ||||
|         /// </summary> | ||||
|  | @ -293,10 +248,10 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
|                 if (className != String.Empty && | ||||
|                         node.Type.ToString() != className) | ||||
|                     return false; | ||||
|             } | ||||
| 
 | ||||
|             }             | ||||
|              | ||||
|             return true; | ||||
|         } | ||||
|         }         | ||||
| 
 | ||||
|         // The root of all evil. | ||||
|         // This is where we handle adding the modules to scenes when they | ||||
|  | @ -368,10 +323,6 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
|                 string moduleString = | ||||
|                         modulesConfig.GetString("Setup_" + node.Id, String.Empty); | ||||
| 
 | ||||
|                 // We may not want to load this at all | ||||
|                 if (moduleString == "disabled") | ||||
|                     continue; | ||||
| 
 | ||||
|                 // Get the port number, if there is one | ||||
|                 if (moduleString != String.Empty) | ||||
|                 { | ||||
|  | @ -509,8 +460,6 @@ namespace OpenSim.ApplicationPlugins.RegionModulesController | |||
|             { | ||||
|                 module.RegionLoaded(scene); | ||||
|             } | ||||
| 
 | ||||
|             scene.AllModulesLoaded(); | ||||
|         } | ||||
| 
 | ||||
|         public void RemoveRegionFromModules (Scene scene) | ||||
|  |  | |||
|  | @ -0,0 +1,13 @@ | |||
| <Addin id="OpenSim.ApplicationPlugins.RegionModulesController" version="0.1"> | ||||
|     <Runtime> | ||||
|         <Import assembly="OpenSim.ApplicationPlugins.RegionModulesController.dll"/> | ||||
|     </Runtime> | ||||
| 
 | ||||
|     <Dependencies> | ||||
|         <Addin id="OpenSim" version="0.5" /> | ||||
|     </Dependencies> | ||||
| 
 | ||||
|     <Extension path = "/OpenSim/Startup"> | ||||
|         <Plugin id="RegionModulesController" type="OpenSim.ApplicationPlugins.RegionModulesController.RegionModulesControllerPlugin" /> | ||||
|     </Extension> | ||||
| </Addin> | ||||
|  | @ -1,36 +0,0 @@ | |||
| using System.Reflection; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Runtime.InteropServices; | ||||
| using Mono.Addins; | ||||
| 
 | ||||
| // General Information about an assembly is controlled through the following | ||||
| // set of attributes. Change these attribute values to modify the information | ||||
| // associated with an assembly. | ||||
| [assembly: AssemblyTitle("OpenSim.ApplicationPlugins.RemoteController")] | ||||
| [assembly: AssemblyDescription("")] | ||||
| [assembly: AssemblyConfiguration("")] | ||||
| [assembly: AssemblyCompany("http://opensimulator.org")] | ||||
| [assembly: AssemblyProduct("OpenSim")] | ||||
| [assembly: AssemblyCopyright("Copyright OpenSimulator developers ©  2012")] | ||||
| [assembly: AssemblyTrademark("")] | ||||
| [assembly: AssemblyCulture("")] | ||||
| 
 | ||||
| // Setting ComVisible to false makes the types in this assembly not visible | ||||
| // to COM components.  If you need to access a type in this assembly from | ||||
| // COM, set the ComVisible attribute to true on that type. | ||||
| [assembly: ComVisible(false)] | ||||
| 
 | ||||
| // The following GUID is for the ID of the typelib if this project is exposed to COM | ||||
| [assembly: Guid("efec6e69-fc4a-4e21-86e6-4a261c12d4db")] | ||||
| 
 | ||||
| // Version information for an assembly consists of the following four values: | ||||
| // | ||||
| //      Major Version | ||||
| //      Minor Version | ||||
| //      Build Number | ||||
| //      Revision | ||||
| // | ||||
| [assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)] | ||||
| 
 | ||||
| [assembly: Addin("OpenSim.ApplicationPlugins.RemoteController", OpenSim.VersionInfo.VersionNumber)] | ||||
| [assembly: AddinDependency("OpenSim", OpenSim.VersionInfo.VersionNumber)] | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -0,0 +1,11 @@ | |||
| <Addin id="OpenSim.ApplicationPlugins.RemoteController" version="0.1"> | ||||
|     <Runtime> | ||||
|         <Import assembly="OpenSim.ApplicationPlugins.RemoteController.dll"/> | ||||
|     </Runtime> | ||||
|     <Dependencies> | ||||
|         <Addin id="OpenSim" version="0.5" /> | ||||
|     </Dependencies> | ||||
|     <Extension path = "/OpenSim/Startup"> | ||||
|         <Plugin id="RemoteController" type="OpenSim.ApplicationPlugins.RemoteController.RemoteAdminPlugin" /> | ||||
|     </Extension> | ||||
| </Addin> | ||||
|  | @ -0,0 +1,43 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.Rest.Inventory | ||||
| { | ||||
|     /// <summary> | ||||
|     /// This interface represents the boundary between the general purpose | ||||
|     /// REST plugin handling, and the functionally specific handlers. The | ||||
|     /// handler knows only to initialize and terminate all such handlers  | ||||
|     /// that it finds. Implementing this interface identifies the class as | ||||
|     /// a REST handler implementation. | ||||
|     /// </summary> | ||||
| 
 | ||||
|     internal interface IRest | ||||
|     { | ||||
|         void Initialize(); | ||||
|         void Close(); | ||||
|     } | ||||
| } | ||||
|  | @ -25,24 +25,35 @@ | |||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| 
 | ||||
| namespace OpenSim.Framework.Console | ||||
| namespace OpenSim.ApplicationPlugins.Rest.Inventory | ||||
| { | ||||
| 
 | ||||
|     /// <remarks> | ||||
|     /// The handler delegates are not noteworthy. The allocator allows | ||||
|     /// a given handler to optionally subclass the base RequestData | ||||
|     /// structure to carry any locally required per-request state | ||||
|     /// needed. | ||||
|     /// </remarks> | ||||
| 
 | ||||
|     public delegate void        RestMethodHandler(RequestData rdata); | ||||
|     public delegate RequestData RestMethodAllocator(OSHttpRequest request, OSHttpResponse response, string path); | ||||
| 
 | ||||
|     /// <summary> | ||||
|     /// This will be a set of typical column sizes to allow greater consistency between console commands. | ||||
|     /// This interface exports the generic plugin-handling services | ||||
|     /// available to each loaded REST services module (IRest implementation) | ||||
|     /// </summary> | ||||
|     public static class ConsoleDisplayUtil | ||||
| 
 | ||||
|     internal interface IRestHandler | ||||
|     { | ||||
|         public const int CoordTupleSize = 11; | ||||
|         public const int PortSize = 5; | ||||
| 
 | ||||
|         public const int EstateNameSize = 20; | ||||
|         public const int ParcelNameSize = 40; | ||||
|         public const int RegionNameSize = 20; | ||||
|         public const int UserNameSize = 35; | ||||
|         string MsgId     { get; } | ||||
|         string RequestId { get; } | ||||
| 
 | ||||
|         void   AddPathHandler(RestMethodHandler mh, string path, RestMethodAllocator ma); | ||||
|         void AddStreamHandler(string httpMethod, string path, RestMethod method); | ||||
| 
 | ||||
|         public const int UuidSize = 36; | ||||
|         public const int VectorSize = 15; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -0,0 +1,11 @@ | |||
| <Addin id="OpenSim.ApplicationPlugins.Rest.Inventory" version="0.1"> | ||||
|     <Runtime> | ||||
|         <Import assembly="OpenSim.ApplicationPlugins.Rest.Inventory.dll"/> | ||||
|     </Runtime> | ||||
|     <Dependencies> | ||||
|         <Addin id="OpenSim" version="0.5" /> | ||||
|     </Dependencies> | ||||
|     <Extension path = "/OpenSim/Startup"> | ||||
|         <Plugin id="RestInventory" type="OpenSim.ApplicationPlugins.Rest.Inventory.RestHandler" /> | ||||
|     </Extension> | ||||
| </Addin> | ||||
|  | @ -0,0 +1,551 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Reflection; | ||||
| using System.Text; | ||||
| using log4net; | ||||
| using Nini.Config; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Communications; | ||||
| using OpenSim.Services.Interfaces; | ||||
| using IAvatarService = OpenSim.Services.Interfaces.IAvatarService; | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.Rest.Inventory | ||||
| { | ||||
|     public class Rest | ||||
|     { | ||||
|         internal static readonly ILog Log = | ||||
|             LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         internal static bool DEBUG = Log.IsDebugEnabled; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Supported authentication schemes | ||||
|         /// </summary> | ||||
| 
 | ||||
|         public const string AS_BASIC                      = "Basic";           // simple user/password verification | ||||
|         public const string AS_DIGEST                     = "Digest";          // password safe authentication | ||||
| 
 | ||||
|         /// Supported Digest algorithms | ||||
| 
 | ||||
|         public const string Digest_MD5                    = "MD5";             // assumed default if omitted | ||||
|         public const string Digest_MD5Sess                = "MD5-sess";        // session-span - not good for REST? | ||||
| 
 | ||||
|         public const string Qop_Auth                      = "auth";            // authentication only | ||||
|         public const string Qop_Int                       = "auth-int";        // TODO | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// These values have a single value for the whole | ||||
|         /// domain and lifetime of the plugin handler. We | ||||
|         /// make them static for ease of reference within | ||||
|         /// the assembly. These are initialized by the | ||||
|         /// RestHandler class during start-up. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         internal static IRestHandler              Plugin            = null; | ||||
|         internal static OpenSimBase               main              = null; | ||||
|         internal static string                    Prefix            = null; | ||||
|         internal static IConfig                   Config            = null; | ||||
|         internal static string                    GodKey            = null; | ||||
|         internal static bool                      Authenticate      = true; | ||||
|         internal static bool                      Secure            = true; | ||||
|         internal static bool                      ExtendedEscape    = true; | ||||
|         internal static bool                      DumpAsset         = false; | ||||
|         internal static bool                      Fill              = true; | ||||
|         internal static bool                      FlushEnabled      = true; | ||||
|         internal static string                    Realm             = "OpenSim REST"; | ||||
|         internal static string                    Scheme            = AS_BASIC; | ||||
|         internal static int                       DumpLineSize      = 32; // Should be a multiple of 16 or (possibly) 4 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// These are all dependent upon the Comms manager | ||||
|         /// being initialized. So they have to be properties | ||||
|         /// because the comms manager is now a module and is | ||||
|         /// not guaranteed to be there when the rest handler | ||||
|         /// initializes. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         internal static IInventoryService InventoryServices | ||||
|         { | ||||
|             get { return main.SceneManager.CurrentOrFirstScene.InventoryService; } | ||||
|         } | ||||
| 
 | ||||
|         internal static IUserAccountService UserServices | ||||
|         { | ||||
|             get { return main.SceneManager.CurrentOrFirstScene.UserAccountService; } | ||||
|         } | ||||
| 
 | ||||
|         internal static IAuthenticationService AuthServices | ||||
|         { | ||||
|             get { return main.SceneManager.CurrentOrFirstScene.AuthenticationService; } | ||||
|         } | ||||
|          | ||||
|         internal static IAvatarService AvatarServices | ||||
|         { | ||||
|             get { return main.SceneManager.CurrentOrFirstScene.AvatarService; } | ||||
|         } | ||||
| 
 | ||||
|         internal static IAssetService AssetServices | ||||
|         { | ||||
|             get { return main.SceneManager.CurrentOrFirstScene.AssetService; } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// HTTP requires that status information be generated for PUT | ||||
|         /// and POST opertaions. This is in support of that. The | ||||
|         /// operation verb gets substituted into the first string, | ||||
|         /// and the completion code is inserted into the tail. The | ||||
|         /// strings are put here to encourage consistency. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         internal static string                    statusHead        = "<html><body><title>{0} status</title><break>"; | ||||
|         internal static string                    statusTail        = "</body></html>"; | ||||
| 
 | ||||
|         internal static Dictionary<int,string> HttpStatusDesc; | ||||
| 
 | ||||
|         static Rest() | ||||
|         { | ||||
|             HttpStatusDesc = new Dictionary<int,string>(); | ||||
|             if (HttpStatusCodeArray.Length != HttpStatusDescArray.Length) | ||||
|             { | ||||
|                 Log.ErrorFormat("{0} HTTP Status Code and Description arrays do not match"); | ||||
|                 throw new Exception("HTTP Status array discrepancy"); | ||||
|             } | ||||
| 
 | ||||
|             // Repackage the data into something more tractable. The sparse | ||||
|             // nature of HTTP return codes makes an array a bad choice. | ||||
| 
 | ||||
|             for (int i=0; i<HttpStatusCodeArray.Length; i++) | ||||
|             { | ||||
|                 HttpStatusDesc.Add(HttpStatusCodeArray[i], HttpStatusDescArray[i]); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         internal static int CreationDate | ||||
|         { | ||||
|             get { return (int) (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; } | ||||
|         } | ||||
| 
 | ||||
|         internal static string MsgId | ||||
|         { | ||||
|             get { return Plugin.MsgId; } | ||||
|         } | ||||
| 
 | ||||
|         internal static string RequestId | ||||
|         { | ||||
|             get { return Plugin.RequestId; } | ||||
|         } | ||||
| 
 | ||||
|         internal static Encoding Encoding = Util.UTF8; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Version control for REST implementation. This | ||||
|         /// refers to the overall infrastructure represented | ||||
|         /// by the following classes | ||||
|         ///     RequestData | ||||
|         ///     RequestInventoryPlugin | ||||
|         ///     Rest | ||||
|         /// It does no describe implementation classes such as | ||||
|         /// RestInventoryServices, which may morph much more | ||||
|         /// often. Such classes ARE dependent upon this however | ||||
|         /// and should check it in their Initialize method. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         public static readonly float Version  = 1.0F; | ||||
|         public const  string  Name            = "REST 1.0"; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Currently defined HTTP methods. | ||||
|         /// Only GET and HEAD are required to be | ||||
|         /// supported by all servers. See Respond | ||||
|         /// to see how these are handled. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         // REST AGENT 1.0 interpretations | ||||
|         public const string GET     = "get";       // information retrieval - server state unchanged | ||||
|         public const string HEAD    = "head";      // same as get except only the headers are returned. | ||||
|         public const string POST    = "post";      // Replace the URI designated resource with the entity. | ||||
|         public const string PUT     = "put";       // Add the entity to the context represented by the URI | ||||
|         public const string DELETE  = "delete";    // Remove the URI designated resource from the server. | ||||
| 
 | ||||
|         public const string OPTIONS = "options";  // | ||||
|         public const string TRACE   = "trace";    // | ||||
|         public const string CONNECT = "connect";  // | ||||
| 
 | ||||
|         // Define this in one place... | ||||
| 
 | ||||
|         public const string UrlPathSeparator   = "/"; | ||||
|         public const string UrlMethodSeparator = ":"; | ||||
| 
 | ||||
|         // Redirection qualifications | ||||
| 
 | ||||
|         public const bool PERMANENT = false; | ||||
|         public const bool TEMPORARY = true; | ||||
| 
 | ||||
|         // Constant arrays used by String.Split | ||||
| 
 | ||||
|         public   static   readonly char   C_SPACE    = ' '; | ||||
|         public   static   readonly char   C_SLASH    = '/'; | ||||
|         public   static   readonly char   C_PATHSEP  = '/'; | ||||
|         public   static   readonly char   C_COLON    = ':'; | ||||
|         public   static   readonly char   C_PLUS     = '+'; | ||||
|         public   static   readonly char   C_PERIOD   = '.'; | ||||
|         public   static   readonly char   C_COMMA    = ','; | ||||
|         public   static   readonly char   C_DQUOTE   = '"'; | ||||
| 
 | ||||
|         public   static   readonly string   CS_SPACE    = " "; | ||||
|         public   static   readonly string   CS_SLASH    = "/"; | ||||
|         public   static   readonly string   CS_PATHSEP  = "/"; | ||||
|         public   static   readonly string   CS_COLON    = ":"; | ||||
|         public   static   readonly string   CS_PLUS     = "+"; | ||||
|         public   static   readonly string   CS_PERIOD   = "."; | ||||
|         public   static   readonly string   CS_COMMA    = ","; | ||||
|         public   static   readonly string   CS_DQUOTE   = "\""; | ||||
| 
 | ||||
|         public   static   readonly char[] CA_SPACE   = { C_SPACE   }; | ||||
|         public   static   readonly char[] CA_SLASH   = { C_SLASH   }; | ||||
|         public   static   readonly char[] CA_PATHSEP = { C_PATHSEP }; | ||||
|         public   static   readonly char[] CA_COLON   = { C_COLON   }; | ||||
|         public   static   readonly char[] CA_PERIOD  = { C_PERIOD  }; | ||||
|         public   static   readonly char[] CA_PLUS    = { C_PLUS    }; | ||||
|         public   static   readonly char[] CA_COMMA   = { C_COMMA   }; | ||||
|         public   static   readonly char[] CA_DQUOTE  = { C_DQUOTE  }; | ||||
| 
 | ||||
|         // HTTP Code Values (in value order) | ||||
| 
 | ||||
|         public const int HttpStatusCodeContinue           = 100; | ||||
|         public const int HttpStatusCodeSwitchingProtocols = 101; | ||||
| 
 | ||||
|         public const int HttpStatusCodeOK                 = 200; | ||||
|         public const int HttpStatusCodeCreated            = 201; | ||||
|         public const int HttpStatusCodeAccepted           = 202; | ||||
|         public const int HttpStatusCodeNonAuthoritative   = 203; | ||||
|         public const int HttpStatusCodeNoContent          = 204; | ||||
|         public const int HttpStatusCodeResetContent       = 205; | ||||
|         public const int HttpStatusCodePartialContent     = 206; | ||||
| 
 | ||||
|         public const int HttpStatusCodeMultipleChoices    = 300; | ||||
|         public const int HttpStatusCodePermanentRedirect  = 301; | ||||
|         public const int HttpStatusCodeFound              = 302; | ||||
|         public const int HttpStatusCodeSeeOther           = 303; | ||||
|         public const int HttpStatusCodeNotModified        = 304; | ||||
|         public const int HttpStatusCodeUseProxy           = 305; | ||||
|         public const int HttpStatusCodeReserved306        = 306; | ||||
|         public const int HttpStatusCodeTemporaryRedirect  = 307; | ||||
| 
 | ||||
|         public const int HttpStatusCodeBadRequest         = 400; | ||||
|         public const int HttpStatusCodeNotAuthorized      = 401; | ||||
|         public const int HttpStatusCodePaymentRequired    = 402; | ||||
|         public const int HttpStatusCodeForbidden          = 403; | ||||
|         public const int HttpStatusCodeNotFound           = 404; | ||||
|         public const int HttpStatusCodeMethodNotAllowed   = 405; | ||||
|         public const int HttpStatusCodeNotAcceptable      = 406; | ||||
|         public const int HttpStatusCodeProxyAuthenticate  = 407; | ||||
|         public const int HttpStatusCodeTimeOut            = 408; | ||||
|         public const int HttpStatusCodeConflict           = 409; | ||||
|         public const int HttpStatusCodeGone               = 410; | ||||
|         public const int HttpStatusCodeLengthRequired     = 411; | ||||
|         public const int HttpStatusCodePreconditionFailed = 412; | ||||
|         public const int HttpStatusCodeEntityTooLarge     = 413; | ||||
|         public const int HttpStatusCodeUriTooLarge        = 414; | ||||
|         public const int HttpStatusCodeUnsupportedMedia   = 415; | ||||
|         public const int HttpStatusCodeRangeNotSatsified  = 416; | ||||
|         public const int HttpStatusCodeExpectationFailed  = 417; | ||||
| 
 | ||||
|         public const int HttpStatusCodeServerError        = 500; | ||||
|         public const int HttpStatusCodeNotImplemented     = 501; | ||||
|         public const int HttpStatusCodeBadGateway         = 502; | ||||
|         public const int HttpStatusCodeServiceUnavailable = 503; | ||||
|         public const int HttpStatusCodeGatewayTimeout     = 504; | ||||
|         public const int HttpStatusCodeHttpVersionError   = 505; | ||||
| 
 | ||||
|         public static readonly int[] HttpStatusCodeArray  = { | ||||
|             HttpStatusCodeContinue, | ||||
|             HttpStatusCodeSwitchingProtocols, | ||||
|             HttpStatusCodeOK, | ||||
|             HttpStatusCodeCreated, | ||||
|             HttpStatusCodeAccepted, | ||||
|             HttpStatusCodeNonAuthoritative, | ||||
|             HttpStatusCodeNoContent, | ||||
|             HttpStatusCodeResetContent, | ||||
|             HttpStatusCodePartialContent, | ||||
|             HttpStatusCodeMultipleChoices, | ||||
|             HttpStatusCodePermanentRedirect, | ||||
|             HttpStatusCodeFound, | ||||
|             HttpStatusCodeSeeOther, | ||||
|             HttpStatusCodeNotModified, | ||||
|             HttpStatusCodeUseProxy, | ||||
|             HttpStatusCodeReserved306, | ||||
|             HttpStatusCodeTemporaryRedirect, | ||||
|             HttpStatusCodeBadRequest, | ||||
|             HttpStatusCodeNotAuthorized, | ||||
|             HttpStatusCodePaymentRequired, | ||||
|             HttpStatusCodeForbidden, | ||||
|             HttpStatusCodeNotFound, | ||||
|             HttpStatusCodeMethodNotAllowed, | ||||
|             HttpStatusCodeNotAcceptable, | ||||
|             HttpStatusCodeProxyAuthenticate, | ||||
|             HttpStatusCodeTimeOut, | ||||
|             HttpStatusCodeConflict, | ||||
|             HttpStatusCodeGone, | ||||
|             HttpStatusCodeLengthRequired, | ||||
|             HttpStatusCodePreconditionFailed, | ||||
|             HttpStatusCodeEntityTooLarge, | ||||
|             HttpStatusCodeUriTooLarge, | ||||
|             HttpStatusCodeUnsupportedMedia, | ||||
|             HttpStatusCodeRangeNotSatsified, | ||||
|             HttpStatusCodeExpectationFailed, | ||||
|             HttpStatusCodeServerError, | ||||
|             HttpStatusCodeNotImplemented, | ||||
|             HttpStatusCodeBadGateway, | ||||
|             HttpStatusCodeServiceUnavailable, | ||||
|             HttpStatusCodeGatewayTimeout, | ||||
|             HttpStatusCodeHttpVersionError | ||||
|         }; | ||||
| 
 | ||||
|         // HTTP Status Descriptions (in status code order) | ||||
|         // This array must be kept strictly consistent with respect | ||||
|         // to the status code array above. | ||||
| 
 | ||||
|         public static readonly string[] HttpStatusDescArray  = { | ||||
|             "Continue Request", | ||||
|             "Switching Protocols", | ||||
|             "OK", | ||||
|             "CREATED", | ||||
|             "ACCEPTED", | ||||
|             "NON-AUTHORITATIVE INFORMATION", | ||||
|             "NO CONTENT", | ||||
|             "RESET CONTENT", | ||||
|             "PARTIAL CONTENT", | ||||
|             "MULTIPLE CHOICES", | ||||
|             "PERMANENT REDIRECT", | ||||
|             "FOUND", | ||||
|             "SEE OTHER", | ||||
|             "NOT MODIFIED", | ||||
|             "USE PROXY", | ||||
|             "RESERVED CODE 306", | ||||
|             "TEMPORARY REDIRECT", | ||||
|             "BAD REQUEST", | ||||
|             "NOT AUTHORIZED", | ||||
|             "PAYMENT REQUIRED", | ||||
|             "FORBIDDEN", | ||||
|             "NOT FOUND", | ||||
|             "METHOD NOT ALLOWED", | ||||
|             "NOT ACCEPTABLE", | ||||
|             "PROXY AUTHENTICATION REQUIRED", | ||||
|             "TIMEOUT", | ||||
|             "CONFLICT", | ||||
|             "GONE", | ||||
|             "LENGTH REQUIRED", | ||||
|             "PRECONDITION FAILED", | ||||
|             "ENTITY TOO LARGE", | ||||
|             "URI TOO LARGE", | ||||
|             "UNSUPPORTED MEDIA", | ||||
|             "RANGE NOT SATISFIED", | ||||
|             "EXPECTATION FAILED", | ||||
|             "SERVER ERROR", | ||||
|             "NOT IMPLEMENTED", | ||||
|             "BAD GATEWAY", | ||||
|             "SERVICE UNAVAILABLE", | ||||
|             "GATEWAY TIMEOUT", | ||||
|             "HTTP VERSION NOT SUPPORTED" | ||||
|         }; | ||||
| 
 | ||||
|         // HTTP Headers | ||||
| 
 | ||||
|         public const string HttpHeaderAccept              = "Accept"; | ||||
|         public const string HttpHeaderAcceptCharset       = "Accept-Charset"; | ||||
|         public const string HttpHeaderAcceptEncoding      = "Accept-Encoding"; | ||||
|         public const string HttpHeaderAcceptLanguage      = "Accept-Language"; | ||||
|         public const string HttpHeaderAcceptRanges        = "Accept-Ranges"; | ||||
|         public const string HttpHeaderAge                 = "Age"; | ||||
|         public const string HttpHeaderAllow               = "Allow"; | ||||
|         public const string HttpHeaderAuthorization       = "Authorization"; | ||||
|         public const string HttpHeaderCacheControl        = "Cache-Control"; | ||||
|         public const string HttpHeaderConnection          = "Connection"; | ||||
|         public const string HttpHeaderContentEncoding     = "Content-Encoding"; | ||||
|         public const string HttpHeaderContentLanguage     = "Content-Language"; | ||||
|         public const string HttpHeaderContentLength       = "Content-Length"; | ||||
|         public const string HttpHeaderContentLocation     = "Content-Location"; | ||||
|         public const string HttpHeaderContentMD5          = "Content-MD5"; | ||||
|         public const string HttpHeaderContentRange        = "Content-Range"; | ||||
|         public const string HttpHeaderContentType         = "Content-Type"; | ||||
|         public const string HttpHeaderDate                = "Date"; | ||||
|         public const string HttpHeaderETag                = "ETag"; | ||||
|         public const string HttpHeaderExpect              = "Expect"; | ||||
|         public const string HttpHeaderExpires             = "Expires"; | ||||
|         public const string HttpHeaderFrom                = "From"; | ||||
|         public const string HttpHeaderHost                = "Host"; | ||||
|         public const string HttpHeaderIfMatch             = "If-Match"; | ||||
|         public const string HttpHeaderIfModifiedSince     = "If-Modified-Since"; | ||||
|         public const string HttpHeaderIfNoneMatch         = "If-None-Match"; | ||||
|         public const string HttpHeaderIfRange             = "If-Range"; | ||||
|         public const string HttpHeaderIfUnmodifiedSince   = "If-Unmodified-Since"; | ||||
|         public const string HttpHeaderLastModified        = "Last-Modified"; | ||||
|         public const string HttpHeaderLocation            = "Location"; | ||||
|         public const string HttpHeaderMaxForwards         = "Max-Forwards"; | ||||
|         public const string HttpHeaderPragma              = "Pragma"; | ||||
|         public const string HttpHeaderProxyAuthenticate   = "Proxy-Authenticate"; | ||||
|         public const string HttpHeaderProxyAuthorization  = "Proxy-Authorization"; | ||||
|         public const string HttpHeaderRange               = "Range"; | ||||
|         public const string HttpHeaderReferer             = "Referer"; | ||||
|         public const string HttpHeaderRetryAfter          = "Retry-After"; | ||||
|         public const string HttpHeaderServer              = "Server"; | ||||
|         public const string HttpHeaderTE                  = "TE"; | ||||
|         public const string HttpHeaderTrailer             = "Trailer"; | ||||
|         public const string HttpHeaderTransferEncoding    = "Transfer-Encoding"; | ||||
|         public const string HttpHeaderUpgrade             = "Upgrade"; | ||||
|         public const string HttpHeaderUserAgent           = "User-Agent"; | ||||
|         public const string HttpHeaderVary                = "Vary"; | ||||
|         public const string HttpHeaderVia                 = "Via"; | ||||
|         public const string HttpHeaderWarning             = "Warning"; | ||||
|         public const string HttpHeaderWWWAuthenticate     = "WWW-Authenticate"; | ||||
| 
 | ||||
|         /// Utility routines | ||||
| 
 | ||||
|         public static string StringToBase64(string str) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 byte[] encData_byte = new byte[str.Length]; | ||||
|                 encData_byte = Util.UTF8.GetBytes(str); | ||||
|                 return Convert.ToBase64String(encData_byte); | ||||
|             } | ||||
|             catch | ||||
|             { | ||||
|                 return String.Empty; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public static string Base64ToString(string str) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 return Util.Base64ToString(str); | ||||
|             } | ||||
|             catch | ||||
|             { | ||||
|                 return String.Empty; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private const string hvals = "0123456789abcdef"; | ||||
| 
 | ||||
|         public static int Hex2Int(string hex) | ||||
|         { | ||||
|             int    val = 0; | ||||
|             int    sum = 0; | ||||
|             string tmp = null; | ||||
| 
 | ||||
|             if (hex != null) | ||||
|             { | ||||
|                 tmp = hex.ToLower(); | ||||
|                 for (int i = 0; i < tmp.Length; i++) | ||||
|                 { | ||||
|                     val = hvals.IndexOf(tmp[i]); | ||||
|                     if (val == -1) | ||||
|                         break; | ||||
|                     sum *= 16; | ||||
|                     sum += val; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return sum; | ||||
|         } | ||||
| 
 | ||||
|         // Nonce management | ||||
| 
 | ||||
|         public static string NonceGenerator() | ||||
|         { | ||||
|             return StringToBase64(CreationDate + Guid.NewGuid().ToString()); | ||||
|         } | ||||
| 
 | ||||
|         // Dump the specified data stream | ||||
| 
 | ||||
|         public static void Dump(byte[] data) | ||||
|         { | ||||
|             char[] buffer = new char[DumpLineSize]; | ||||
|             int cc = 0; | ||||
| 
 | ||||
|             for (int i = 0; i < data.Length; i++) | ||||
|             { | ||||
|                 if (i % DumpLineSize == 0) Console.Write("\n{0}: ",i.ToString("d8")); | ||||
| 
 | ||||
|                 if (i % 4  == 0) Console.Write(" "); | ||||
| 
 | ||||
|                 Console.Write("{0}",data[i].ToString("x2")); | ||||
| 
 | ||||
|                 if (data[i] < 127 && data[i] > 31) | ||||
|                     buffer[i % DumpLineSize] = (char) data[i]; | ||||
|                 else | ||||
|                     buffer[i % DumpLineSize] = '.'; | ||||
| 
 | ||||
|                 cc++; | ||||
| 
 | ||||
|                 if (i != 0 && (i + 1) % DumpLineSize == 0) | ||||
|                 { | ||||
|                     Console.Write(" |"+(new String(buffer))+"|"); | ||||
|                     cc = 0; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // Finish off any incomplete line | ||||
| 
 | ||||
|             if (cc != 0) | ||||
|             { | ||||
|                 for (int i = cc ; i < DumpLineSize; i++) | ||||
|                 { | ||||
|                     if (i % 4  == 0) Console.Write(" "); | ||||
|                     Console.Write("  "); | ||||
|                     buffer[i % DumpLineSize] = ' '; | ||||
|                 } | ||||
|                 Console.WriteLine(" |"+(new String(buffer))+"|"); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Console.Write("\n"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Local exception type | ||||
| 
 | ||||
|     public class RestException : Exception | ||||
|     { | ||||
|         internal int    statusCode; | ||||
|         internal string statusDesc; | ||||
|         internal string httpmethod; | ||||
|         internal string httppath; | ||||
| 
 | ||||
|         public RestException(string msg) : base(msg) | ||||
|         { | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,860 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| using System.Xml; | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Servers; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Services.Interfaces; | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.Rest.Inventory | ||||
| { | ||||
| 
 | ||||
|     public class RestAppearanceServices : IRest | ||||
|     { | ||||
| //        private static readonly int PARM_USERID = 0; | ||||
| 
 | ||||
|         // private static readonly int PARM_PATH   = 1; | ||||
| 
 | ||||
| //        private bool       enabled = false; | ||||
|         private string     qPrefix = "appearance"; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// The constructor makes sure that the service prefix is absolute | ||||
|         /// and the registers the service handler and the allocator. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         public RestAppearanceServices() | ||||
|         { | ||||
|             Rest.Log.InfoFormat("{0} User appearance services initializing", MsgId); | ||||
|             Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); | ||||
| 
 | ||||
|             // If a relative path was specified for the handler's domain, | ||||
|             // add the standard prefix to make it absolute, e.g. /admin | ||||
| 
 | ||||
|             if (!qPrefix.StartsWith(Rest.UrlPathSeparator)) | ||||
|             { | ||||
|                 Rest.Log.InfoFormat("{0} Domain is relative, adding absolute prefix", MsgId); | ||||
|                 qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix); | ||||
|                 qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix); | ||||
|                 Rest.Log.InfoFormat("{0} Domain is now <{1}>", MsgId, qPrefix); | ||||
|             } | ||||
| 
 | ||||
|             // Register interface using the absolute URI. | ||||
| 
 | ||||
|             Rest.Plugin.AddPathHandler(DoAppearance,qPrefix,Allocate); | ||||
| 
 | ||||
|             // Activate if everything went OK | ||||
| 
 | ||||
| //            enabled = true; | ||||
| 
 | ||||
|             Rest.Log.InfoFormat("{0} User appearance services initialization complete", MsgId); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Post-construction, pre-enabled initialization opportunity | ||||
|         /// Not currently exploited. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         public void Initialize() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Called by the plug-in to halt service processing. Local processing is | ||||
|         /// disabled. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         public void Close() | ||||
|         { | ||||
| //            enabled = false; | ||||
|             Rest.Log.InfoFormat("{0} User appearance services closing down", MsgId); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// This property is declared locally because it is used a lot and | ||||
|         /// brevity is nice. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         internal string MsgId | ||||
|         { | ||||
|             get { return Rest.MsgId; } | ||||
|         } | ||||
| 
 | ||||
|         #region Interface | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// The plugin (RestHandler) calls this method to allocate the request | ||||
|         /// state carrier for a new request. It is destroyed when the request | ||||
|         /// completes. All request-instance specific state is kept here. This | ||||
|         /// is registered when this service provider is registered. | ||||
|         /// </summary> | ||||
|         /// <param name=request>Inbound HTTP request information</param> | ||||
|         /// <param name=response>Outbound HTTP request information</param> | ||||
|         /// <param name=qPrefix>REST service domain prefix</param> | ||||
|         /// <returns>A RequestData instance suitable for this service</returns> | ||||
| 
 | ||||
|         private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix) | ||||
|         { | ||||
|             return (RequestData) new AppearanceRequestData(request, response, prefix); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// This method is registered with the handler when this service provider | ||||
|         /// is initialized. It is called whenever the plug-in identifies this service | ||||
|         /// provider as the best match for a given request. | ||||
|         /// It handles all aspects of inventory REST processing, i.e. /admin/inventory | ||||
|         /// </summary> | ||||
|         /// <param name=hdata>A consolidated HTTP request work area</param> | ||||
| 
 | ||||
|         private void DoAppearance(RequestData hdata) | ||||
|         { | ||||
|             // !!! REFACTORIMG PROBLEM. This needs rewriting for 0.7 | ||||
| 
 | ||||
|             //AppearanceRequestData rdata = (AppearanceRequestData) hdata; | ||||
| 
 | ||||
|             //Rest.Log.DebugFormat("{0} DoAppearance ENTRY", MsgId); | ||||
| 
 | ||||
|             //// If we're disabled, do nothing. | ||||
| 
 | ||||
|             //if (!enabled) | ||||
|             //{ | ||||
|             //    return; | ||||
|             //} | ||||
| 
 | ||||
|             //// Now that we know this is a serious attempt to | ||||
|             //// access inventory data, we should find out who | ||||
|             //// is asking, and make sure they are authorized | ||||
|             //// to do so. We need to validate the caller's | ||||
|             //// identity before revealing anything about the | ||||
|             //// status quo. Authenticate throws an exception | ||||
|             //// via Fail if no identity information is present. | ||||
|             //// | ||||
|             //// With the present HTTP server we can't use the | ||||
|             //// builtin authentication mechanisms because they | ||||
|             //// would be enforced for all in-bound requests. | ||||
|             //// Instead we look at the headers ourselves and | ||||
|             //// handle authentication directly. | ||||
| 
 | ||||
|             //try | ||||
|             //{ | ||||
|             //    if (!rdata.IsAuthenticated) | ||||
|             //    { | ||||
|             //        rdata.Fail(Rest.HttpStatusCodeNotAuthorized,String.Format("user \"{0}\" could not be authenticated", rdata.userName)); | ||||
|             //    } | ||||
|             //} | ||||
|             //catch (RestException e) | ||||
|             //{ | ||||
|             //    if (e.statusCode == Rest.HttpStatusCodeNotAuthorized) | ||||
|             //    { | ||||
|             //        Rest.Log.WarnFormat("{0} User not authenticated", MsgId); | ||||
|             //        Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization")); | ||||
|             //    } | ||||
|             //    else | ||||
|             //    { | ||||
|             //        Rest.Log.ErrorFormat("{0} User authentication failed", MsgId); | ||||
|             //        Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization")); | ||||
|             //    } | ||||
|             //    throw (e); | ||||
|             //} | ||||
| 
 | ||||
|             //Rest.Log.DebugFormat("{0} Authenticated {1}", MsgId, rdata.userName); | ||||
| 
 | ||||
|             //// We can only get here if we are authorized | ||||
|             //// | ||||
|             //// The requestor may have specified an UUID or | ||||
|             //// a conjoined FirstName LastName string. We'll | ||||
|             //// try both. If we fail with the first, UUID, | ||||
|             //// attempt, we try the other. As an example, the | ||||
|             //// URI for a valid inventory request might be: | ||||
|             //// | ||||
|             //// http://<host>:<port>/admin/inventory/Arthur Dent | ||||
|             //// | ||||
|             //// Indicating that this is an inventory request for | ||||
|             //// an avatar named Arthur Dent. This is ALL that is | ||||
|             //// required to designate a GET for an entire | ||||
|             //// inventory. | ||||
|             //// | ||||
| 
 | ||||
|             //// Do we have at least a user agent name? | ||||
| 
 | ||||
|             //if (rdata.Parameters.Length < 1) | ||||
|             //{ | ||||
|             //    Rest.Log.WarnFormat("{0} Appearance: No user agent identifier specified", MsgId); | ||||
|             //    rdata.Fail(Rest.HttpStatusCodeBadRequest, "no user identity specified"); | ||||
|             //} | ||||
| 
 | ||||
|             //// The first parameter MUST be the agent identification, either an UUID | ||||
|             //// or a space-separated First-name Last-Name specification. We check for | ||||
|             //// an UUID first, if anyone names their character using a valid UUID | ||||
|             //// that identifies another existing avatar will cause this a problem... | ||||
| 
 | ||||
|             //try | ||||
|             //{ | ||||
|             //    rdata.uuid = new UUID(rdata.Parameters[PARM_USERID]); | ||||
|             //    Rest.Log.DebugFormat("{0} UUID supplied", MsgId); | ||||
|             //    rdata.userProfile = Rest.UserServices.GetUserProfile(rdata.uuid); | ||||
|             //} | ||||
|             //catch | ||||
|             //{ | ||||
|             //    string[] names = rdata.Parameters[PARM_USERID].Split(Rest.CA_SPACE); | ||||
|             //    if (names.Length == 2) | ||||
|             //    { | ||||
|             //        Rest.Log.DebugFormat("{0} Agent Name supplied [2]", MsgId); | ||||
|             //        rdata.userProfile = Rest.UserServices.GetUserProfile(names[0],names[1]); | ||||
|             //    } | ||||
|             //    else | ||||
|             //    { | ||||
|             //        Rest.Log.WarnFormat("{0} A Valid UUID or both first and last names must be specified", MsgId); | ||||
|             //        rdata.Fail(Rest.HttpStatusCodeBadRequest, "invalid user identity"); | ||||
|             //    } | ||||
|             //} | ||||
| 
 | ||||
|             //// If the user profile is null then either the server is broken, or the | ||||
|             //// user is not known. We always assume the latter case. | ||||
| 
 | ||||
|             //if (rdata.userProfile != null) | ||||
|             //{ | ||||
|             //    Rest.Log.DebugFormat("{0} User profile obtained for agent {1} {2}", | ||||
|             //                         MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); | ||||
|             //} | ||||
|             //else | ||||
|             //{ | ||||
|             //    Rest.Log.WarnFormat("{0} No user profile for {1}", MsgId, rdata.path); | ||||
|             //    rdata.Fail(Rest.HttpStatusCodeNotFound, "unrecognized user identity"); | ||||
|             //} | ||||
| 
 | ||||
|             //// If we get to here, then we have effectively validated the user's | ||||
| 
 | ||||
|             //switch (rdata.method) | ||||
|             //{ | ||||
|             //    case Rest.HEAD   : // Do the processing, set the status code, suppress entity | ||||
|             //        DoGet(rdata); | ||||
|             //        rdata.buffer = null; | ||||
|             //        break; | ||||
| 
 | ||||
|             //    case Rest.GET    : // Do the processing, set the status code, return entity | ||||
|             //        DoGet(rdata); | ||||
|             //        break; | ||||
| 
 | ||||
|             //    case Rest.PUT    : // Update named element | ||||
|             //        DoUpdate(rdata); | ||||
|             //        break; | ||||
| 
 | ||||
|             //    case Rest.POST   : // Add new information to identified context. | ||||
|             //        DoExtend(rdata); | ||||
|             //        break; | ||||
| 
 | ||||
|             //    case Rest.DELETE : // Delete information | ||||
|             //        DoDelete(rdata); | ||||
|             //        break; | ||||
| 
 | ||||
|             //    default : | ||||
|             //        Rest.Log.WarnFormat("{0} Method {1} not supported for {2}", | ||||
|             //                             MsgId, rdata.method, rdata.path); | ||||
|             //        rdata.Fail(Rest.HttpStatusCodeMethodNotAllowed,  | ||||
|             //                   String.Format("{0} not supported", rdata.method)); | ||||
|             //        break; | ||||
|             //} | ||||
|         } | ||||
| 
 | ||||
|         #endregion Interface | ||||
| 
 | ||||
|         #region method-specific processing | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// This method implements GET processing for user's appearance. | ||||
|         /// </summary> | ||||
|         /// <param name=rdata>HTTP service request work area</param> | ||||
| 
 | ||||
| //        private void DoGet(AppearanceRequestData rdata) | ||||
| //        { | ||||
| //            AvatarData adata = Rest.AvatarServices.GetAvatar(rdata.userProfile.ID); | ||||
| // | ||||
| //            if (adata == null) | ||||
| //            { | ||||
| //                rdata.Fail(Rest.HttpStatusCodeNoContent, | ||||
| //                    String.Format("appearance data not found for user {0} {1}",  | ||||
| //                      rdata.userProfile.FirstName, rdata.userProfile.SurName)); | ||||
| //            } | ||||
| //            rdata.userAppearance = adata.ToAvatarAppearance(rdata.userProfile.ID); | ||||
| // | ||||
| //            rdata.initXmlWriter(); | ||||
| // | ||||
| //            FormatUserAppearance(rdata); | ||||
| // | ||||
| //            // Indicate a successful request | ||||
| // | ||||
| //            rdata.Complete(); | ||||
| // | ||||
| //            // Send the response to the user. The body will be implicitly | ||||
| //            // constructed from the result of the XML writer. | ||||
| // | ||||
| //            rdata.Respond(String.Format("Appearance {0} Normal completion", rdata.method)); | ||||
| //        } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// POST adds NEW information to the user profile database. | ||||
|         /// This effectively resets the appearance before applying those | ||||
|         /// characteristics supplied in the request. | ||||
|         /// </summary> | ||||
| 
 | ||||
| //        private void DoExtend(AppearanceRequestData rdata) | ||||
| //        { | ||||
| // | ||||
| //            bool  created  = false; | ||||
| //            bool  modified = false; | ||||
| //            string newnode = String.Empty; | ||||
| // | ||||
| //            Rest.Log.DebugFormat("{0} POST ENTRY", MsgId); | ||||
| // | ||||
| //            //AvatarAppearance old = Rest.AvatarServices.GetUserAppearance(rdata.userProfile.ID); | ||||
| // | ||||
| //            rdata.userAppearance = new AvatarAppearance(); | ||||
| // | ||||
| //            //  Although the following behavior is admitted by HTTP I am becoming  | ||||
| //            //  increasingly doubtful that it is appropriate for REST. If I attempt to | ||||
| //            //  add a new record, and it already exists, then it seems to me that the | ||||
| //            //  attempt should fail, rather than update the existing record. | ||||
| //            AvatarData adata = null; | ||||
| //            if (GetUserAppearance(rdata)) | ||||
| //            { | ||||
| //                modified = rdata.userAppearance != null; | ||||
| //                created  = !modified; | ||||
| //                adata = new AvatarData(rdata.userAppearance); | ||||
| //                Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata); | ||||
| //            //    Rest.UserServices.UpdateUserProfile(rdata.userProfile); | ||||
| //            } | ||||
| //            else | ||||
| //            { | ||||
| //                created  = true; | ||||
| //                adata = new AvatarData(rdata.userAppearance); | ||||
| //                Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata); | ||||
| //             //   Rest.UserServices.UpdateUserProfile(rdata.userProfile); | ||||
| //            } | ||||
| // | ||||
| //            if (created) | ||||
| //            { | ||||
| //                newnode = String.Format("{0} {1}", rdata.userProfile.FirstName, | ||||
| //                                   rdata.userProfile.SurName); | ||||
| //                // Must include a location header with a URI that identifies the new resource. | ||||
| // | ||||
| //                rdata.AddHeader(Rest.HttpHeaderLocation,String.Format("http://{0}{1}:{2}{3}{4}", | ||||
| //                         rdata.hostname,rdata.port,rdata.path,Rest.UrlPathSeparator, newnode)); | ||||
| //                rdata.Complete(Rest.HttpStatusCodeCreated); | ||||
| // | ||||
| //            } | ||||
| //            else | ||||
| //            { | ||||
| //                if (modified) | ||||
| //                { | ||||
| //                    rdata.Complete(Rest.HttpStatusCodeOK); | ||||
| //                } | ||||
| //                else | ||||
| //                { | ||||
| //                    rdata.Complete(Rest.HttpStatusCodeNoContent); | ||||
| //                } | ||||
| //            } | ||||
| // | ||||
| //            rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method)); | ||||
| // | ||||
| //        } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// This updates the user's appearance. not all aspects need to be provided, | ||||
|         /// only those supplied will be changed. | ||||
|         /// </summary> | ||||
| 
 | ||||
| //        private void DoUpdate(AppearanceRequestData rdata) | ||||
| //        { | ||||
| // | ||||
| //            // REFACTORING PROBLEM This was commented out. It doesn't work for 0.7 | ||||
| // | ||||
| //            //bool  created  = false; | ||||
| //            //bool  modified = false; | ||||
| // | ||||
| // | ||||
| //            //rdata.userAppearance = Rest.AvatarServices.GetUserAppearance(rdata.userProfile.ID); | ||||
| // | ||||
| //            //// If the user exists then this is considered a modification regardless | ||||
| //            //// of what may, or may not be, specified in the payload. | ||||
| // | ||||
| //            //if (rdata.userAppearance != null) | ||||
| //            //{ | ||||
| //            //    modified = true; | ||||
| //            //    Rest.AvatarServices.UpdateUserAppearance(rdata.userProfile.ID, rdata.userAppearance); | ||||
| //            //    Rest.UserServices.UpdateUserProfile(rdata.userProfile); | ||||
| //            //} | ||||
| // | ||||
| //            //if (created) | ||||
| //            //{ | ||||
| //            //    rdata.Complete(Rest.HttpStatusCodeCreated); | ||||
| //            //} | ||||
| //            //else | ||||
| //            //{ | ||||
| //            //    if (modified) | ||||
| //            //    { | ||||
| //            //        rdata.Complete(Rest.HttpStatusCodeOK); | ||||
| //            //    } | ||||
| //            //    else | ||||
| //            //    { | ||||
| //            //        rdata.Complete(Rest.HttpStatusCodeNoContent); | ||||
| //            //    } | ||||
| //            //} | ||||
| // | ||||
| //            rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method)); | ||||
| // | ||||
| //        } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Delete the specified user's appearance. This actually performs a reset | ||||
|         /// to the default avatar appearance, if the info is already there.  | ||||
|         /// Existing ownership is preserved. All prior updates are lost and can not | ||||
|         /// be recovered. | ||||
|         /// </summary> | ||||
| //        private void DoDelete(AppearanceRequestData rdata) | ||||
| //        { | ||||
| //            AvatarData adata = Rest.AvatarServices.GetAvatar(rdata.userProfile.ID); | ||||
| // | ||||
| //            if (adata != null) | ||||
| //            { | ||||
| //                AvatarAppearance old = adata.ToAvatarAppearance(rdata.userProfile.ID); | ||||
| //                rdata.userAppearance = new AvatarAppearance(); | ||||
| //                rdata.userAppearance.Owner = old.Owner; | ||||
| //                adata = new AvatarData(rdata.userAppearance); | ||||
| // | ||||
| //                Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata); | ||||
| // | ||||
| //                rdata.Complete(); | ||||
| //            } | ||||
| //            else | ||||
| //            { | ||||
| // | ||||
| //                rdata.Complete(Rest.HttpStatusCodeNoContent); | ||||
| //            } | ||||
| // | ||||
| //            rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method)); | ||||
| //        } | ||||
| 
 | ||||
| #endregion method-specific processing | ||||
| 
 | ||||
|         private bool GetUserAppearance(AppearanceRequestData rdata) | ||||
|         { | ||||
| 
 | ||||
|             XmlReader xml; | ||||
|             bool indata = false; | ||||
| 
 | ||||
|             rdata.initXmlReader(); | ||||
|             xml     = rdata.reader; | ||||
| 
 | ||||
|             while (xml.Read()) | ||||
|             { | ||||
|                 switch (xml.NodeType) | ||||
|                 { | ||||
|                     case XmlNodeType.Element : | ||||
|                         switch (xml.Name) | ||||
|                         { | ||||
|                             case "Appearance" : | ||||
|                                 if (xml.MoveToAttribute("Height")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.AvatarHeight = (float) Convert.ToDouble(xml.Value); | ||||
|                                     indata = true; | ||||
|                                 } | ||||
| //                                if (xml.MoveToAttribute("Owner")) | ||||
| //                                { | ||||
| //                                    rdata.userAppearance.Owner = (UUID)xml.Value; | ||||
| //                                    indata = true; | ||||
| //                                } | ||||
|                                 if (xml.MoveToAttribute("Serial")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.Serial = Convert.ToInt32(xml.Value); | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
| /* | ||||
|                             case "Body" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.BodyItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.BodyAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Skin" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.SkinItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.SkinAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Hair" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.HairItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.HairAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Eyes" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.EyesItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.EyesAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Shirt" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.ShirtItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.ShirtAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Pants" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.PantsItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.PantsAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Shoes" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.ShoesItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.ShoesAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Socks" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.SocksItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.SocksAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Jacket" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.JacketItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.JacketAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Gloves" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.GlovesItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.GlovesAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "UnderShirt" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.UnderShirtItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.UnderShirtAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "UnderPants" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.UnderPantsItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.UnderPantsAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Skirt" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.SkirtItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.SkirtAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
| */ | ||||
|                             case "Attachment" : | ||||
|                                 { | ||||
| 
 | ||||
|                                     int  ap; | ||||
|                                     UUID asset; | ||||
|                                     UUID item; | ||||
| 
 | ||||
|                                     if (xml.MoveToAttribute("AtPoint")) | ||||
|                                     { | ||||
|                                         ap = Convert.ToInt32(xml.Value); | ||||
|                                         if (xml.MoveToAttribute("Asset")) | ||||
|                                         { | ||||
|                                             asset = new UUID(xml.Value); | ||||
|                                             if (xml.MoveToAttribute("Asset")) | ||||
|                                             { | ||||
|                                                 item = new UUID(xml.Value); | ||||
|                                                 rdata.userAppearance.SetAttachment(ap, item, asset); | ||||
|                                                 indata = true; | ||||
|                                             } | ||||
|                                         } | ||||
|                                     } | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Texture" : | ||||
|                                 if (xml.MoveToAttribute("Default")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.Texture = new Primitive.TextureEntry(new UUID(xml.Value)); | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Face" : | ||||
|                                 { | ||||
|                                     uint index; | ||||
|                                     if (xml.MoveToAttribute("Index")) | ||||
|                                     { | ||||
|                                         index = Convert.ToUInt32(xml.Value); | ||||
|                                         if (xml.MoveToAttribute("Id")) | ||||
|                                         { | ||||
|                                             rdata.userAppearance.Texture.CreateFace(index).TextureID = new UUID(xml.Value); | ||||
|                                             indata = true; | ||||
|                                         } | ||||
|                                     } | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "VisualParameters" : | ||||
|                                 { | ||||
|                                     xml.ReadContentAsBase64(rdata.userAppearance.VisualParams, | ||||
|                                                             0, rdata.userAppearance.VisualParams.Length); | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                         }  | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return indata; | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         private void FormatPart(AppearanceRequestData rdata, string part, UUID item, UUID asset) | ||||
|         { | ||||
|             if (item != UUID.Zero || asset != UUID.Zero) | ||||
|             { | ||||
|                 rdata.writer.WriteStartElement(part); | ||||
|                 if (item  != UUID.Zero) | ||||
|                 { | ||||
|                     rdata.writer.WriteAttributeString("Item",item.ToString()); | ||||
|                 } | ||||
| 
 | ||||
|                 if (asset != UUID.Zero) | ||||
|                 { | ||||
|                     rdata.writer.WriteAttributeString("Asset",asset.ToString()); | ||||
|                 } | ||||
|                 rdata.writer.WriteEndElement(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private void FormatUserAppearance(AppearanceRequestData rdata) | ||||
|         { | ||||
| 
 | ||||
|             Rest.Log.DebugFormat("{0} FormatUserAppearance", MsgId); | ||||
| 
 | ||||
|             if (rdata.userAppearance != null) | ||||
|             { | ||||
| 
 | ||||
|                 Rest.Log.DebugFormat("{0} FormatUserAppearance: appearance object exists", MsgId); | ||||
|                 rdata.writer.WriteStartElement("Appearance"); | ||||
| 
 | ||||
|                 rdata.writer.WriteAttributeString("Height", rdata.userAppearance.AvatarHeight.ToString()); | ||||
| //                if (rdata.userAppearance.Owner != UUID.Zero) | ||||
| //                    rdata.writer.WriteAttributeString("Owner", rdata.userAppearance.Owner.ToString()); | ||||
|                 rdata.writer.WriteAttributeString("Serial", rdata.userAppearance.Serial.ToString()); | ||||
| 
 | ||||
| /* | ||||
|                 FormatPart(rdata, "Body", rdata.userAppearance.BodyItem, rdata.userAppearance.BodyAsset); | ||||
|                 FormatPart(rdata, "Skin", rdata.userAppearance.SkinItem, rdata.userAppearance.SkinAsset); | ||||
|                 FormatPart(rdata, "Hair", rdata.userAppearance.HairItem, rdata.userAppearance.HairAsset); | ||||
|                 FormatPart(rdata, "Eyes", rdata.userAppearance.EyesItem, rdata.userAppearance.EyesAsset); | ||||
| 
 | ||||
|                 FormatPart(rdata, "Shirt", rdata.userAppearance.ShirtItem, rdata.userAppearance.ShirtAsset); | ||||
|                 FormatPart(rdata, "Pants", rdata.userAppearance.PantsItem, rdata.userAppearance.PantsAsset); | ||||
|                 FormatPart(rdata, "Skirt", rdata.userAppearance.SkirtItem, rdata.userAppearance.SkirtAsset); | ||||
|                 FormatPart(rdata, "Shoes", rdata.userAppearance.ShoesItem, rdata.userAppearance.ShoesAsset); | ||||
|                 FormatPart(rdata, "Socks", rdata.userAppearance.SocksItem, rdata.userAppearance.SocksAsset); | ||||
| 
 | ||||
|                 FormatPart(rdata, "Jacket", rdata.userAppearance.JacketItem, rdata.userAppearance.JacketAsset); | ||||
|                 FormatPart(rdata, "Gloves", rdata.userAppearance.GlovesItem, rdata.userAppearance.GlovesAsset); | ||||
| 
 | ||||
|                 FormatPart(rdata, "UnderShirt", rdata.userAppearance.UnderShirtItem, rdata.userAppearance.UnderShirtAsset); | ||||
|                 FormatPart(rdata, "UnderPants", rdata.userAppearance.UnderPantsItem, rdata.userAppearance.UnderPantsAsset); | ||||
| */ | ||||
|                 Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting attachments", MsgId); | ||||
| 
 | ||||
|                 rdata.writer.WriteStartElement("Attachments"); | ||||
|                 List<AvatarAttachment> attachments = rdata.userAppearance.GetAttachments(); | ||||
|                 foreach (AvatarAttachment attach in attachments) | ||||
|                 { | ||||
|                     rdata.writer.WriteStartElement("Attachment"); | ||||
|                     rdata.writer.WriteAttributeString("AtPoint", attach.AttachPoint.ToString()); | ||||
|                     rdata.writer.WriteAttributeString("Item", attach.ItemID.ToString()); | ||||
|                     rdata.writer.WriteAttributeString("Asset", attach.AssetID.ToString()); | ||||
|                     rdata.writer.WriteEndElement(); | ||||
|                 } | ||||
|                 rdata.writer.WriteEndElement(); | ||||
| 
 | ||||
|                 Primitive.TextureEntry texture = rdata.userAppearance.Texture; | ||||
| 
 | ||||
|                 if (texture != null && (texture.DefaultTexture != null || texture.FaceTextures != null)) | ||||
|                 { | ||||
|                     Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting textures", MsgId); | ||||
| 
 | ||||
|                     rdata.writer.WriteStartElement("Texture"); | ||||
| 
 | ||||
|                     if (texture.DefaultTexture != null) | ||||
|                     { | ||||
|                         Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting default texture", MsgId); | ||||
|                         rdata.writer.WriteAttributeString("Default", | ||||
|                             texture.DefaultTexture.TextureID.ToString()); | ||||
|                     } | ||||
| 
 | ||||
|                     if (texture.FaceTextures != null) | ||||
|                     { | ||||
| 
 | ||||
|                         Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting face textures", MsgId); | ||||
| 
 | ||||
|                         for (int i=0; i<texture.FaceTextures.Length;i++) | ||||
|                         { | ||||
|                             if (texture.FaceTextures[i] != null) | ||||
|                             { | ||||
|                                 rdata.writer.WriteStartElement("Face"); | ||||
|                                 rdata.writer.WriteAttributeString("Index", i.ToString()); | ||||
|                                 rdata.writer.WriteAttributeString("Id", | ||||
|                                         texture.FaceTextures[i].TextureID.ToString()); | ||||
|                                 rdata.writer.WriteEndElement(); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     rdata.writer.WriteEndElement(); | ||||
|                 } | ||||
| 
 | ||||
|                 Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting visual parameters", MsgId); | ||||
| 
 | ||||
|                 rdata.writer.WriteStartElement("VisualParameters"); | ||||
|                 rdata.writer.WriteBase64(rdata.userAppearance.VisualParams,0, | ||||
|                             rdata.userAppearance.VisualParams.Length); | ||||
|                 rdata.writer.WriteEndElement(); | ||||
|                 rdata.writer.WriteFullEndElement(); | ||||
|             } | ||||
| 
 | ||||
|             Rest.Log.DebugFormat("{0} FormatUserAppearance: completed", MsgId); | ||||
| 
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         #region appearance RequestData extension | ||||
| 
 | ||||
|         internal class AppearanceRequestData : RequestData | ||||
|         { | ||||
| 
 | ||||
|             /// <summary> | ||||
|             /// These are the inventory specific request/response state | ||||
|             /// extensions. | ||||
|             /// </summary> | ||||
| 
 | ||||
|             internal UUID                       uuid = UUID.Zero; | ||||
|             internal UserProfileData     userProfile = null; | ||||
|             internal AvatarAppearance userAppearance = null; | ||||
| 
 | ||||
|             internal AppearanceRequestData(OSHttpRequest request, OSHttpResponse response, string prefix) | ||||
|                 : base(request, response, prefix) | ||||
|             { | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         #endregion Appearance RequestData extension | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,383 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Xml; | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Servers; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.Rest.Inventory | ||||
| { | ||||
|     public class RestAssetServices : IRest | ||||
|     { | ||||
|         private bool    enabled = false; | ||||
|         private string  qPrefix = "assets"; | ||||
| 
 | ||||
|         // A simple constructor is used to handle any once-only | ||||
|         // initialization of working classes. | ||||
| 
 | ||||
|         public RestAssetServices() | ||||
|         { | ||||
|             Rest.Log.InfoFormat("{0} Asset services initializing", MsgId); | ||||
|             Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); | ||||
| 
 | ||||
|             // If the handler specifies a relative path for its domain | ||||
|             // then we must add the standard absolute prefix, e.g. /admin | ||||
| 
 | ||||
|             if (!qPrefix.StartsWith(Rest.UrlPathSeparator)) | ||||
|             { | ||||
|                 Rest.Log.InfoFormat("{0} Prefixing domain name ({1})", MsgId, qPrefix); | ||||
|                 qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix); | ||||
|                 Rest.Log.InfoFormat("{0} Fully qualified domain name is <{1}>", MsgId, qPrefix); | ||||
|             } | ||||
| 
 | ||||
|             // Register interface using the fully-qualified prefix | ||||
| 
 | ||||
|             Rest.Plugin.AddPathHandler(DoAsset, qPrefix, Allocate); | ||||
| 
 | ||||
|             // Activate if all went OK | ||||
| 
 | ||||
|             enabled = true; | ||||
| 
 | ||||
|             Rest.Log.InfoFormat("{0} Asset services initialization complete", MsgId); | ||||
|         } | ||||
| 
 | ||||
|         // Post-construction, pre-enabled initialization opportunity | ||||
|         // Not currently exploited. | ||||
| 
 | ||||
|         public void Initialize() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         // Called by the plug-in to halt REST processing. Local processing is | ||||
|         // disabled, and control blocks until all current processing has | ||||
|         // completed. No new processing will be started | ||||
| 
 | ||||
|         public void Close() | ||||
|         { | ||||
|             enabled = false; | ||||
|             Rest.Log.InfoFormat("{0} Asset services ({1}) closing down", MsgId, qPrefix); | ||||
|         } | ||||
| 
 | ||||
|         // Properties | ||||
| 
 | ||||
|         internal string MsgId | ||||
|         { | ||||
|             get { return Rest.MsgId; } | ||||
|         } | ||||
| 
 | ||||
|         #region Interface | ||||
| 
 | ||||
|         private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix) | ||||
|         { | ||||
|             return (RequestData) new AssetRequestData(request, response, prefix); | ||||
|         } | ||||
| 
 | ||||
|         // Asset Handler | ||||
| 
 | ||||
|         private void DoAsset(RequestData rparm) | ||||
|         { | ||||
|             if (!enabled) return; | ||||
| 
 | ||||
|             AssetRequestData rdata = (AssetRequestData) rparm; | ||||
| 
 | ||||
|             Rest.Log.DebugFormat("{0} REST Asset handler ({1}) ENTRY", MsgId, qPrefix); | ||||
| 
 | ||||
|             // Now that we know this is a serious attempt to | ||||
|             // access inventory data, we should find out who | ||||
|             // is asking, and make sure they are authorized | ||||
|             // to do so. We need to validate the caller's | ||||
|             // identity before revealing anything about the | ||||
|             // status quo. Authenticate throws an exception | ||||
|             // via Fail if no identity information is present. | ||||
|             // | ||||
|             // With the present HTTP server we can't use the | ||||
|             // builtin authentication mechanisms because they | ||||
|             // would be enforced for all in-bound requests. | ||||
|             // Instead we look at the headers ourselves and | ||||
|             // handle authentication directly. | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 if (!rdata.IsAuthenticated) | ||||
|                 { | ||||
|                     rdata.Fail(Rest.HttpStatusCodeNotAuthorized, String.Format("user \"{0}\" could not be authenticated")); | ||||
|                 } | ||||
|             } | ||||
|             catch (RestException e) | ||||
|             { | ||||
|                 if (e.statusCode == Rest.HttpStatusCodeNotAuthorized) | ||||
|                 { | ||||
|                     Rest.Log.WarnFormat("{0} User not authenticated", MsgId); | ||||
|                     Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, | ||||
|                                          rdata.request.Headers.Get("Authorization")); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     Rest.Log.ErrorFormat("{0} User authentication failed", MsgId); | ||||
|                     Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, | ||||
|                                          rdata.request.Headers.Get("Authorization")); | ||||
|                 } | ||||
|                 throw (e); | ||||
|             } | ||||
| 
 | ||||
|             // Remove the prefix and what's left are the parameters. If we don't have | ||||
|             // the parameters we need, fail the request. Parameters do NOT include | ||||
|             // any supplied query values. | ||||
| 
 | ||||
|             if (rdata.Parameters.Length > 0) | ||||
|             { | ||||
|                 switch (rdata.method) | ||||
|                 { | ||||
|                 case "get" : | ||||
|                     DoGet(rdata); | ||||
|                     break; | ||||
|                 case "put" : | ||||
|                     DoPut(rdata); | ||||
|                     break; | ||||
|                 case "post" : | ||||
|                     DoPost(rdata); | ||||
|                     break; | ||||
|                 case "delete" : | ||||
|                 default : | ||||
|                     Rest.Log.WarnFormat("{0} Asset: Method not supported: {1}", | ||||
|                                         MsgId, rdata.method); | ||||
|                     rdata.Fail(Rest.HttpStatusCodeBadRequest,String.Format("method <{0}> not supported", rdata.method)); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Rest.Log.WarnFormat("{0} Asset: No agent information provided", MsgId); | ||||
|                 rdata.Fail(Rest.HttpStatusCodeBadRequest, "no agent information provided"); | ||||
|             } | ||||
| 
 | ||||
|             Rest.Log.DebugFormat("{0} REST Asset handler EXIT", MsgId); | ||||
|         } | ||||
| 
 | ||||
|         #endregion Interface | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// The only parameter we recognize is a UUID.If an asset with this identification is | ||||
|         /// found, it's content, base-64 encoded, is returned to the client. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         private void DoGet(AssetRequestData rdata) | ||||
|         { | ||||
|             Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method); | ||||
| 
 | ||||
|             if (rdata.Parameters.Length == 1) | ||||
|             { | ||||
|                 UUID uuid = new UUID(rdata.Parameters[0]); | ||||
|                 AssetBase asset = Rest.AssetServices.Get(uuid.ToString()); | ||||
| 
 | ||||
|                 if (asset != null) | ||||
|                 { | ||||
|                     Rest.Log.DebugFormat("{0}  Asset located <{1}>", MsgId, rdata.Parameters[0]); | ||||
| 
 | ||||
|                     rdata.initXmlWriter(); | ||||
| 
 | ||||
|                     rdata.writer.WriteStartElement(String.Empty,"Asset",String.Empty); | ||||
| 
 | ||||
|                     rdata.writer.WriteAttributeString("id", asset.ID); | ||||
|                     rdata.writer.WriteAttributeString("name", asset.Name); | ||||
|                     rdata.writer.WriteAttributeString("desc", asset.Description); | ||||
|                     rdata.writer.WriteAttributeString("type", asset.Type.ToString()); | ||||
|                     rdata.writer.WriteAttributeString("local", asset.Local.ToString()); | ||||
|                     rdata.writer.WriteAttributeString("temporary", asset.Temporary.ToString()); | ||||
| 
 | ||||
|                     rdata.writer.WriteBase64(asset.Data,0,asset.Data.Length); | ||||
| 
 | ||||
|                     rdata.writer.WriteFullEndElement(); | ||||
| 
 | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path); | ||||
|                     rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters"); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             rdata.Complete(); | ||||
|             rdata.Respond(String.Format("Asset <{0}> : Normal completion", rdata.method)); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// UPDATE existing item, if it exists. URI identifies the item in question. | ||||
|         /// The only parameter we recognize is a UUID. The enclosed asset data (base-64 encoded) | ||||
|         /// is decoded and stored in the database, identified by the supplied UUID. | ||||
|         /// </summary> | ||||
|         private void DoPut(AssetRequestData rdata) | ||||
|         { | ||||
|             bool modified = false; | ||||
|             bool created  = false; | ||||
| 
 | ||||
|             AssetBase asset = null; | ||||
| 
 | ||||
|             Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method); | ||||
| 
 | ||||
|             if (rdata.Parameters.Length == 1) | ||||
|             { | ||||
| 
 | ||||
|                 rdata.initXmlReader(); | ||||
|                 XmlReader xml = rdata.reader; | ||||
| 
 | ||||
|                 if (!xml.ReadToFollowing("Asset")) | ||||
|                 { | ||||
|                     Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path); | ||||
|                     rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data"); | ||||
|                 } | ||||
| 
 | ||||
|                 UUID uuid = new UUID(rdata.Parameters[0]); | ||||
|                 asset = Rest.AssetServices.Get(uuid.ToString()); | ||||
| 
 | ||||
|                 modified = (asset != null); | ||||
|                 created  = !modified; | ||||
| 
 | ||||
|                 asset = new AssetBase(uuid, xml.GetAttribute("name"), SByte.Parse(xml.GetAttribute("type")), UUID.Zero.ToString()); | ||||
|                 asset.Description = xml.GetAttribute("desc"); | ||||
|                 asset.Local       = Int32.Parse(xml.GetAttribute("local")) != 0; | ||||
|                 asset.Temporary   = Int32.Parse(xml.GetAttribute("temporary")) != 0; | ||||
|                 asset.Data        = Convert.FromBase64String(xml.ReadElementContentAsString("Asset", "")); | ||||
| 
 | ||||
|                 if (asset.ID != rdata.Parameters[0]) | ||||
|                 { | ||||
|                     Rest.Log.WarnFormat("{0} URI and payload disagree on UUID U:{1} vs P:{2}", | ||||
|                                         MsgId, rdata.Parameters[0], asset.ID); | ||||
|                 } | ||||
| 
 | ||||
|                 Rest.AssetServices.Store(asset); | ||||
| 
 | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path); | ||||
|                 rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters"); | ||||
|             } | ||||
| 
 | ||||
|             if (created) | ||||
|             { | ||||
|                 rdata.appendStatus(String.Format("<p> Created asset {0}, UUID {1} <p>", asset.Name, asset.FullID)); | ||||
|                 rdata.Complete(Rest.HttpStatusCodeCreated); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (modified) | ||||
|                 { | ||||
|                     rdata.appendStatus(String.Format("<p> Modified asset {0}, UUID {1} <p>", asset.Name, asset.FullID)); | ||||
|                     rdata.Complete(Rest.HttpStatusCodeOK); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rdata.Complete(Rest.HttpStatusCodeNoContent); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             rdata.Respond(String.Format("Asset {0} : Normal completion", rdata.method)); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// CREATE new item, replace if it exists. URI identifies the context for the item in question. | ||||
|         /// No parameters are required for POST, just thepayload. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         private void DoPost(AssetRequestData rdata) | ||||
|         { | ||||
| 
 | ||||
|             bool modified = false; | ||||
|             bool created  = false; | ||||
| 
 | ||||
|             Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method); | ||||
| 
 | ||||
|             if (rdata.Parameters.Length != 0) | ||||
|             { | ||||
|                 Rest.Log.WarnFormat("{0} Parameters ignored <{1}>", MsgId, rdata.path); | ||||
|                 Rest.Log.InfoFormat("{0} POST of an asset has no parameters", MsgId, rdata.path); | ||||
|             } | ||||
| 
 | ||||
|             rdata.initXmlReader(); | ||||
|             XmlReader xml = rdata.reader; | ||||
| 
 | ||||
|             if (!xml.ReadToFollowing("Asset")) | ||||
|             { | ||||
|                 Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path); | ||||
|                 rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data"); | ||||
|             } | ||||
| 
 | ||||
|             UUID uuid = new UUID(xml.GetAttribute("id")); | ||||
|             AssetBase asset = Rest.AssetServices.Get(uuid.ToString()); | ||||
| 
 | ||||
|             modified = (asset != null); | ||||
|             created  = !modified; | ||||
| 
 | ||||
|             asset             = new AssetBase(uuid, xml.GetAttribute("name"), SByte.Parse(xml.GetAttribute("type")), UUID.Zero.ToString()); | ||||
|             asset.Description = xml.GetAttribute("desc"); | ||||
|             asset.Local       = Int32.Parse(xml.GetAttribute("local")) != 0; | ||||
|             asset.Temporary   = Int32.Parse(xml.GetAttribute("temporary")) != 0; | ||||
|             asset.Data        = Convert.FromBase64String(xml.ReadElementContentAsString("Asset", "")); | ||||
| 
 | ||||
|             Rest.AssetServices.Store(asset); | ||||
| 
 | ||||
|             if (created) | ||||
|             { | ||||
|                 rdata.appendStatus(String.Format("<p> Created asset {0}, UUID {1} <p>", asset.Name, asset.FullID)); | ||||
|                 rdata.Complete(Rest.HttpStatusCodeCreated); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (modified) | ||||
|                 { | ||||
|                     rdata.appendStatus(String.Format("<p> Modified asset {0}, UUID {1} <p>", asset.Name, asset.FullID)); | ||||
|                     rdata.Complete(Rest.HttpStatusCodeOK); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rdata.Complete(Rest.HttpStatusCodeNoContent); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             rdata.Respond(String.Format("Asset {0} : Normal completion", rdata.method)); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Asset processing has no special data area requirements. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         internal class AssetRequestData : RequestData | ||||
|         { | ||||
|             internal AssetRequestData(OSHttpRequest request, OSHttpResponse response, string prefix) | ||||
|                 : base(request, response, prefix) | ||||
|             { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,448 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Xml; | ||||
| using System.IO; | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Servers; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.Rest.Inventory | ||||
| { | ||||
|     public class RestFileServices : IRest | ||||
|     { | ||||
|         private bool    enabled = false; | ||||
|         private string  qPrefix = "files"; | ||||
| 
 | ||||
|         // A simple constructor is used to handle any once-only | ||||
|         // initialization of working classes. | ||||
| 
 | ||||
|         public RestFileServices() | ||||
|         { | ||||
|             Rest.Log.InfoFormat("{0} File services initializing", MsgId); | ||||
|             Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); | ||||
| 
 | ||||
|             // If the handler specifies a relative path for its domain | ||||
|             // then we must add the standard absolute prefix, e.g. /admin | ||||
| 
 | ||||
|             if (!qPrefix.StartsWith(Rest.UrlPathSeparator)) | ||||
|             { | ||||
|                 Rest.Log.InfoFormat("{0} Prefixing domain name ({1})", MsgId, qPrefix); | ||||
|                 qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix); | ||||
|                 Rest.Log.InfoFormat("{0} Fully qualified domain name is <{1}>", MsgId, qPrefix); | ||||
|             } | ||||
| 
 | ||||
|             // Register interface using the fully-qualified prefix | ||||
| 
 | ||||
|             Rest.Plugin.AddPathHandler(DoFile, qPrefix, Allocate); | ||||
| 
 | ||||
|             // Activate if all went OK | ||||
| 
 | ||||
|             enabled = true; | ||||
| 
 | ||||
|             Rest.Log.InfoFormat("{0} File services initialization complete", MsgId); | ||||
|         } | ||||
| 
 | ||||
|         // Post-construction, pre-enabled initialization opportunity | ||||
|         // Not currently exploited. | ||||
| 
 | ||||
|         public void Initialize() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         // Called by the plug-in to halt REST processing. Local processing is | ||||
|         // disabled, and control blocks until all current processing has | ||||
|         // completed. No new processing will be started | ||||
| 
 | ||||
|         public void Close() | ||||
|         { | ||||
|             enabled = false; | ||||
|             Rest.Log.InfoFormat("{0} File services ({1}) closing down", MsgId, qPrefix); | ||||
|         } | ||||
| 
 | ||||
|         // Properties | ||||
| 
 | ||||
|         internal string MsgId | ||||
|         { | ||||
|             get { return Rest.MsgId; } | ||||
|         } | ||||
| 
 | ||||
|         #region Interface | ||||
| 
 | ||||
|         private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix) | ||||
|         { | ||||
|             return (RequestData) new FileRequestData(request, response, prefix); | ||||
|         } | ||||
| 
 | ||||
|         // Asset Handler | ||||
| 
 | ||||
|         private void DoFile(RequestData rparm) | ||||
|         { | ||||
|             if (!enabled) return; | ||||
| 
 | ||||
|             FileRequestData rdata = (FileRequestData) rparm; | ||||
| 
 | ||||
|             Rest.Log.DebugFormat("{0} REST File handler ({1}) ENTRY", MsgId, qPrefix); | ||||
| 
 | ||||
|             // Now that we know this is a serious attempt to | ||||
|             // access file data, we should find out who | ||||
|             // is asking, and make sure they are authorized | ||||
|             // to do so. We need to validate the caller's | ||||
|             // identity before revealing anything about the | ||||
|             // status quo. Authenticate throws an exception | ||||
|             // via Fail if no identity information is present. | ||||
|             // | ||||
|             // With the present HTTP server we can't use the | ||||
|             // builtin authentication mechanisms because they | ||||
|             // would be enforced for all in-bound requests. | ||||
|             // Instead we look at the headers ourselves and | ||||
|             // handle authentication directly. | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 if (!rdata.IsAuthenticated) | ||||
|                 { | ||||
|                     rdata.Fail(Rest.HttpStatusCodeNotAuthorized, String.Format("user \"{0}\" could not be authenticated")); | ||||
|                 } | ||||
|             } | ||||
|             catch (RestException e) | ||||
|             { | ||||
|                 if (e.statusCode == Rest.HttpStatusCodeNotAuthorized) | ||||
|                 { | ||||
|                     Rest.Log.WarnFormat("{0} User not authenticated", MsgId); | ||||
|                     Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, | ||||
|                                          rdata.request.Headers.Get("Authorization")); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     Rest.Log.ErrorFormat("{0} User authentication failed", MsgId); | ||||
|                     Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, | ||||
|                                          rdata.request.Headers.Get("Authorization")); | ||||
|                 } | ||||
|                 throw (e); | ||||
|             } | ||||
| 
 | ||||
|             // Remove the prefix and what's left are the parameters. If we don't have | ||||
|             // the parameters we need, fail the request. Parameters do NOT include | ||||
|             // any supplied query values. | ||||
| 
 | ||||
|             if (rdata.Parameters.Length > 0) | ||||
|             { | ||||
|                 switch (rdata.method) | ||||
|                 { | ||||
|                 case "get" : | ||||
|                     DoGet(rdata); | ||||
|                     break; | ||||
|                 case "put" : | ||||
|                     DoPut(rdata); | ||||
|                     break; | ||||
|                 case "post" : | ||||
|                     DoPost(rdata); | ||||
|                     break; | ||||
|                 case "delete" : | ||||
|                     DoDelete(rdata); | ||||
|                     break; | ||||
|                 default : | ||||
|                     Rest.Log.WarnFormat("{0} File: Method not supported: {1}", | ||||
|                                         MsgId, rdata.method); | ||||
|                     rdata.Fail(Rest.HttpStatusCodeBadRequest,String.Format("method <{0}> not supported", rdata.method)); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Rest.Log.WarnFormat("{0} File: No agent information provided", MsgId); | ||||
|                 rdata.Fail(Rest.HttpStatusCodeBadRequest, "no agent information provided"); | ||||
|             } | ||||
| 
 | ||||
|             Rest.Log.DebugFormat("{0} REST File handler EXIT", MsgId); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         #endregion Interface | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// The only parameter we recognize is a UUID.If an asset with this identification is | ||||
|         /// found, it's content, base-64 encoded, is returned to the client. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         private void DoGet(FileRequestData rdata) | ||||
|         { | ||||
| 
 | ||||
|             string path = String.Empty; | ||||
| 
 | ||||
|             Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method); | ||||
| 
 | ||||
|             if (rdata.Parameters.Length > 1) | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2); | ||||
|                     if (File.Exists(path)) | ||||
|                     { | ||||
|                         Rest.Log.DebugFormat("{0}  File located <{1}>", MsgId, path); | ||||
|                         Byte[] data = File.ReadAllBytes(path); | ||||
|                         rdata.initXmlWriter(); | ||||
|                         rdata.writer.WriteStartElement(String.Empty,"File",String.Empty); | ||||
|                         rdata.writer.WriteAttributeString("name", path); | ||||
|                         rdata.writer.WriteBase64(data,0,data.Length); | ||||
|                         rdata.writer.WriteFullEndElement(); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, path); | ||||
|                         rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0}", path)); | ||||
|                     } | ||||
|                 } | ||||
|                 catch (Exception e) | ||||
|                 { | ||||
|                     Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, e.Message); | ||||
|                     rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0} {1}",  | ||||
|                                      path, e.Message)); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             rdata.Complete(); | ||||
|             rdata.Respond(String.Format("File <{0}> : Normal completion", rdata.method)); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// UPDATE existing item, if it exists. URI identifies the item in question. | ||||
|         /// The only parameter we recognize is a UUID. The enclosed asset data (base-64 encoded) | ||||
|         /// is decoded and stored in the database, identified by the supplied UUID. | ||||
|         /// </summary> | ||||
|         private void DoPut(FileRequestData rdata) | ||||
|         { | ||||
|             bool modified = false; | ||||
|             bool created  = false; | ||||
|             string path   = String.Empty; | ||||
| 
 | ||||
|             Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method); | ||||
| 
 | ||||
|             if (rdata.Parameters.Length > 1) | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2); | ||||
|                     bool maymod = File.Exists(path); | ||||
|                      | ||||
|                     rdata.initXmlReader(); | ||||
|                     XmlReader xml = rdata.reader; | ||||
| 
 | ||||
|                     if (!xml.ReadToFollowing("File")) | ||||
|                     { | ||||
|                         Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path); | ||||
|                         rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data"); | ||||
|                     } | ||||
| 
 | ||||
|                     Byte[] data = Convert.FromBase64String(xml.ReadElementContentAsString("File", "")); | ||||
| 
 | ||||
|                     File.WriteAllBytes(path,data); | ||||
|                     modified =   maymod; | ||||
|                     created  = ! maymod; | ||||
|                 } | ||||
|                 catch (Exception e) | ||||
|                 { | ||||
|                     Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId,  | ||||
|                           e.Message); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path); | ||||
|                 rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters"); | ||||
|             } | ||||
| 
 | ||||
|             if (created) | ||||
|             { | ||||
|                 rdata.appendStatus(String.Format("<p> Created file {0} <p>", path)); | ||||
|                 rdata.Complete(Rest.HttpStatusCodeCreated); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (modified) | ||||
|                 { | ||||
|                     rdata.appendStatus(String.Format("<p> Modified file {0} <p>", path)); | ||||
|                     rdata.Complete(Rest.HttpStatusCodeOK); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rdata.Complete(Rest.HttpStatusCodeNoContent); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             rdata.Respond(String.Format("File {0} : Normal completion", rdata.method)); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// CREATE new item, replace if it exists. URI identifies the context for the item in question. | ||||
|         /// No parameters are required for POST, just thepayload. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         private void DoPost(FileRequestData rdata) | ||||
|         { | ||||
| 
 | ||||
|             bool modified = false; | ||||
|             bool created  = false; | ||||
|             string path   = String.Empty; | ||||
| 
 | ||||
|             Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method); | ||||
| 
 | ||||
|             if (rdata.Parameters.Length > 1) | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2); | ||||
|                     bool maymod = File.Exists(path); | ||||
|                      | ||||
|                     rdata.initXmlReader(); | ||||
|                     XmlReader xml = rdata.reader; | ||||
| 
 | ||||
|                     if (!xml.ReadToFollowing("File")) | ||||
|                     { | ||||
|                         Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path); | ||||
|                         rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data"); | ||||
|                     } | ||||
| 
 | ||||
|                     Byte[] data = Convert.FromBase64String(xml.ReadElementContentAsString("File", "")); | ||||
| 
 | ||||
|                     File.WriteAllBytes(path,data); | ||||
|                     modified =   maymod; | ||||
|                     created  = ! maymod; | ||||
|                 } | ||||
|                 catch (Exception e) | ||||
|                 { | ||||
|                     Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId,  | ||||
|                           e.Message); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path); | ||||
|                 rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters"); | ||||
|             } | ||||
| 
 | ||||
|             if (created) | ||||
|             { | ||||
|                 rdata.appendStatus(String.Format("<p> Created file {0} <p>", path)); | ||||
|                 rdata.Complete(Rest.HttpStatusCodeCreated); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (modified) | ||||
|                 { | ||||
|                     rdata.appendStatus(String.Format("<p> Modified file {0} <p>", path)); | ||||
|                     rdata.Complete(Rest.HttpStatusCodeOK); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rdata.Complete(Rest.HttpStatusCodeNoContent); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             rdata.Respond(String.Format("File {0} : Normal completion", rdata.method)); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// CREATE new item, replace if it exists. URI identifies the context for the item in question. | ||||
|         /// No parameters are required for POST, just thepayload. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         private void DoDelete(FileRequestData rdata) | ||||
|         { | ||||
| 
 | ||||
|             bool modified = false; | ||||
|             bool created  = false; | ||||
|             string path   = String.Empty; | ||||
| 
 | ||||
|             Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method); | ||||
| 
 | ||||
|             if (rdata.Parameters.Length > 1) | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2); | ||||
| 
 | ||||
|                     if (File.Exists(path)) | ||||
|                     { | ||||
|                         File.Delete(path); | ||||
|                     } | ||||
|                 } | ||||
|                 catch (Exception e) | ||||
|                 { | ||||
|                     Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId,  | ||||
|                           e.Message); | ||||
|                     rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0} {1}", | ||||
|                           path, e.Message)); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path); | ||||
|                 rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters"); | ||||
|             } | ||||
| 
 | ||||
|             if (created) | ||||
|             { | ||||
|                 rdata.appendStatus(String.Format("<p> Created file {0} <p>", path)); | ||||
|                 rdata.Complete(Rest.HttpStatusCodeCreated); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (modified) | ||||
|                 { | ||||
|                     rdata.appendStatus(String.Format("<p> Modified file {0} <p>", path)); | ||||
|                     rdata.Complete(Rest.HttpStatusCodeOK); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rdata.Complete(Rest.HttpStatusCodeNoContent); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             rdata.Respond(String.Format("File {0} : Normal completion", rdata.method)); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// File processing has no special data area requirements. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         internal class FileRequestData : RequestData | ||||
|         { | ||||
|             internal FileRequestData(OSHttpRequest request, OSHttpResponse response, string prefix) | ||||
|                 : base(request, response, prefix) | ||||
|             { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,659 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Reflection; | ||||
| using OpenSim.Framework.Servers; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.Rest.Inventory | ||||
| { | ||||
|     /// <remarks> | ||||
|     /// The class signature reveals the roles that RestHandler plays. | ||||
|     /// | ||||
|     /// [1] It is a sub-class of RestPlugin. It inherits and extends | ||||
|     ///     the functionality of this class, constraining it to the | ||||
|     ///     specific needs of this REST implementation. This relates | ||||
|     ///     to the plug-in mechanism supported by OpenSim, the specifics | ||||
|     ///     of which are mostly hidden by RestPlugin. | ||||
|     /// [2] IRestHandler describes the interface that this class | ||||
|     ///     exports to service implementations. This is the services | ||||
|     ///     management interface. | ||||
|     /// [3] IHttpAgentHandler describes the interface that is exported | ||||
|     ///     to the BaseHttpServer in support of this particular HTTP | ||||
|     ///     processing model. This is the request interface of the | ||||
|     ///     handler. | ||||
|     /// </remarks> | ||||
| 
 | ||||
|     public class RestHandler : RestPlugin, IRestHandler, IHttpAgentHandler | ||||
|     { | ||||
|         // Handler tables: both stream and REST are supported. The path handlers and their | ||||
|         // respective allocators are stored in separate tables. | ||||
| 
 | ||||
|         internal Dictionary<string,RestMethodHandler>   pathHandlers   = new Dictionary<string,RestMethodHandler>(); | ||||
|         internal Dictionary<string,RestMethodAllocator> pathAllocators = new Dictionary<string,RestMethodAllocator>(); | ||||
|         internal Dictionary<string,RestStreamHandler>   streamHandlers = new Dictionary<string,RestStreamHandler>(); | ||||
| 
 | ||||
|         #region local static state | ||||
| 
 | ||||
|         private static bool  handlersLoaded = false; | ||||
|         private static List<Type>  classes  = new List<Type>(); | ||||
|         private static List<IRest> handlers = new List<IRest>(); | ||||
|         private static Type[]         parms = new Type[0]; | ||||
|         private static Object[]       args  = new Object[0]; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// This static initializer scans the ASSEMBLY for classes that | ||||
|         /// export the IRest interface and builds a list of them. These | ||||
|         /// are later activated by the handler. To add a new handler it | ||||
|         /// is only necessary to create a new services class that implements | ||||
|         /// the IRest interface, and recompile the handler. This gives | ||||
|         /// all of the build-time flexibility of a modular approach | ||||
|         /// while not introducing yet-another module loader. Note that | ||||
|         /// multiple assembles can still be built, each with its own set | ||||
|         /// of handlers. Examples of services classes are RestInventoryServices | ||||
|         /// and RestSkeleton. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         static RestHandler() | ||||
|         { | ||||
|             Module[] mods = Assembly.GetExecutingAssembly().GetModules(); | ||||
| 
 | ||||
|             foreach (Module m in mods) | ||||
|             { | ||||
|                 Type[] types = m.GetTypes(); | ||||
|                 foreach (Type t in types) | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         if (t.GetInterface("IRest") != null) | ||||
|                         { | ||||
|                             classes.Add(t); | ||||
|                         } | ||||
|                     } | ||||
|                     catch (Exception) | ||||
|                     { | ||||
|                         Rest.Log.WarnFormat("[STATIC-HANDLER]: #0 Error scanning {1}", t); | ||||
|                         Rest.Log.InfoFormat("[STATIC-HANDLER]: #0 {1} is not included", t); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #endregion local static state | ||||
| 
 | ||||
|         #region local instance state | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// This routine loads all of the handlers discovered during | ||||
|         /// instance initialization. | ||||
|         /// A table of all loaded and successfully constructed handlers | ||||
|         /// is built, and this table is then used by the constructor to | ||||
|         /// initialize each of the handlers in turn. | ||||
|         /// NOTE: The loading process does not automatically imply that | ||||
|         /// the handler has registered any kind of an interface, that | ||||
|         /// may be (optionally) done by the handler either during | ||||
|         /// construction, or during initialization. | ||||
|         /// | ||||
|         /// I was not able to make this code work within a constructor | ||||
|         /// so it is isolated within this method. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         private void LoadHandlers() | ||||
|         { | ||||
|             lock (handlers) | ||||
|             { | ||||
|                 if (!handlersLoaded) | ||||
|                 { | ||||
|                     ConstructorInfo ci; | ||||
|                     Object          ht; | ||||
| 
 | ||||
|                     foreach (Type t in classes) | ||||
|                     { | ||||
|                         try | ||||
|                         { | ||||
|                             ci = t.GetConstructor(parms); | ||||
|                             ht = ci.Invoke(args); | ||||
|                             handlers.Add((IRest)ht); | ||||
|                         } | ||||
|                         catch (Exception e) | ||||
|                         { | ||||
|                             Rest.Log.WarnFormat("{0} Unable to load {1} : {2}", MsgId, t, e.Message); | ||||
|                         } | ||||
|                     } | ||||
|                     handlersLoaded = true; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #endregion local instance state | ||||
| 
 | ||||
|         #region overriding properties | ||||
| 
 | ||||
|         // These properties override definitions | ||||
|         // in the base class. | ||||
| 
 | ||||
|         // Name is used to differentiate the message header. | ||||
| 
 | ||||
|         public override string Name | ||||
|         { | ||||
|             get { return "HANDLER"; } | ||||
|         } | ||||
| 
 | ||||
|         // Used to partition the .ini configuration space. | ||||
| 
 | ||||
|         public override string ConfigName | ||||
|         { | ||||
|             get { return "RestHandler"; } | ||||
|         } | ||||
| 
 | ||||
|         // We have to rename these because we want | ||||
|         // to be able to share the values with other | ||||
|         // classes in our assembly and the base | ||||
|         // names are protected. | ||||
| 
 | ||||
|         public string MsgId | ||||
|         { | ||||
|             get { return base.MsgID; } | ||||
|         } | ||||
| 
 | ||||
|         public string RequestId | ||||
|         { | ||||
|             get { return base.RequestID; } | ||||
|         } | ||||
| 
 | ||||
|         #endregion overriding properties | ||||
| 
 | ||||
|         #region overriding methods | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// This method is called by OpenSimMain immediately after loading the | ||||
|         /// plugin and after basic server setup,  but before running any server commands. | ||||
|         /// </summary> | ||||
|         /// <remarks> | ||||
|         /// Note that entries MUST be added to the active configuration files before | ||||
|         /// the plugin can be enabled. | ||||
|         /// </remarks> | ||||
| 
 | ||||
|         public override void Initialise(OpenSimBase openSim) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 // This plugin will only be enabled if the broader | ||||
|                 // REST plugin mechanism is enabled. | ||||
| 
 | ||||
|                 //Rest.Log.InfoFormat("{0}  Plugin is initializing", MsgId); | ||||
| 
 | ||||
|                 base.Initialise(openSim); | ||||
| 
 | ||||
|                 // IsEnabled is implemented by the base class and | ||||
|                 // reflects an overall RestPlugin status | ||||
| 
 | ||||
|                 if (!IsEnabled) | ||||
|                 { | ||||
|                     //Rest.Log.WarnFormat("{0} Plugins are disabled", MsgId); | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 Rest.Log.InfoFormat("{0} Rest <{1}> plugin will be enabled", MsgId, Name); | ||||
|                 Rest.Log.InfoFormat("{0} Configuration parameters read from <{1}>", MsgId, ConfigName); | ||||
| 
 | ||||
|                 // These are stored in static variables to make | ||||
|                 // them easy to reach from anywhere in the assembly. | ||||
| 
 | ||||
|                 Rest.main              = openSim; | ||||
|                 if (Rest.main == null) | ||||
|                     throw new Exception("OpenSim base pointer is null"); | ||||
| 
 | ||||
|                 Rest.Plugin            = this; | ||||
|                 Rest.Config            = Config; | ||||
|                 Rest.Prefix            = Prefix; | ||||
|                 Rest.GodKey            = GodKey; | ||||
|                 Rest.Authenticate      = Rest.Config.GetBoolean("authenticate", Rest.Authenticate); | ||||
|                 Rest.Scheme            = Rest.Config.GetString("auth-scheme", Rest.Scheme); | ||||
|                 Rest.Secure            = Rest.Config.GetBoolean("secured", Rest.Secure); | ||||
|                 Rest.ExtendedEscape    = Rest.Config.GetBoolean("extended-escape", Rest.ExtendedEscape); | ||||
|                 Rest.Realm             = Rest.Config.GetString("realm", Rest.Realm); | ||||
|                 Rest.DumpAsset         = Rest.Config.GetBoolean("dump-asset", Rest.DumpAsset); | ||||
|                 Rest.Fill              = Rest.Config.GetBoolean("path-fill", Rest.Fill); | ||||
|                 Rest.DumpLineSize      = Rest.Config.GetInt("dump-line-size", Rest.DumpLineSize); | ||||
|                 Rest.FlushEnabled      = Rest.Config.GetBoolean("flush-on-error", Rest.FlushEnabled); | ||||
| 
 | ||||
|                 // Note: Odd spacing is required in the following strings | ||||
| 
 | ||||
|                 Rest.Log.InfoFormat("{0} Authentication is {1}required", MsgId, | ||||
|                                     (Rest.Authenticate ? "" : "not ")); | ||||
| 
 | ||||
|                 Rest.Log.InfoFormat("{0} Security is {1}enabled", MsgId, | ||||
|                                     (Rest.Secure ? "" : "not ")); | ||||
| 
 | ||||
|                 Rest.Log.InfoFormat("{0} Extended URI escape processing is {1}enabled", MsgId, | ||||
|                                     (Rest.ExtendedEscape ? "" : "not ")); | ||||
| 
 | ||||
|                 Rest.Log.InfoFormat("{0} Dumping of asset data is {1}enabled", MsgId, | ||||
|                                     (Rest.DumpAsset ? "" : "not ")); | ||||
| 
 | ||||
|                 // The supplied prefix MUST be absolute | ||||
| 
 | ||||
|                 if (Rest.Prefix.Substring(0,1) != Rest.UrlPathSeparator) | ||||
|                 { | ||||
|                     Rest.Log.WarnFormat("{0} Prefix <{1}> is not absolute and must be", MsgId, Rest.Prefix); | ||||
|                     Rest.Log.InfoFormat("{0} Prefix changed to </{1}>", MsgId, Rest.Prefix); | ||||
|                     Rest.Prefix = String.Format("{0}{1}", Rest.UrlPathSeparator, Rest.Prefix); | ||||
|                 } | ||||
| 
 | ||||
|                 // If data dumping is requested, report on the chosen line | ||||
|                 // length. | ||||
| 
 | ||||
|                 if (Rest.DumpAsset) | ||||
|                 { | ||||
|                     Rest.Log.InfoFormat("{0} Dump {1} bytes per line", MsgId, Rest.DumpLineSize); | ||||
|                 } | ||||
| 
 | ||||
|                 // Load all of the handlers present in the | ||||
|                 // assembly | ||||
| 
 | ||||
|                 // In principle, as we're an application plug-in, | ||||
|                 // most of what needs to be done could be done using | ||||
|                 // static resources, however the Open Sim plug-in | ||||
|                 // model makes this an instance, so that's what we | ||||
|                 // need to be. | ||||
|                 // There is only one Communications manager per | ||||
|                 // server, and by inference, only one each of the | ||||
|                 // user, asset, and inventory servers. So we can cache | ||||
|                 // those using a static initializer. | ||||
|                 // We move all of this processing off to another | ||||
|                 // services class to minimize overlap between function | ||||
|                 // and infrastructure. | ||||
| 
 | ||||
|                 LoadHandlers(); | ||||
| 
 | ||||
|                 // The intention of a post construction initializer | ||||
|                 // is to allow for setup that is dependent upon other | ||||
|                 // activities outside of the agency. | ||||
| 
 | ||||
|                 foreach (IRest handler in handlers) | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         handler.Initialize(); | ||||
|                     } | ||||
|                     catch (Exception e) | ||||
|                     { | ||||
|                         Rest.Log.ErrorFormat("{0} initialization error: {1}", MsgId, e.Message); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 // Now that everything is setup we can proceed to | ||||
|                 // add THIS agent to the HTTP server's handler list | ||||
| 
 | ||||
|                 if (!AddAgentHandler(Rest.Name,this)) | ||||
|                 { | ||||
|                     Rest.Log.ErrorFormat("{0} Unable to activate handler interface", MsgId); | ||||
|                     foreach (IRest handler in handlers) | ||||
|                     { | ||||
|                         handler.Close(); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 Rest.Log.ErrorFormat("{0} Plugin initialization has failed: {1}", MsgId, e.Message); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// In the interests of efficiency, and because we cannot determine whether | ||||
|         /// or not this instance will actually be harvested, we clobber the only | ||||
|         /// anchoring reference to the working state for this plug-in. What the | ||||
|         /// call to close does is irrelevant to this class beyond knowing that it | ||||
|         /// can nullify the reference when it returns. | ||||
|         /// To make sure everything is copacetic we make sure the primary interface | ||||
|         /// is disabled by deleting the handler from the HTTP server tables. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         public override void Close() | ||||
|         { | ||||
|             Rest.Log.InfoFormat("{0} Plugin is terminating", MsgId); | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 RemoveAgentHandler(Rest.Name, this); | ||||
|             } | ||||
|             catch (KeyNotFoundException){} | ||||
| 
 | ||||
|             foreach (IRest handler in handlers) | ||||
|             { | ||||
|                 handler.Close(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #endregion overriding methods | ||||
| 
 | ||||
|         #region interface methods | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// This method is called by the HTTP server to match an incoming | ||||
|         /// request. It scans all of the strings registered by the | ||||
|         /// underlying handlers and looks for the best match. It returns | ||||
|         /// true if a match is found. | ||||
|         /// The matching process could be made arbitrarily complex. | ||||
|         /// Note: The match is case-insensitive. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         public bool Match(OSHttpRequest request, OSHttpResponse response) | ||||
|         { | ||||
| 
 | ||||
|             string path = request.RawUrl.ToLower(); | ||||
| 
 | ||||
|             // Rest.Log.DebugFormat("{0} Match ENTRY", MsgId); | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 foreach (string key in pathHandlers.Keys) | ||||
|                 { | ||||
|                     // Rest.Log.DebugFormat("{0} Match testing {1} against agent prefix <{2}>", MsgId, path, key); | ||||
| 
 | ||||
|                     // Note that Match will not necessarily find the handler that will | ||||
|                     // actually be used - it does no test for the "closest" fit. It | ||||
|                     // simply reflects that at least one possible handler exists. | ||||
| 
 | ||||
|                     if (path.StartsWith(key)) | ||||
|                     { | ||||
|                         // Rest.Log.DebugFormat("{0} Matched prefix <{1}>", MsgId, key); | ||||
| 
 | ||||
|                         // This apparently odd evaluation is needed to prevent a match | ||||
|                         // on anything other than a URI token boundary. Otherwise we | ||||
|                         // may match on URL's that were not intended for this handler. | ||||
| 
 | ||||
|                         return (path.Length == key.Length || | ||||
|                                 path.Substring(key.Length, 1) == Rest.UrlPathSeparator); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 path = String.Format("{0}{1}{2}", request.HttpMethod, Rest.UrlMethodSeparator, path); | ||||
| 
 | ||||
|                 foreach (string key in streamHandlers.Keys) | ||||
|                 { | ||||
|                     // Rest.Log.DebugFormat("{0} Match testing {1} against stream prefix <{2}>", MsgId, path, key); | ||||
| 
 | ||||
|                     // Note that Match will not necessarily find the handler that will | ||||
|                     // actually be used - it does no test for the "closest" fit. It | ||||
|                     // simply reflects that at least one possible handler exists. | ||||
| 
 | ||||
|                     if (path.StartsWith(key)) | ||||
|                     { | ||||
|                         // Rest.Log.DebugFormat("{0} Matched prefix <{1}>", MsgId, key); | ||||
| 
 | ||||
|                         // This apparently odd evaluation is needed to prevent a match | ||||
|                         // on anything other than a URI token boundary. Otherwise we | ||||
|                         // may match on URL's that were not intended for this handler. | ||||
| 
 | ||||
|                         return (path.Length == key.Length || | ||||
|                                 path.Substring(key.Length, 1) == Rest.UrlPathSeparator); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 Rest.Log.ErrorFormat("{0} matching exception for path <{1}> : {2}", MsgId, path, e.Message); | ||||
|             } | ||||
| 
 | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// This is called by the HTTP server once the handler has indicated | ||||
|         /// that it is able to handle the request. | ||||
|         /// Preconditions: | ||||
|         ///  [1] request  != null and is a valid request object | ||||
|         ///  [2] response != null and is a valid response object | ||||
|         /// Behavior is undefined if preconditions are not satisfied. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         public bool Handle(OSHttpRequest request, OSHttpResponse response) | ||||
|         { | ||||
|             bool handled; | ||||
|             base.MsgID = base.RequestID; | ||||
| 
 | ||||
|             // Debug only | ||||
| 
 | ||||
|             if (Rest.DEBUG) | ||||
|             { | ||||
|                 Rest.Log.DebugFormat("{0} ENTRY", MsgId); | ||||
|                 Rest.Log.DebugFormat("{0}  Agent: {1}", MsgId, request.UserAgent); | ||||
|                 Rest.Log.DebugFormat("{0} Method: {1}", MsgId, request.HttpMethod); | ||||
| 
 | ||||
|                 for (int i = 0; i < request.Headers.Count; i++) | ||||
|                 { | ||||
|                     Rest.Log.DebugFormat("{0} Header [{1}] : <{2}> = <{3}>", | ||||
|                                          MsgId, i, request.Headers.GetKey(i), request.Headers.Get(i)); | ||||
|                 } | ||||
|                 Rest.Log.DebugFormat("{0}    URI: {1}", MsgId, request.RawUrl); | ||||
|             } | ||||
| 
 | ||||
|             // If a path handler worked we're done, otherwise try any | ||||
|             // available stream handlers too. | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 handled = (FindPathHandler(request, response) || | ||||
|                     FindStreamHandler(request, response)); | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 // A raw exception indicates that something we weren't expecting has | ||||
|                 // happened. This should always reflect a shortcoming in the plugin, | ||||
|                 // or a failure to satisfy the preconditions. It should not reflect | ||||
|                 // an error in the request itself. Under such circumstances the state | ||||
|                 // of the request cannot be determined and we are obliged to mark it | ||||
|                 // as 'handled'. | ||||
| 
 | ||||
|                 Rest.Log.ErrorFormat("{0} Plugin error: {1}", MsgId, e.Message); | ||||
|                 handled = true; | ||||
|             } | ||||
| 
 | ||||
|             Rest.Log.DebugFormat("{0} EXIT", MsgId); | ||||
| 
 | ||||
|             return handled; | ||||
|         } | ||||
| 
 | ||||
|         #endregion interface methods | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// If there is a stream handler registered that can handle the | ||||
|         /// request, then fine. If the request is not matched, do | ||||
|         /// nothing. | ||||
|         /// Note: The selection is case-insensitive | ||||
|         /// </summary> | ||||
| 
 | ||||
|         private bool FindStreamHandler(OSHttpRequest request, OSHttpResponse response) | ||||
|         { | ||||
|             RequestData rdata = new RequestData(request, response, String.Empty); | ||||
| 
 | ||||
|             string bestMatch = String.Empty; | ||||
|             string path      = String.Format("{0}:{1}", rdata.method, rdata.path).ToLower(); | ||||
| 
 | ||||
|             Rest.Log.DebugFormat("{0} Checking for stream handler for <{1}>", MsgId, path); | ||||
| 
 | ||||
|             if (!IsEnabled) | ||||
|             { | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             foreach (string pattern in streamHandlers.Keys) | ||||
|             { | ||||
|                 if (path.StartsWith(pattern)) | ||||
|                 { | ||||
|                     if (pattern.Length > bestMatch.Length) | ||||
|                     { | ||||
|                         bestMatch = pattern; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // Handle using the best match available | ||||
| 
 | ||||
|             if (bestMatch.Length > 0) | ||||
|             { | ||||
|                 Rest.Log.DebugFormat("{0} Stream-based handler matched with <{1}>", MsgId, bestMatch); | ||||
|                 RestStreamHandler handler = streamHandlers[bestMatch]; | ||||
|                 rdata.buffer = handler.Handle(rdata.path, rdata.request.InputStream, rdata.request, rdata.response); | ||||
|                 rdata.AddHeader(rdata.response.ContentType,handler.ContentType); | ||||
|                 rdata.Respond("FindStreamHandler Completion"); | ||||
|             } | ||||
| 
 | ||||
|             return rdata.handled; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Add a stream handler for the designated HTTP method and path prefix. | ||||
|         /// If the handler is not enabled, the request is ignored. If the path | ||||
|         /// does not start with the REST prefix, it is added. If method-qualified | ||||
|         /// path has not already been registered, the method is added to the active | ||||
|         /// handler table. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         public void AddStreamHandler(string httpMethod, string path, RestMethod method) | ||||
|         { | ||||
|             if (!IsEnabled) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (!path.StartsWith(Rest.Prefix)) | ||||
|             { | ||||
|                 path = String.Format("{0}{1}", Rest.Prefix, path); | ||||
|             } | ||||
| 
 | ||||
|             path = String.Format("{0}{1}{2}", httpMethod, Rest.UrlMethodSeparator, path); | ||||
| 
 | ||||
|             // Conditionally add to the list | ||||
| 
 | ||||
|             if (!streamHandlers.ContainsKey(path)) | ||||
|             { | ||||
|                 streamHandlers.Add(path, new RestStreamHandler(httpMethod, path, method)); | ||||
|                 Rest.Log.DebugFormat("{0} Added handler for {1}", MsgId, path); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Rest.Log.WarnFormat("{0} Ignoring duplicate handler for {1}", MsgId, path); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Given the supplied request/response, if the handler is enabled, the inbound | ||||
|         /// information is used to match an entry in the active path handler tables, using | ||||
|         /// the method-qualified path information. If a match is found, then the handler is | ||||
|         /// invoked. The result is the boolean result of the handler, or false if no | ||||
|         /// handler was located. The boolean indicates whether or not the request has been | ||||
|         /// handled, not whether or not the request was successful - that information is in | ||||
|         /// the response. | ||||
|         /// Note: The selection process is case-insensitive | ||||
|         /// </summary> | ||||
| 
 | ||||
|         internal bool FindPathHandler(OSHttpRequest request, OSHttpResponse response) | ||||
|         { | ||||
|             RequestData rdata = null; | ||||
|             string bestMatch = null; | ||||
| 
 | ||||
|             if (!IsEnabled) | ||||
|             { | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             // Conditionally add to the list | ||||
| 
 | ||||
|             Rest.Log.DebugFormat("{0} Checking for path handler for <{1}>", MsgId, request.RawUrl); | ||||
| 
 | ||||
|             foreach (string pattern in pathHandlers.Keys) | ||||
|             { | ||||
|                 if (request.RawUrl.ToLower().StartsWith(pattern)) | ||||
|                 { | ||||
|                     if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) | ||||
|                     { | ||||
|                         bestMatch = pattern; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (!String.IsNullOrEmpty(bestMatch)) | ||||
|             { | ||||
|                 rdata = pathAllocators[bestMatch](request, response, bestMatch); | ||||
| 
 | ||||
|                 Rest.Log.DebugFormat("{0} Path based REST handler matched with <{1}>", MsgId, bestMatch); | ||||
| 
 | ||||
|                 try | ||||
|                 { | ||||
|                     pathHandlers[bestMatch](rdata); | ||||
|                 } | ||||
| 
 | ||||
|                 // A plugin generated error indicates a request-related error | ||||
|                 // that has been handled by the plugin. | ||||
| 
 | ||||
|                 catch (RestException r) | ||||
|                 { | ||||
|                     Rest.Log.WarnFormat("{0} Request failed: {1}", MsgId, r.Message); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return (rdata == null) ? false : rdata.handled; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// A method handler and a request allocator are stored using the designated | ||||
|         /// path as a key. If an entry already exists, it is replaced by the new one. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         public void AddPathHandler(RestMethodHandler mh, string path, RestMethodAllocator ra) | ||||
|         { | ||||
|             if (!IsEnabled) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (pathHandlers.ContainsKey(path)) | ||||
|             { | ||||
|                 Rest.Log.DebugFormat("{0} Replacing handler for <${1}>", MsgId, path); | ||||
|                 pathHandlers.Remove(path); | ||||
|             } | ||||
| 
 | ||||
|             if (pathAllocators.ContainsKey(path)) | ||||
|             { | ||||
|                 Rest.Log.DebugFormat("{0} Replacing allocator for <${1}>", MsgId, path); | ||||
|                 pathAllocators.Remove(path); | ||||
|             } | ||||
| 
 | ||||
|             Rest.Log.DebugFormat("{0} Adding path handler for {1}", MsgId, path); | ||||
| 
 | ||||
|             pathHandlers.Add(path, mh); | ||||
|             pathAllocators.Add(path, ra); | ||||
|         } | ||||
|     } | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -0,0 +1,246 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  *  | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Reflection; | ||||
| using OpenSim.Framework.Servers; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.Rest.Inventory | ||||
| { | ||||
|     public class RestTestServices : IRest | ||||
|     { | ||||
|         private bool    enabled = false; | ||||
|         private string  qPrefix = "test"; | ||||
| 
 | ||||
|         // A simple constructor is used to handle any once-only | ||||
|         // initialization of working classes. | ||||
| 
 | ||||
|         public RestTestServices() | ||||
|         { | ||||
|             Rest.Log.InfoFormat("{0} Test services initializing", MsgId); | ||||
|             Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); | ||||
| 
 | ||||
|             // If a relative path was specified, make it absolute by adding | ||||
|             // the standard prefix, e.g. /admin | ||||
| 
 | ||||
|             if (!qPrefix.StartsWith(Rest.UrlPathSeparator)) | ||||
|             { | ||||
|                 Rest.Log.InfoFormat("{0} Domain is relative, adding absolute prefix", MsgId); | ||||
|                 qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix); | ||||
|                 Rest.Log.InfoFormat("{0} Domain is now <{1}>", MsgId, qPrefix); | ||||
|             } | ||||
| 
 | ||||
|             // Load test cases | ||||
| 
 | ||||
|             loadTests(); | ||||
|             foreach (ITest test in tests) | ||||
|             { | ||||
|                 test.Initialize(); | ||||
|             } | ||||
| 
 | ||||
|             // Register interface | ||||
| 
 | ||||
|             Rest.Plugin.AddPathHandler(DoTests,qPrefix,Allocate); | ||||
| 
 | ||||
|             // Activate | ||||
| 
 | ||||
|             enabled = true; | ||||
| 
 | ||||
|             Rest.Log.InfoFormat("{0} Test services initialization complete", MsgId); | ||||
|         } | ||||
| 
 | ||||
|         // Post-construction, pre-enabled initialization opportunity | ||||
|         // Not currently exploited. | ||||
| 
 | ||||
|         public void Initialize() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         // Called by the plug-in to halt REST processing. Local processing is | ||||
|         // disabled, and control blocks until all current processing has  | ||||
|         // completed. No new processing will be started | ||||
| 
 | ||||
|         public void Close() | ||||
|         { | ||||
|             enabled = false; | ||||
|             foreach (ITest test in tests) | ||||
|             { | ||||
|                 test.Close(); | ||||
|             } | ||||
|             Rest.Log.InfoFormat("{0} Test services closing down", MsgId); | ||||
|         } | ||||
| 
 | ||||
|         // Properties | ||||
| 
 | ||||
|         internal string MsgId | ||||
|         { | ||||
|             get { return Rest.MsgId; } | ||||
|         } | ||||
| 
 | ||||
|         #region Interface | ||||
| 
 | ||||
|         private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix) | ||||
|         { | ||||
|             return new RequestData(request, response, prefix); | ||||
|         } | ||||
| 
 | ||||
|         // Inventory Handler | ||||
| 
 | ||||
|         private void DoTests(RequestData rdata) | ||||
|         { | ||||
|             if (!enabled) | ||||
|                 return; | ||||
| 
 | ||||
|             // Now that we know this is a serious attempt to  | ||||
|             // access inventory data, we should find out who | ||||
|             // is asking, and make sure they are authorized | ||||
|             // to do so. We need to validate the caller's | ||||
|             // identity before revealing anything about the | ||||
|             // status quo. Authenticate throws an exception | ||||
|             // via Fail if no identity information is present. | ||||
|             // | ||||
|             // With the present HTTP server we can't use the | ||||
|             // builtin authentication mechanisms because they | ||||
|             // would be enforced for all in-bound requests. | ||||
|             // Instead we look at the headers ourselves and  | ||||
|             // handle authentication directly. | ||||
|   | ||||
|             try | ||||
|             { | ||||
|                 if (!rdata.IsAuthenticated) | ||||
|                 { | ||||
|                     rdata.Fail(Rest.HttpStatusCodeNotAuthorized,  | ||||
|                           String.Format("user \"{0}\" could not be authenticated", rdata.userName)); | ||||
|                 } | ||||
|             } | ||||
|             catch (RestException e) | ||||
|             { | ||||
|                 if (e.statusCode == Rest.HttpStatusCodeNotAuthorized) | ||||
|                 { | ||||
|                     Rest.Log.WarnFormat("{0} User not authenticated", MsgId); | ||||
|                     Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization")); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     Rest.Log.ErrorFormat("{0} User authentication failed", MsgId); | ||||
|                     Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization")); | ||||
|                 } | ||||
|                 throw (e); | ||||
|             } | ||||
| 
 | ||||
|             // Check that a test was specified | ||||
| 
 | ||||
|             if (rdata.Parameters.Length < 1) | ||||
|             { | ||||
|                 Rest.Log.DebugFormat("{0} Insufficient parameters", MsgId); | ||||
|                 rdata.Fail(Rest.HttpStatusCodeBadRequest, "not enough parameters"); | ||||
|             } | ||||
| 
 | ||||
|             // Select the test | ||||
| 
 | ||||
|             foreach (ITest test in tests) | ||||
|             { | ||||
|                 if (!rdata.handled) | ||||
|                     test.Execute(rdata); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #endregion Interface | ||||
| 
 | ||||
|         private static bool    testsLoaded = false; | ||||
|         private static List<Type> classes  = new List<Type>(); | ||||
|         private static List<ITest>   tests = new List<ITest>(); | ||||
|         private static Type[]        parms = new Type[0]; | ||||
|         private static Object[]      args  = new Object[0]; | ||||
| 
 | ||||
|         static RestTestServices() | ||||
|         { | ||||
|             Module[] mods = Assembly.GetExecutingAssembly().GetModules(); | ||||
|             foreach (Module m in mods) | ||||
|             { | ||||
|                 Type[] types = m.GetTypes(); | ||||
|                 foreach (Type t in types)  | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         if (t.GetInterface("ITest") != null) | ||||
|                         { | ||||
|                             classes.Add(t); | ||||
|                         } | ||||
|                     } | ||||
|                     catch (Exception e) | ||||
|                     { | ||||
|                         Rest.Log.WarnFormat("[STATIC-TEST] Unable to include test {0} : {1}", t, e.Message); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// This routine loads all of the handlers discovered during | ||||
|         /// instance initialization. Each handler is responsible for | ||||
|         /// registering itself with this handler. | ||||
|         /// I was not able to make this code work in a constructor. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         private void loadTests() | ||||
|         { | ||||
|             lock (tests) | ||||
|             { | ||||
|                 if (!testsLoaded) | ||||
|                 { | ||||
| 
 | ||||
|                     ConstructorInfo ci; | ||||
|                     Object          ht; | ||||
| 
 | ||||
|                     foreach (Type t in classes) | ||||
|                     { | ||||
|                         try | ||||
|                         { | ||||
|                             if (t.GetInterface("ITest") != null) | ||||
|                             { | ||||
|                                 ci = t.GetConstructor(parms); | ||||
|                                 ht = ci.Invoke(args); | ||||
|                                 tests.Add((ITest)ht); | ||||
|                                 Rest.Log.InfoFormat("{0} Test {1} added", MsgId, t); | ||||
|                             } | ||||
|                         } | ||||
|                         catch (Exception e) | ||||
|                         { | ||||
|                             Rest.Log.WarnFormat("{0} Unable to load test {1} : {2}", MsgId, t, e.Message); | ||||
|                         } | ||||
|                     } | ||||
|                     testsLoaded = true; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,46 @@ | |||
| /* | ||||
| * Copyright (c) Contributors, http://opensimulator.org/ | ||||
| * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
| * | ||||
| * Redistribution and use in source and binary forms, with or without | ||||
| * modification, are permitted provided that the following conditions are met: | ||||
| *     * Redistributions of source code must retain the above copyright | ||||
| *       notice, this list of conditions and the following disclaimer. | ||||
| *     * Redistributions in binary form must reproduce the above copyright | ||||
| *       notice, this list of conditions and the following disclaimer in the | ||||
| *       documentation and/or other materials provided with the distribution. | ||||
| *     * Neither the name of the OpenSimulator Project nor the | ||||
| *       names of its contributors may be used to endorse or promote products | ||||
| *       derived from this software without specific prior written permission. | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
| * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| *  | ||||
| */ | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.Rest.Inventory | ||||
| { | ||||
| 
 | ||||
|     /// <summary> | ||||
|     /// This interface represents the boundary between the general purpose | ||||
|     /// REST plugin handling, and the functionally specific handlers. The | ||||
|     /// handler knows only to initialzie and terminate all such handlers  | ||||
|     /// that it finds. | ||||
|     /// </summary> | ||||
| 
 | ||||
|     internal interface ITest | ||||
|     { | ||||
|         void Initialize(); | ||||
|         void Execute(RequestData rdata); | ||||
|         void Close(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,204 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Region.Framework.Scenes; | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.Rest.Inventory.Tests | ||||
| { | ||||
|     public class Remote : ITest | ||||
|     { | ||||
|         private static readonly int PARM_TESTID      = 0; | ||||
|         private static readonly int PARM_COMMAND     = 1; | ||||
| 
 | ||||
|         private static readonly int PARM_MOVE_AVATAR = 2; | ||||
|         private static readonly int PARM_MOVE_X      = 3; | ||||
|         private static readonly int PARM_MOVE_Y      = 4; | ||||
|         private static readonly int PARM_MOVE_Z      = 5; | ||||
| 
 | ||||
|         private bool    enabled = false; | ||||
| 
 | ||||
|         // No constructor code is required. | ||||
| 
 | ||||
|         public Remote() | ||||
|         { | ||||
|             Rest.Log.InfoFormat("{0} Remote services constructor", MsgId); | ||||
|         } | ||||
| 
 | ||||
|         // Post-construction, pre-enabled initialization opportunity | ||||
|         // Not currently exploited. | ||||
| 
 | ||||
|         public void Initialize() | ||||
|         { | ||||
|             enabled = true; | ||||
|             Rest.Log.InfoFormat("{0} Remote services initialized", MsgId); | ||||
|         } | ||||
| 
 | ||||
|         // Called by the plug-in to halt REST processing. Local processing is | ||||
|         // disabled, and control blocks until all current processing has | ||||
|         // completed. No new processing will be started | ||||
| 
 | ||||
|         public void Close() | ||||
|         { | ||||
|             enabled = false; | ||||
|             Rest.Log.InfoFormat("{0} Remote services closing down", MsgId); | ||||
|         } | ||||
| 
 | ||||
|         // Properties | ||||
| 
 | ||||
|         internal string MsgId | ||||
|         { | ||||
|             get { return Rest.MsgId; } | ||||
|         } | ||||
| 
 | ||||
|         // Remote Handler | ||||
|         // Key information of interest here is the Parameters array, each | ||||
|         // entry represents an element of the URI, with element zero being | ||||
|         // the | ||||
| 
 | ||||
|         public void Execute(RequestData rdata) | ||||
|         { | ||||
|             if (!enabled) return; | ||||
| 
 | ||||
|             // If we can't relate to what's there, leave it for others. | ||||
| 
 | ||||
|             if (rdata.Parameters.Length == 0 || rdata.Parameters[PARM_TESTID] != "remote") | ||||
|                 return; | ||||
| 
 | ||||
|             Rest.Log.DebugFormat("{0} REST Remote handler ENTRY", MsgId); | ||||
| 
 | ||||
|             // Remove the prefix and what's left are the parameters. If we don't have | ||||
|             // the parameters we need, fail the request. Parameters do NOT include | ||||
|             // any supplied query values. | ||||
| 
 | ||||
|             if (rdata.Parameters.Length > 1) | ||||
|             { | ||||
|                 switch (rdata.Parameters[PARM_COMMAND].ToLower()) | ||||
|                 { | ||||
|                     case "move" : | ||||
|                         DoMove(rdata); | ||||
|                         break; | ||||
|                     default : | ||||
|                         DoHelp(rdata); | ||||
|                         break; | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 DoHelp(rdata); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private void DoHelp(RequestData rdata) | ||||
|         { | ||||
|             rdata.body = Help; | ||||
|             rdata.Complete(); | ||||
|             rdata.Respond("Help"); | ||||
|         } | ||||
| 
 | ||||
|         private void DoMove(RequestData rdata) | ||||
|         { | ||||
|             if (rdata.Parameters.Length < 6) | ||||
|             { | ||||
|                 Rest.Log.WarnFormat("{0} Move: No movement information provided", MsgId); | ||||
|                 rdata.Fail(Rest.HttpStatusCodeBadRequest, "no movement information provided"); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 string[] names = rdata.Parameters[PARM_MOVE_AVATAR].Split(Rest.CA_SPACE); | ||||
|                 ScenePresence presence = null; | ||||
|                 Scene scene = null; | ||||
| 
 | ||||
|                 if (names.Length != 2) | ||||
|                 { | ||||
|                     rdata.Fail(Rest.HttpStatusCodeBadRequest, | ||||
|                         String.Format("invalid avatar name: <{0}>",rdata.Parameters[PARM_MOVE_AVATAR])); | ||||
|                 } | ||||
| 
 | ||||
|                 Rest.Log.WarnFormat("{0} '{1}' command received for {2} {3}", | ||||
|                             MsgId, rdata.Parameters[0], names[0], names[1]); | ||||
| 
 | ||||
|                 // The first parameter should be an avatar name, look for the | ||||
|                 // avatar in the known regions first. | ||||
| 
 | ||||
|                 Rest.main.SceneManager.ForEachScene(delegate(Scene s) | ||||
|                 { | ||||
|                     s.ForEachRootScenePresence(delegate(ScenePresence sp) | ||||
|                     { | ||||
|                         if (sp.Firstname == names[0] && sp.Lastname == names[1]) | ||||
|                         { | ||||
|                             scene = s; | ||||
|                             presence = sp; | ||||
|                         } | ||||
|                     }); | ||||
|                 }); | ||||
| 
 | ||||
|                 if (presence != null) | ||||
|                 { | ||||
|                     Rest.Log.DebugFormat("{0} Move : Avatar {1} located in region {2}", | ||||
|                                 MsgId, rdata.Parameters[PARM_MOVE_AVATAR], scene.RegionInfo.RegionName); | ||||
| 
 | ||||
|                     try | ||||
|                     { | ||||
|                         float x = Convert.ToSingle(rdata.Parameters[PARM_MOVE_X]); | ||||
|                         float y = Convert.ToSingle(rdata.Parameters[PARM_MOVE_Y]); | ||||
|                         float z = Convert.ToSingle(rdata.Parameters[PARM_MOVE_Z]); | ||||
|                         Vector3 vector = new Vector3(x, y, z); | ||||
|                         presence.MoveToTarget(vector, false, false); | ||||
|                     } | ||||
|                     catch (Exception e) | ||||
|                     { | ||||
|                         rdata.Fail(Rest.HttpStatusCodeBadRequest, | ||||
|                                    String.Format("invalid parameters: {0}", e.Message)); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rdata.Fail(Rest.HttpStatusCodeBadRequest, | ||||
|                             String.Format("avatar {0} not present", rdata.Parameters[PARM_MOVE_AVATAR])); | ||||
|                 } | ||||
| 
 | ||||
|                 rdata.Complete(); | ||||
|                 rdata.Respond("OK"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static readonly string Help = | ||||
|                 "<html>" | ||||
|               + "<head><title>Remote Command Usage</title></head>" | ||||
|               + "<body>" | ||||
|               + "<p>Supported commands are:</p>" | ||||
|               + "<dl>" | ||||
|               + "<dt>move/avatar-name/x/y/z</dt>" | ||||
|               + "<dd>moves the specified avatar to another location</dd>" | ||||
|               + "</dl>" | ||||
|               + "</body>" | ||||
|               + "</html>" | ||||
|         ; | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,228 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.IO; | ||||
| using System.Xml.Serialization; | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Servers; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Region.Framework.Interfaces; | ||||
| using OpenSim.Region.Framework.Scenes; | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.Rest.Regions | ||||
| { | ||||
|     public partial class RestRegionPlugin : RestPlugin | ||||
|     { | ||||
|         #region GET methods | ||||
|         public string GetHandler(string request, string path, string param, | ||||
|                                  IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||||
|         { | ||||
|             // foreach (string h in httpRequest.Headers.AllKeys) | ||||
|             //     foreach (string v in httpRequest.Headers.GetValues(h)) | ||||
|             //         m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v); | ||||
| 
 | ||||
|             MsgID = RequestID; | ||||
|             m_log.DebugFormat("{0} GET path {1} param {2}", MsgID, path, param); | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 // param empty: regions list | ||||
|                 if (String.IsNullOrEmpty(param)) return GetHandlerRegions(httpResponse); | ||||
| 
 | ||||
|                 // param not empty: specific region | ||||
|                 return GetHandlerRegion(httpResponse, param); | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "GET", e); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public string GetHandlerRegions(IOSHttpResponse httpResponse) | ||||
|         { | ||||
|             RestXmlWriter rxw = new RestXmlWriter(new StringWriter()); | ||||
| 
 | ||||
|             rxw.WriteStartElement(String.Empty, "regions", String.Empty); | ||||
|             foreach (Scene s in App.SceneManager.Scenes) | ||||
|             { | ||||
|                 rxw.WriteStartElement(String.Empty, "uuid", String.Empty); | ||||
|                 rxw.WriteString(s.RegionInfo.RegionID.ToString()); | ||||
|                 rxw.WriteEndElement(); | ||||
|             } | ||||
|             rxw.WriteEndElement(); | ||||
| 
 | ||||
|             return rxw.ToString(); | ||||
|         } | ||||
| 
 | ||||
|         protected string ShortRegionInfo(string key, string value) | ||||
|         { | ||||
|             RestXmlWriter rxw = new RestXmlWriter(new StringWriter()); | ||||
| 
 | ||||
|             if (String.IsNullOrEmpty(value) || | ||||
|                 String.IsNullOrEmpty(key)) return null; | ||||
| 
 | ||||
|             rxw.WriteStartElement(String.Empty, "region", String.Empty); | ||||
|             rxw.WriteStartElement(String.Empty, key, String.Empty); | ||||
|             rxw.WriteString(value); | ||||
|             rxw.WriteEndDocument(); | ||||
| 
 | ||||
|             return rxw.ToString(); | ||||
|         } | ||||
| 
 | ||||
|         public string GetHandlerRegion(IOSHttpResponse httpResponse, string param) | ||||
|         { | ||||
|             // be resilient and don't get confused by a terminating '/' | ||||
|             param = param.TrimEnd(new char[]{'/'}); | ||||
|             string[] comps = param.Split('/'); | ||||
|             UUID regionID = (UUID)comps[0]; | ||||
| 
 | ||||
|             m_log.DebugFormat("{0} GET region UUID {1}", MsgID, regionID.ToString()); | ||||
| 
 | ||||
|             if (UUID.Zero == regionID) throw new Exception("missing region ID"); | ||||
| 
 | ||||
|             Scene scene = null; | ||||
|             App.SceneManager.TryGetScene(regionID, out scene); | ||||
|             if (null == scene) return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound, | ||||
|                                               "GET", "cannot find region {0}", regionID.ToString()); | ||||
| 
 | ||||
|             RegionDetails details = new RegionDetails(scene.RegionInfo); | ||||
| 
 | ||||
|             // m_log.DebugFormat("{0} GET comps {1}", MsgID, comps.Length); | ||||
|             // for (int i = 0; i < comps.Length; i++)  m_log.DebugFormat("{0} GET comps[{1}] >{2}<", MsgID, i, comps[i]); | ||||
| 
 | ||||
|             if (1 == comps.Length) | ||||
|             { | ||||
|                 // complete region details requested | ||||
|                 RestXmlWriter rxw = new RestXmlWriter(new StringWriter()); | ||||
|                 XmlSerializer xs = new XmlSerializer(typeof(RegionDetails)); | ||||
|                 xs.Serialize(rxw, details, _xmlNs); | ||||
|                 return rxw.ToString(); | ||||
|             } | ||||
| 
 | ||||
|             if (2 == comps.Length) | ||||
|             { | ||||
|                 string resp = ShortRegionInfo(comps[1], details[comps[1]]); | ||||
|                 if (null != resp) return resp; | ||||
| 
 | ||||
|                 // m_log.DebugFormat("{0} GET comps advanced: >{1}<", MsgID, comps[1]); | ||||
| 
 | ||||
|                 // check for {terrain,stats,prims} | ||||
|                 switch (comps[1].ToLower()) | ||||
|                 { | ||||
|                 case "terrain": | ||||
|                     return RegionTerrain(httpResponse, scene); | ||||
| 
 | ||||
|                 case "stats": | ||||
|                     return RegionStats(httpResponse, scene); | ||||
| 
 | ||||
|                 case "prims": | ||||
|                     return RegionPrims(httpResponse, scene, Vector3.Zero, Vector3.Zero); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (3 == comps.Length) | ||||
|             { | ||||
|                 switch (comps[1].ToLower()) | ||||
|                 { | ||||
|                 case "prims": | ||||
|                     string[] subregion = comps[2].Split(','); | ||||
|                     if (subregion.Length == 6) | ||||
|                     { | ||||
|                         Vector3 min, max; | ||||
|                         try | ||||
|                         { | ||||
|                             min = new Vector3((float)Double.Parse(subregion[0], Culture.NumberFormatInfo), (float)Double.Parse(subregion[1], Culture.NumberFormatInfo), (float)Double.Parse(subregion[2], Culture.NumberFormatInfo)); | ||||
|                             max = new Vector3((float)Double.Parse(subregion[3], Culture.NumberFormatInfo), (float)Double.Parse(subregion[4], Culture.NumberFormatInfo), (float)Double.Parse(subregion[5], Culture.NumberFormatInfo)); | ||||
|                         } | ||||
|                         catch (Exception) | ||||
|                         { | ||||
|                             return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest, | ||||
|                                            "GET", "invalid subregion parameter"); | ||||
|                         } | ||||
|                         return RegionPrims(httpResponse, scene, min, max); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest, | ||||
|                                        "GET", "invalid subregion parameter"); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest, | ||||
|                            "GET", "too many parameters {0}", param); | ||||
|         } | ||||
|         #endregion GET methods | ||||
| 
 | ||||
|         protected string RegionTerrain(IOSHttpResponse httpResponse, Scene scene) | ||||
|         { | ||||
|             httpResponse.SendChunked = true; | ||||
|             httpResponse.ContentType = "text/xml"; | ||||
| 
 | ||||
|             return scene.Heightmap.SaveToXmlString(); | ||||
|             //return Failure(httpResponse, OSHttpStatusCode.ServerErrorNotImplemented, | ||||
|             //               "GET", "terrain not implemented"); | ||||
|         } | ||||
| 
 | ||||
|         protected string RegionStats(IOSHttpResponse httpResponse, Scene scene) | ||||
|         { | ||||
|             int users = scene.GetRootAgentCount(); | ||||
|             int objects = scene.Entities.Count - users; | ||||
| 
 | ||||
|             RestXmlWriter rxw = new RestXmlWriter(new StringWriter()); | ||||
| 
 | ||||
|             rxw.WriteStartElement(String.Empty, "region", String.Empty); | ||||
|             rxw.WriteStartElement(String.Empty, "stats", String.Empty); | ||||
| 
 | ||||
|             rxw.WriteStartElement(String.Empty, "users", String.Empty); | ||||
|             rxw.WriteString(users.ToString()); | ||||
|             rxw.WriteEndElement(); | ||||
| 
 | ||||
|             rxw.WriteStartElement(String.Empty, "objects", String.Empty); | ||||
|             rxw.WriteString(objects.ToString()); | ||||
|             rxw.WriteEndElement(); | ||||
| 
 | ||||
|             rxw.WriteEndDocument(); | ||||
| 
 | ||||
|             return rxw.ToString(); | ||||
|         } | ||||
| 
 | ||||
|         protected string RegionPrims(IOSHttpResponse httpResponse, Scene scene, Vector3 min, Vector3 max) | ||||
|         { | ||||
|             httpResponse.SendChunked = true; | ||||
|             httpResponse.ContentType = "text/xml"; | ||||
|              | ||||
|             IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>(); | ||||
|             if (serialiser != null) | ||||
|                 serialiser.SavePrimsToXml2(scene, new StreamWriter(httpResponse.OutputStream), min, max); | ||||
|              | ||||
|             return ""; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,136 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.IO; | ||||
| using System.Xml.Serialization; | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Framework.Servers; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Region.Framework.Interfaces; | ||||
| using OpenSim.Region.Framework.Scenes; | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.Rest.Regions | ||||
| { | ||||
|     public partial class RestRegionPlugin : RestPlugin | ||||
|     { | ||||
|         #region GET methods | ||||
|         public string GetRegionInfoHandler(string request, string path, string param, | ||||
|                                            IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||||
|         { | ||||
|             // foreach (string h in httpRequest.Headers.AllKeys) | ||||
|             //     foreach (string v in httpRequest.Headers.GetValues(h)) | ||||
|             //         m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v); | ||||
| 
 | ||||
|             MsgID = RequestID; | ||||
|             m_log.DebugFormat("{0} GET path {1} param {2}", MsgID, path, param); | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 // param empty: regions list | ||||
|                 // if (String.IsNullOrEmpty(param))  | ||||
|                 return GetRegionInfoHandlerRegions(httpResponse); | ||||
|                      | ||||
|                 // // param not empty: specific region | ||||
|                 // return GetRegionInfoHandlerRegion(httpResponse, param); | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "GET", e); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public string GetRegionInfoHandlerRegions(IOSHttpResponse httpResponse) | ||||
|         { | ||||
|             RestXmlWriter rxw = new RestXmlWriter(new StringWriter()); | ||||
| 
 | ||||
|             // regions info | ||||
|             rxw.WriteStartElement(String.Empty, "regions", String.Empty); | ||||
|             { | ||||
|                 // regions info: number of regions | ||||
|                 rxw.WriteStartAttribute(String.Empty, "number", String.Empty); | ||||
|                 rxw.WriteValue(App.SceneManager.Scenes.Count); | ||||
|                 rxw.WriteEndAttribute(); | ||||
| 
 | ||||
|                 // regions info: max number of regions | ||||
|                 rxw.WriteStartAttribute(String.Empty, "max", String.Empty); | ||||
|                 if (App.ConfigSource.Source.Configs["RemoteAdmin"] != null) | ||||
|                 { | ||||
|                     rxw.WriteValue(App.ConfigSource.Source.Configs["RemoteAdmin"].GetInt("region_limit", -1)); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rxw.WriteValue(-1); | ||||
|                 } | ||||
|                 rxw.WriteEndAttribute(); | ||||
|                  | ||||
|                 // regions info: region | ||||
|                 foreach (Scene s in App.SceneManager.Scenes) | ||||
|                 { | ||||
|                     rxw.WriteStartElement(String.Empty, "region", String.Empty); | ||||
|                      | ||||
|                     rxw.WriteStartAttribute(String.Empty, "uuid", String.Empty); | ||||
|                     rxw.WriteString(s.RegionInfo.RegionID.ToString()); | ||||
|                     rxw.WriteEndAttribute(); | ||||
|                      | ||||
|                     rxw.WriteStartAttribute(String.Empty, "name", String.Empty); | ||||
|                     rxw.WriteString(s.RegionInfo.RegionName); | ||||
|                     rxw.WriteEndAttribute(); | ||||
|                      | ||||
|                     rxw.WriteStartAttribute(String.Empty, "x", String.Empty); | ||||
|                     rxw.WriteValue(s.RegionInfo.RegionLocX); | ||||
|                     rxw.WriteEndAttribute(); | ||||
|                      | ||||
|                     rxw.WriteStartAttribute(String.Empty, "y", String.Empty); | ||||
|                     rxw.WriteValue(s.RegionInfo.RegionLocY); | ||||
|                     rxw.WriteEndAttribute(); | ||||
|                      | ||||
|                     rxw.WriteStartAttribute(String.Empty, "external_hostname", String.Empty); | ||||
|                     rxw.WriteString(s.RegionInfo.ExternalHostName); | ||||
|                     rxw.WriteEndAttribute(); | ||||
|                      | ||||
|                     rxw.WriteStartAttribute(String.Empty, "ip", String.Empty); | ||||
|                     rxw.WriteString(s.RegionInfo.InternalEndPoint.ToString()); | ||||
|                     rxw.WriteEndAttribute(); | ||||
|                      | ||||
|                     int users = s.GetRootAgentCount(); | ||||
|                     rxw.WriteStartAttribute(String.Empty, "avatars", String.Empty); | ||||
|                     rxw.WriteValue(users); | ||||
|                     rxw.WriteEndAttribute(); | ||||
|                      | ||||
|                     rxw.WriteStartAttribute(String.Empty, "objects", String.Empty); | ||||
|                     rxw.WriteValue(s.Entities.Count - users); | ||||
|                     rxw.WriteEndAttribute(); | ||||
|                      | ||||
|                     rxw.WriteEndElement(); | ||||
|                 } | ||||
|             } | ||||
|             return rxw.ToString(); | ||||
|         } | ||||
|         #endregion GET methods | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,122 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.IO; | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Framework.Servers; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Region.Framework.Interfaces; | ||||
| using OpenSim.Region.Framework.Scenes; | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.Rest.Regions | ||||
| { | ||||
|     public partial class RestRegionPlugin : RestPlugin | ||||
|     { | ||||
|         #region POST methods | ||||
| 
 | ||||
|         public string PostHandler(string request, string path, string param, | ||||
|                                   IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||||
|         { | ||||
|             // foreach (string h in httpRequest.Headers.AllKeys) | ||||
|             //     foreach (string v in httpRequest.Headers.GetValues(h)) | ||||
|             //         m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v); | ||||
| 
 | ||||
|             MsgID = RequestID; | ||||
|             m_log.DebugFormat("{0} POST path {1} param {2}", MsgID, path, param); | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 // param empty: new region post | ||||
|                 if (!IsGod(httpRequest)) | ||||
|                     // XXX: this needs to be turned into a FailureUnauthorized(...) | ||||
|                     return Failure(httpResponse, OSHttpStatusCode.ClientErrorUnauthorized, | ||||
|                                    "GET", "you are not god"); | ||||
| 
 | ||||
|                 if (String.IsNullOrEmpty(param)) return CreateRegion(httpRequest, httpResponse); | ||||
| 
 | ||||
|                 // Parse region ID and other parameters | ||||
|                 param = param.TrimEnd(new char[] {'/'}); | ||||
|                 string[] comps = param.Split('/'); | ||||
|                 UUID regionID = (UUID) comps[0]; | ||||
| 
 | ||||
|                 m_log.DebugFormat("{0} POST region UUID {1}", MsgID, regionID.ToString()); | ||||
|                 if (UUID.Zero == regionID) throw new Exception("missing region ID"); | ||||
| 
 | ||||
|                 Scene scene = null; | ||||
|                 App.SceneManager.TryGetScene(regionID, out scene); | ||||
|                 if (null == scene) | ||||
|                     return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound, | ||||
|                                    "POST", "cannot find region {0}", regionID.ToString()); | ||||
| 
 | ||||
|                 if (2 == comps.Length) | ||||
|                 { | ||||
|                     // check for {prims} | ||||
|                     switch (comps[1].ToLower()) | ||||
|                     { | ||||
|                         case "prims": | ||||
|                             return LoadPrims(request, httpRequest, httpResponse, scene); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound, | ||||
|                                "POST", "url {0} not supported", param); | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "POST", e); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public string CreateRegion(IOSHttpRequest request, IOSHttpResponse response) | ||||
|         { | ||||
|             RestXmlWriter rxw = new RestXmlWriter(new StringWriter()); | ||||
| 
 | ||||
|             rxw.WriteStartElement(String.Empty, "regions", String.Empty); | ||||
|             foreach (Scene s in App.SceneManager.Scenes) | ||||
|             { | ||||
|                 rxw.WriteStartElement(String.Empty, "uuid", String.Empty); | ||||
|                 rxw.WriteString(s.RegionInfo.RegionID.ToString()); | ||||
|                 rxw.WriteEndElement(); | ||||
|             } | ||||
|             rxw.WriteEndElement(); | ||||
| 
 | ||||
|             return rxw.ToString(); | ||||
|         } | ||||
| 
 | ||||
|         public string LoadPrims(string requestBody, IOSHttpRequest request, IOSHttpResponse response, Scene scene) | ||||
|         { | ||||
|             IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>(); | ||||
|             if (serialiser != null) | ||||
|                 serialiser.LoadPrimsFromXml2(scene, new StringReader(requestBody), true); | ||||
| 
 | ||||
|             return ""; | ||||
|         } | ||||
| 
 | ||||
|         #endregion POST methods | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,98 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Xml.Serialization; | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Framework; | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.Rest.Regions | ||||
| { | ||||
|     [XmlRoot(ElementName="region", IsNullable = false)] | ||||
|     public class RegionDetails | ||||
|     { | ||||
|         public string region_name; | ||||
|         public string region_id; | ||||
|         public uint region_x; | ||||
|         public uint region_y; | ||||
|         public string region_owner; | ||||
|         public string region_owner_id; | ||||
|         public uint region_http_port; | ||||
|         public uint region_port; | ||||
|         public string region_server_uri; | ||||
|         public string region_external_hostname; | ||||
| 
 | ||||
|         public RegionDetails() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         public RegionDetails(RegionInfo regInfo) | ||||
|         { | ||||
|             region_name = regInfo.RegionName; | ||||
|             region_id = regInfo.RegionID.ToString(); | ||||
|             region_x = regInfo.RegionLocX; | ||||
|             region_y = regInfo.RegionLocY; | ||||
|             region_owner_id = regInfo.EstateSettings.EstateOwner.ToString(); | ||||
|             region_http_port = regInfo.HttpPort; | ||||
|             region_server_uri = regInfo.ServerURI; | ||||
|             region_external_hostname = regInfo.ExternalHostName; | ||||
| 
 | ||||
|             Uri uri = new Uri(region_server_uri); | ||||
|             region_port = (uint)uri.Port; | ||||
|         } | ||||
| 
 | ||||
|         public string this[string idx] | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 switch (idx.ToLower()) | ||||
|                 { | ||||
|                 case "name": | ||||
|                     return region_name; | ||||
|                 case "id": | ||||
|                     return region_id; | ||||
|                 case "location": | ||||
|                     return String.Format("<x>{0}</x><y>{1}</y>", region_x, region_y); | ||||
|                 case "owner": | ||||
|                     return region_owner; | ||||
|                 case "owner_id": | ||||
|                     return region_owner_id; | ||||
|                 case "http_port": | ||||
|                     return region_http_port.ToString(); | ||||
|                 case "server_uri": | ||||
|                     return region_server_uri; | ||||
|                 case "external_hostname": | ||||
|                 case "hostname": | ||||
|                     return region_external_hostname; | ||||
| 
 | ||||
|                 default: | ||||
|                     return null; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,11 @@ | |||
| <Addin id="OpenSim.ApplicationPlugins.Rest.Regions" version="0.1"> | ||||
|     <Runtime> | ||||
|         <Import assembly="OpenSim.ApplicationPlugins.Rest.Regions.dll"/> | ||||
|     </Runtime> | ||||
|     <Dependencies> | ||||
|         <Addin id="OpenSim" version="0.5" /> | ||||
|     </Dependencies> | ||||
|     <Extension path = "/OpenSim/Startup"> | ||||
|         <Plugin id="RestRegions" type="OpenSim.ApplicationPlugins.Rest.Regions.RestRegionPlugin" /> | ||||
|     </Extension> | ||||
| </Addin> | ||||
|  | @ -0,0 +1,94 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Xml.Serialization; | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.Rest.Regions | ||||
| { | ||||
|     public partial class RestRegionPlugin : RestPlugin | ||||
|     { | ||||
|         private static XmlSerializerNamespaces _xmlNs; | ||||
| 
 | ||||
|         static RestRegionPlugin() | ||||
|         { | ||||
|             _xmlNs = new XmlSerializerNamespaces(); | ||||
|             _xmlNs.Add(String.Empty, String.Empty); | ||||
|         } | ||||
| 
 | ||||
|         #region overriding properties | ||||
|         public override string Name | ||||
|         { | ||||
|             get { return "REGION"; } | ||||
|         } | ||||
| 
 | ||||
|         public override string ConfigName | ||||
|         { | ||||
|             get { return "RestRegionPlugin"; } | ||||
|         } | ||||
|         #endregion overriding properties | ||||
| 
 | ||||
|         #region overriding methods | ||||
|         /// <summary> | ||||
|         /// This method is called by OpenSimMain immediately after loading the | ||||
|         /// plugin and after basic server setup,  but before running any server commands. | ||||
|         /// </summary> | ||||
|         /// <remarks> | ||||
|         /// Note that entries MUST be added to the active configuration files before | ||||
|         /// the plugin can be enabled. | ||||
|         /// </remarks> | ||||
|         public override void Initialise(OpenSimBase openSim) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 base.Initialise(openSim); | ||||
|                 if (!IsEnabled) | ||||
|                 { | ||||
|                     //m_log.WarnFormat("{0} Rest Plugins are disabled", MsgID); | ||||
|                     return; | ||||
|                 } | ||||
|                  | ||||
|                 m_log.InfoFormat("{0} REST region plugin enabled", MsgID); | ||||
| 
 | ||||
|                 // add REST method handlers | ||||
|                 AddRestStreamHandler("GET", "/regions/", GetHandler); | ||||
|                 AddRestStreamHandler("POST", "/regions/", PostHandler); | ||||
|                 AddRestStreamHandler("GET", "/regioninfo/", GetRegionInfoHandler); | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 m_log.WarnFormat("{0} Initialization failed: {1}", MsgID, e.Message); | ||||
|                 m_log.DebugFormat("{0} Initialization failed: {1}", MsgID, e.ToString()); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public override void Close() | ||||
|         { | ||||
|         } | ||||
|         #endregion overriding methods | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,415 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Reflection; | ||||
| using System.Xml; | ||||
| using log4net; | ||||
| using Nini.Config; | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Servers; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.Rest | ||||
| { | ||||
|     public abstract class RestPlugin : IApplicationPlugin | ||||
|     { | ||||
|         #region properties | ||||
| 
 | ||||
|         protected static readonly ILog m_log = | ||||
|             LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private IConfig _config; // Configuration source: Rest Plugins | ||||
|         private IConfig _pluginConfig; // Configuration source: Plugin specific | ||||
|         private OpenSimBase _app; // The 'server' | ||||
|         private BaseHttpServer _httpd; // The server's RPC interface | ||||
|         private string _prefix; // URL prefix below | ||||
|         // which all REST URLs | ||||
|         // are living | ||||
|         // private StringWriter _sw = null; | ||||
|         // private RestXmlWriter _xw = null; | ||||
| 
 | ||||
|         private string _godkey; | ||||
|         private int _reqk; | ||||
| 
 | ||||
|         [ThreadStatic] | ||||
|         private static string  _threadRequestID = String.Empty; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Return an ever increasing request ID for logging | ||||
|         /// </summary> | ||||
|         protected string RequestID | ||||
|         { | ||||
|             get { return _reqk++.ToString(); } | ||||
|             set { _reqk = Convert.ToInt32(value); } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Thread-constant message IDs for logging. | ||||
|         /// </summary> | ||||
|         protected string MsgID | ||||
|         { | ||||
|             get { return String.Format("[REST-{0}] #{1}", Name, _threadRequestID); } | ||||
|             set { _threadRequestID = value; } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Returns true if Rest Plugins are enabled. | ||||
|         /// </summary> | ||||
|         public bool PluginsAreEnabled | ||||
|         { | ||||
|             get { return null != _config; } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Returns true if specific Rest Plugin is enabled. | ||||
|         /// </summary> | ||||
|         public bool IsEnabled | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 return (null != _pluginConfig) && _pluginConfig.GetBoolean("enabled", false); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// OpenSimMain application | ||||
|         /// </summary> | ||||
|         public OpenSimBase App | ||||
|         { | ||||
|             get { return _app; } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// RPC server | ||||
|         /// </summary> | ||||
|         public BaseHttpServer HttpServer | ||||
|         { | ||||
|             get { return _httpd; } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// URL prefix to use for all REST handlers | ||||
|         /// </summary> | ||||
|         public string Prefix | ||||
|         { | ||||
|             get { return _prefix; } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Access to GOD password string | ||||
|         /// </summary> | ||||
|         protected string GodKey | ||||
|         { | ||||
|             get { return _godkey; } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Configuration of the plugin | ||||
|         /// </summary> | ||||
|         public IConfig Config | ||||
|         { | ||||
|             get { return _pluginConfig; } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Name of the plugin | ||||
|         /// </summary> | ||||
|         public abstract string Name { get; } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Return the config section name | ||||
|         /// </summary> | ||||
|         public abstract string ConfigName { get; } | ||||
| 
 | ||||
|         // public XmlTextWriter XmlWriter | ||||
|         // { | ||||
|         //     get | ||||
|         //     { | ||||
|         //         if (null == _xw) | ||||
|         //         { | ||||
|         //             _sw = new StringWriter(); | ||||
|         //             _xw = new RestXmlWriter(_sw); | ||||
|         //             _xw.Formatting = Formatting.Indented; | ||||
|         //         } | ||||
|         //         return _xw; | ||||
|         //     } | ||||
|         // } | ||||
| 
 | ||||
|         // public string XmlWriterResult | ||||
|         // { | ||||
|         //     get | ||||
|         //     { | ||||
|         //         _xw.Flush(); | ||||
|         //         _xw.Close(); | ||||
|         //         _xw = null; | ||||
| 
 | ||||
|         //         return _sw.ToString(); | ||||
|         //     } | ||||
|         // } | ||||
| 
 | ||||
|         #endregion properties | ||||
| 
 | ||||
|         #region methods | ||||
| 
 | ||||
|         // TODO: required by IPlugin, but likely not at all right | ||||
|         private string m_version = "0.0"; | ||||
| 
 | ||||
|         public string Version | ||||
|         { | ||||
|             get { return m_version; } | ||||
|         } | ||||
| 
 | ||||
|         public void Initialise() | ||||
|         { | ||||
|             m_log.Info("[RESTPLUGIN]: " + Name + " cannot be default-initialized!"); | ||||
|             throw new PluginNotInitialisedException(Name); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// This method is called by OpenSimMain immediately after loading the | ||||
|         /// plugin and after basic server setup,  but before running any server commands. | ||||
|         /// </summary> | ||||
|         /// <remarks> | ||||
|         /// Note that entries MUST be added to the active configuration files before | ||||
|         /// the plugin can be enabled. | ||||
|         /// </remarks> | ||||
|         public virtual void Initialise(OpenSimBase openSim) | ||||
|         { | ||||
|             RequestID = "0"; | ||||
|             MsgID = RequestID; | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 if ((_config = openSim.ConfigSource.Source.Configs["RestPlugins"]) == null) | ||||
|                 { | ||||
|                     m_log.WarnFormat("{0} Rest Plugins not configured", MsgID); | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 if (!_config.GetBoolean("enabled", false)) | ||||
|                 { | ||||
|                     //m_log.WarnFormat("{0} Rest Plugins are disabled", MsgID); | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 _app = openSim; | ||||
|                 _httpd = openSim.HttpServer; | ||||
| 
 | ||||
|                 // Retrieve GOD key value, if any. | ||||
|                 _godkey = _config.GetString("god_key", String.Empty); | ||||
| 
 | ||||
|                 // Retrive prefix if any. | ||||
|                 _prefix = _config.GetString("prefix", "/admin"); | ||||
| 
 | ||||
|                 // Get plugin specific config | ||||
|                 _pluginConfig = openSim.ConfigSource.Source.Configs[ConfigName]; | ||||
| 
 | ||||
|                 m_log.InfoFormat("{0} Rest Plugins Enabled", MsgID); | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 // we can safely ignore this, as it just means that | ||||
|                 // the key lookup in Configs failed, which signals to | ||||
|                 // us that noone is interested in our services...they | ||||
|                 // don't know what they are missing out on... | ||||
|                 // NOTE: Under the present OpenSimulator implementation it is | ||||
|                 // not possible for the openSimulator pointer to be null. However | ||||
|                 // were the implementation to be changed, this could | ||||
|                 // result in a silent initialization failure. Harmless | ||||
|                 // except for lack of function and lack of any | ||||
|                 // diagnostic indication as to why. The same is true if | ||||
|                 // the HTTP server reference is bad. | ||||
|                 // We should at least issue a message... | ||||
|                 m_log.WarnFormat("{0} Initialization failed: {1}", MsgID, e.Message); | ||||
|                 m_log.DebugFormat("{0} Initialization failed: {1}", MsgID, e.ToString()); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public virtual void PostInitialise() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         private List<RestStreamHandler> _handlers = new List<RestStreamHandler>(); | ||||
|         private Dictionary<string, IHttpAgentHandler> _agents = new Dictionary<string, IHttpAgentHandler>(); | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Add a REST stream handler to the underlying HTTP server. | ||||
|         /// </summary> | ||||
|         /// <param name="httpMethod">GET/PUT/POST/DELETE or | ||||
|         /// similar</param> | ||||
|         /// <param name="path">URL prefix</param> | ||||
|         /// <param name="method">RestMethod handler doing the actual work</param> | ||||
|         public virtual void AddRestStreamHandler(string httpMethod, string path, RestMethod method) | ||||
|         { | ||||
|             if (!IsEnabled) return; | ||||
| 
 | ||||
|             if (!path.StartsWith(_prefix)) | ||||
|             { | ||||
|                 path = String.Format("{0}{1}", _prefix, path); | ||||
|             } | ||||
| 
 | ||||
|             RestStreamHandler h = new RestStreamHandler(httpMethod, path, method); | ||||
|             _httpd.AddStreamHandler(h); | ||||
|             _handlers.Add(h); | ||||
| 
 | ||||
|             m_log.DebugFormat("{0} Added REST handler {1} {2}", MsgID, httpMethod, path); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Add a powerful Agent handler to the underlying HTTP | ||||
|         /// server. | ||||
|         /// </summary> | ||||
|         /// <param name="agentName">name of agent handler</param> | ||||
|         /// <param name="handler">agent handler method</param> | ||||
|         /// <returns>false when the plugin is disabled or the agent | ||||
|         /// handler could not be added. Any generated exceptions are | ||||
|         /// allowed to drop through to the caller, i.e. ArgumentException. | ||||
|         /// </returns> | ||||
|         public bool AddAgentHandler(string agentName, IHttpAgentHandler handler) | ||||
|         { | ||||
|             if (!IsEnabled) return false; | ||||
|             _agents.Add(agentName, handler); | ||||
|             return _httpd.AddAgentHandler(agentName, handler); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Remove a powerful Agent handler from the underlying HTTP | ||||
|         /// server. | ||||
|         /// </summary> | ||||
|         /// <param name="agentName">name of agent handler</param> | ||||
|         /// <param name="handler">agent handler method</param> | ||||
|         /// <returns>false when the plugin is disabled or the agent | ||||
|         /// handler could not be removed. Any generated exceptions are | ||||
|         /// allowed to drop through to the caller, i.e. KeyNotFound. | ||||
|         /// </returns> | ||||
|         public bool RemoveAgentHandler(string agentName, IHttpAgentHandler handler) | ||||
|         { | ||||
|             if (!IsEnabled) return false; | ||||
|             if (_agents[agentName] == handler) | ||||
|             { | ||||
|                 _agents.Remove(agentName); | ||||
|                 return _httpd.RemoveAgentHandler(agentName, handler); | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Check whether the HTTP request came from god; that is, is | ||||
|         /// the god_key as configured in the config section supplied | ||||
|         /// via X-OpenSim-Godkey? | ||||
|         /// </summary> | ||||
|         /// <param name="request">HTTP request header</param> | ||||
|         /// <returns>true when the HTTP request came from god.</returns> | ||||
|         protected bool IsGod(IOSHttpRequest request) | ||||
|         { | ||||
|             string[] keys = request.Headers.GetValues("X-OpenSim-Godkey"); | ||||
|             if (null == keys) return false; | ||||
| 
 | ||||
|             // we take the last key supplied | ||||
|             return keys[keys.Length - 1] == _godkey; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Checks wether the X-OpenSim-Password value provided in the | ||||
|         /// HTTP header is indeed the password on file for the avatar | ||||
|         /// specified by the UUID | ||||
|         /// </summary> | ||||
|         protected bool IsVerifiedUser(IOSHttpRequest request, UUID uuid) | ||||
|         { | ||||
|             // XXX under construction | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Clean up and remove all handlers that were added earlier. | ||||
|         /// </summary> | ||||
|         public virtual void Close() | ||||
|         { | ||||
|             foreach (RestStreamHandler h in _handlers) | ||||
|             { | ||||
|                 _httpd.RemoveStreamHandler(h.HttpMethod, h.Path); | ||||
|             } | ||||
|             _handlers = null; | ||||
|             foreach (KeyValuePair<string, IHttpAgentHandler> h in _agents) | ||||
|             { | ||||
|                 _httpd.RemoveAgentHandler(h.Key, h.Value); | ||||
|             } | ||||
|             _agents = null; | ||||
|         } | ||||
| 
 | ||||
|         public virtual void Dispose() | ||||
|         { | ||||
|             Close(); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Return a failure message. | ||||
|         /// </summary> | ||||
|         /// <param name="method">origin of the failure message</param> | ||||
|         /// <param name="message">failure message</param> | ||||
|         /// <remarks>This should probably set a return code as | ||||
|         /// well. (?)</remarks> | ||||
|         protected string Failure(IOSHttpResponse response, OSHttpStatusCode status, | ||||
|                                  string method, string format, params string[] msg) | ||||
|         { | ||||
|             string m = String.Format(format, msg); | ||||
| 
 | ||||
|             response.StatusCode = (int) status; | ||||
|             response.StatusDescription = m; | ||||
| 
 | ||||
|             m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, m); | ||||
|             return String.Format("<error>{0}</error>", m); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Return a failure message. | ||||
|         /// </summary> | ||||
|         /// <param name="method">origin of the failure message</param> | ||||
|         /// <param name="e">exception causing the failure message</param> | ||||
|         /// <remarks>This should probably set a return code as | ||||
|         /// well. (?)</remarks> | ||||
|         public string Failure(IOSHttpResponse response, OSHttpStatusCode status, | ||||
|                               string method, Exception e) | ||||
|         { | ||||
|             string m = String.Format("exception occurred: {0}", e.Message); | ||||
| 
 | ||||
|             response.StatusCode = (int) status; | ||||
|             response.StatusDescription = m; | ||||
| 
 | ||||
|             m_log.DebugFormat("{0} {1} failed: {2}", MsgID, method, e.ToString()); | ||||
|             m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, e.Message); | ||||
| 
 | ||||
|             return String.Format("<error>{0}</error>", e.Message); | ||||
|         } | ||||
| 
 | ||||
|         #endregion methods | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,72 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System.IO; | ||||
| using System.Text; | ||||
| using System.Xml; | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.Rest | ||||
| { | ||||
|     public class RestXmlWriter: XmlTextWriter | ||||
|     { | ||||
|         private StringWriter m_sw = null; | ||||
| 
 | ||||
|         public RestXmlWriter(StringWriter sw) : base(sw) | ||||
|         { | ||||
|             m_sw = sw; | ||||
|             Formatting = Formatting.Indented; | ||||
|         } | ||||
| 
 | ||||
|         public RestXmlWriter(TextWriter textWriter) : base(textWriter) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         public RestXmlWriter(Stream stream) | ||||
|             : this(stream, Encoding.UTF8) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         public RestXmlWriter(Stream stream, Encoding enc) : base(stream, enc) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         public override void WriteStartDocument() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         public override void WriteStartDocument(bool standalone) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         public override string ToString() | ||||
|         { | ||||
|             Flush(); | ||||
|             Close(); | ||||
|             return m_sw.ToString(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,276 @@ | |||
| <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | ||||
| 
 | ||||
| 	<xsd:annotation> | ||||
| 		<xsd:documentation xml:lang="en"> | ||||
| 		Open Simulator Export/Import XML schema | ||||
| 		August 2008 | ||||
| 		</xsd:documentation> | ||||
| 	</xsd:annotation> | ||||
| 
 | ||||
|     <!-- WARNING!!! | ||||
| 		 This is currently a draft, it does not reflect | ||||
| 		 what is exported, nor what will be understood | ||||
| 		 on import. It is included as a working document | ||||
| 		 and this comment will be removed at such time as | ||||
| 		 the schema corresponds to reality. | ||||
| 	 --> | ||||
| 
 | ||||
| 	<!-- | ||||
| 		REST-related information | ||||
| 		Inventory data is always framed by an  | ||||
| 		inventory element. Consists of zero or | ||||
| 		more elements representing either folders | ||||
| 		or items within those folders. The inventory | ||||
| 		element represents the "real" root folder. | ||||
| 	 --> | ||||
| 
 | ||||
| 	<xsd:element name="inventory" type="inventory_ct" /> | ||||
| 
 | ||||
|     <!-- | ||||
|          The inventory complex type is just an arbitrary | ||||
|          sequence of folders and items. In reality it is | ||||
|          typically just folders. Both item and folder  | ||||
|          have corresponding complex types. It is distinct | ||||
|          from folders insofar as it has no other defining | ||||
|          attributes. | ||||
|      --> | ||||
| 
 | ||||
| 	<xsd:complexType name="inventory_ct"> | ||||
| 		<xsd:element name="folder" type="folder_ct" maxOccurs="unbounded"/> | ||||
| 		<xsd:element name="item"   type="item_ct" maxOccurs="unbounded" /> | ||||
| 	</xsd:complexType> | ||||
|   | ||||
| 	<xsd:complexType name="folder_ct"> | ||||
| 		<xsd:attribute name="UUID"         type="uuid_st" /> | ||||
| 		<xsd:attribute name="name"         type="name_st" /> | ||||
| 		<xsd:attribute name="type"         type="folder_type_st" /> | ||||
| 		<xsd:attribute name="description"  type="xsd:string" />	<!-- added --> | ||||
| 		<xsd:attribute name="version" 	   type="unsignedShort" /> | ||||
| 		<xsd:attribute name="owner"        type="uuid_st" /> | ||||
| 
 | ||||
| 		<xsd:attribute name="creator" 	   type="uuid_st" /> <!-- added --> | ||||
| 		<xsd:attribute name="creationdate" type="date_st" /> <!-- added --> | ||||
| 
 | ||||
| 		<xsd:attribute name="parent"  	   type="uuid_st" /> | ||||
| 
 | ||||
| 		<xsd:element   name="permissions"  type="permissions_ct" maxOccurs="unbounded" />	<!-- added --> | ||||
| 		<xsd:element   name="folder"       type="folder_ct"      maxOccurs="unbounded" /> | ||||
| 		<xsd:element   name="item"         type="item_ct"        maxOccurs="unbounded" /> | ||||
| 	</xsd:complexType> | ||||
| 
 | ||||
| 	<xsd:complexType name="item_ct"> | ||||
| 		<xsd:attribute name="UUID"         type="uuid_st" /> | ||||
| 		<xsd:attribute name="name"         type="name_st" /> | ||||
| 		<xsd:attribute name="type"         type="inventory_type_st" /> | ||||
| 		<xsd:attribute name="description"  type="xsd:string" /> | ||||
| 		<xsd:attribute name="version" 	   type="unsignedShort" />	<!-- added --> | ||||
| 		<xsd:attribute name="owner"        type="uuid_st" /> | ||||
| 
 | ||||
| 		<xsd:attribute name="creator" 	   type="uuid_st" /> | ||||
| 		<xsd:attribute name="creationdate" type="date_st" /> | ||||
| 
 | ||||
| 		<xsd:attribute name="folder"  	   type="uuid_st" /> | ||||
| 		<xsd:attribute name="groupid" 	   type="uuid_st" /> | ||||
| 		<xsd:attribute name="groupowned"   type="xsd:boolean" /> | ||||
| 		<xsd:attribute name="saletype"     type="sale_st" /> | ||||
| 		<xsd:attribute name="saleprice"    type="xsd:decimal" /> | ||||
| 
 | ||||
| 		<xsd:element   name="permissions"  type="permissions_ct" maxOccurs="unbounded" /> | ||||
| 	</xsd:complexType> | ||||
| 
 | ||||
| 	<xsd:complexType name="asset_ct"> | ||||
| 		<xsd:attribute name="UUID"         type="uuid_st" /> | ||||
| 		<xsd:attribute name="name"         type="name_st" /> | ||||
| 		<xsd:attribute name="type"         type="asset_type_st" /> | ||||
| 		<xsd:attribute name="description"  type="xsd:string" /> | ||||
| 		<xsd:attribute name="version" 	   type="unsignedShort" />	<!-- added --> | ||||
| 		<xsd:attribute name="owner"        type="uuid_st" /> | ||||
| 
 | ||||
| 		<xsd:attribute name="creator" 	   type="uuid_st" /> | ||||
| 		<xsd:attribute name="creationdate" type="date_st" /> | ||||
| 
 | ||||
| 		<xsd:attribute name="temporary"    type="xsd:boolean" /> | ||||
| 		<xsd:attribute name="local"        type="xsd:boolean" /> | ||||
| 		<xsd:attribute name="inline"       type="xsd:boolean" /> | ||||
| 	</xsd:complexType> | ||||
| 
 | ||||
| 	<!-- Constrained Simple Data types --> | ||||
| 
 | ||||
|     <!-- | ||||
|          We need to specify name as a simple type because on | ||||
|          some platforms it is constrained by a certain length | ||||
|          limitation. For completeness we indicate that whitespace | ||||
|          should be preserved exactly as specified. | ||||
|      --> | ||||
| 
 | ||||
| 	<xsd:simpleType name="name_st"> | ||||
| 		<xsd:restriction base="xsd:string"> | ||||
| 		    <whiteSpace value="preserve" /> | ||||
|             <minLength value="0" /> | ||||
|             <maxLength value="64" /> | ||||
| 		</xsd:restriction> | ||||
| 	</xsd:simpleType> | ||||
| 
 | ||||
|     <!-- | ||||
|          Type information in the folder is meant to indicate | ||||
|          the preferred asset type for this folder. As such, that | ||||
|          currently corresponds to the type values allowed for | ||||
|          assets, however that is not mandated, so for | ||||
|          now at least I'll represent this as a distinct  | ||||
|          enumeration. | ||||
|          This seems inappropriate; it seems like the folder's | ||||
|          content should reflect the InventoryType classifications | ||||
|          rather than the asset types. | ||||
|      --> | ||||
| 
 | ||||
| 	<xsd:simpleType name="folder_type_st"> | ||||
| 		<xsd:restriction base="xsd:string"> | ||||
| 			<xsd:enumeration value="Texture" /> | ||||
| 			<xsd:enumeration value="Sound" /> | ||||
| 			<xsd:enumeration value="CallingCard" /> | ||||
| 			<xsd:enumeration value="Landmark" /> | ||||
| 			<xsd:enumeration value="Script" /> | ||||
| 			<xsd:enumeration value="Clothing" /> | ||||
| 			<xsd:enumeration value="Object" /> | ||||
| 			<xsd:enumeration value="Notecard" /> | ||||
| 			<xsd:enumeration value="LSLText" /> | ||||
| 			<xsd:enumeration value="LSLByteCode" /> | ||||
| 			<xsd:enumeration value="TextureTGA" /> | ||||
| 			<xsd:enumeration value="BodyPart" /> | ||||
| 			<xsd:enumeration value="SoundWAV" /> | ||||
| 			<xsd:enumeration value="ImageTGA" /> | ||||
| 			<xsd:enumeration value="ImageJPEG" /> | ||||
| 			<xsd:enumeration value="Animation" /> | ||||
| 			<xsd:enumeration value="Gesture" /> | ||||
| 			<xsd:enumeration value="Simstate" /> | ||||
| 			<xsd:enumeration value="Unknown" /> | ||||
| 			<xsd:enumeration value="LostAndFoundFolder" /> | ||||
| 			<xsd:enumeration value="SnapshotFolder" /> | ||||
| 			<xsd:enumeration value="TrashFolder" /> | ||||
| 			<xsd:enumeration value="Folder" /> | ||||
| 			<xsd:enumeration value="RootFolder" /> | ||||
| 		</xsd:restriction> | ||||
| 	</xsd:simpleType> | ||||
| 
 | ||||
|     <!-- | ||||
|          Inventory item type designates an asset class, rather | ||||
|          than a specific asset type. For example, "SnapShot" | ||||
|          might include a number of asset types such as JPEG,  | ||||
|          TGA, etc.. This is not a consistent interpretation, | ||||
|          classifications such as LostAndFound are meta-types | ||||
|          relative to asset classes.  | ||||
| 
 | ||||
|          These types should be abstract and not be tied to a  | ||||
|          specific platform. A world's import facility should be | ||||
|          responsible for mapping these to meaningful internal | ||||
|          representations. | ||||
| 
 | ||||
|          These types were based on information in: | ||||
|              libsecondlife/InventoryManager.cs | ||||
|      --> | ||||
| 
 | ||||
| 	<xsd:simpleType name="inventory_type_st"> | ||||
| 		<xsd:restriction base="xsd:string"> | ||||
| 			<xsd:enumeration value="Texture" /> | ||||
| 			<xsd:enumeration value="Sound" /> | ||||
| 			<xsd:enumeration value="CallingCard" /> | ||||
| 			<xsd:enumeration value="Landmark" /> | ||||
| 			<xsd:enumeration value="Script" /> | ||||
| 			<xsd:enumeration value="Clothing" /> | ||||
| 			<xsd:enumeration value="Object" /> | ||||
| 			<xsd:enumeration value="Notecard" /> | ||||
| 			<xsd:enumeration value="LSL" /> | ||||
| 			<xsd:enumeration value="LSLBytecode" /> | ||||
| 			<xsd:enumeration value="TextureTGA" /> | ||||
| 			<xsd:enumeration value="BodyPart" /> | ||||
| 			<xsd:enumeration value="Snapshot" /> | ||||
| 			<xsd:enumeration value="Attachment" /> | ||||
| 			<xsd:enumeration value="Wearable" /> | ||||
| 			<xsd:enumeration value="Animation" /> | ||||
| 			<xsd:enumeration value="Gesture" /> | ||||
| 			<xsd:enumeration value="Folder" /> | ||||
| 			<xsd:enumeration value="Unknown" /> | ||||
| 			<xsd:enumeration value="LostAndFound" /> | ||||
| 			<xsd:enumeration value="Trash" /> | ||||
| 			<xsd:enumeration value="Root" /> | ||||
| 		</xsd:restriction> | ||||
| 	</xsd:simpleType> | ||||
| 
 | ||||
|     <!-- | ||||
|          The asset types seem to be even more disarrayed than | ||||
|          the inventory types. It seems to be little more than | ||||
|          a reiteration of the inventory type information, | ||||
|          which adds little or nothing to the overall data | ||||
|          model. | ||||
| 
 | ||||
|          Of course, given that these are drawn from the | ||||
|          libsecondlife definitions, we aren't at liberty to | ||||
|          simply redefine them in place. But the XML definitions | ||||
|          here could be made more useful. | ||||
| 
 | ||||
|          These types were based on information in: | ||||
|              libsecondlife/AssetManager.cs | ||||
|      --> | ||||
| 
 | ||||
| 	<xsd:simpleType name="asset_type_st"> | ||||
| 		<xsd:restriction base="xsd:string"> | ||||
| 			<xsd:enumeration value="Texture" /> | ||||
| 			<xsd:enumeration value="Sound" /> | ||||
| 			<xsd:enumeration value="CallingCard" /> | ||||
| 			<xsd:enumeration value="Landmark" /> | ||||
| 			<xsd:enumeration value="Script" /> | ||||
| 			<xsd:enumeration value="Clothing" /> | ||||
| 			<xsd:enumeration value="Object" /> | ||||
| 			<xsd:enumeration value="Notecard" /> | ||||
| 			<xsd:enumeration value="LSLText" /> | ||||
| 			<xsd:enumeration value="LSLByteCode" /> | ||||
| 			<xsd:enumeration value="TextureTGA" /> | ||||
| 			<xsd:enumeration value="BodyPart" /> | ||||
| 			<xsd:enumeration value="SoundWAV" /> | ||||
| 			<xsd:enumeration value="ImageTGA" /> | ||||
| 			<xsd:enumeration value="ImageJPEG" /> | ||||
| 			<xsd:enumeration value="Animation" /> | ||||
| 			<xsd:enumeration value="Gesture" /> | ||||
| 			<xsd:enumeration value="Simstate" /> | ||||
| 			<xsd:enumeration value="Unknown" /> | ||||
| 			<xsd:enumeration value="LostAndFoundFolder" /> | ||||
| 			<xsd:enumeration value="SnapshotFolder" /> | ||||
| 			<xsd:enumeration value="TrashFolder" /> | ||||
| 			<xsd:enumeration value="Folder" /> | ||||
| 			<xsd:enumeration value="RootFolder" /> | ||||
| 		</xsd:restriction> | ||||
| 	</xsd:simpleType> | ||||
| 
 | ||||
|     <!-- This is describing the apparent form of a UUID. If | ||||
|          we ever want a more metaphysical definition we'll  | ||||
|          need to add to it. | ||||
|      --> | ||||
| 
 | ||||
| 	<xsd:simpleType name="uuid_st"> | ||||
| 		<xsd:restriction base="xsd:string"> | ||||
| 		    <xsd:pattern value="[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"/> | ||||
| 		</xsd:restriction> | ||||
| 	</xsd:simpleType> | ||||
| 
 | ||||
|     <!-- This constrains the date representation. Currently | ||||
|          it is simply an integer representing the elapsed | ||||
| 		 ?? since ??. | ||||
|      --> | ||||
| 
 | ||||
| 	<xsd:simpleType name="date_st"> | ||||
| 		<xsd:restriction base="xsd:positiveInteger"> | ||||
| 		</xsd:restriction> | ||||
| 	</xsd:simpleType> | ||||
| 
 | ||||
|     <!-- This constrains the representation of sale price. | ||||
| 		 Currently it is a simple decimal with no unit | ||||
| 		 specified.  | ||||
|          Issues: interoperability. | ||||
|      --> | ||||
| 
 | ||||
| 	<xsd:simpleType name="sale_st"> | ||||
| 		<xsd:restriction base="xsd:decimal"> | ||||
| 		</xsd:restriction> | ||||
| 	</xsd:simpleType> | ||||
| 
 | ||||
| </xsd:schema> | ||||
|  | @ -28,10 +28,8 @@ | |||
| using System; | ||||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| using System.Collections.Concurrent; | ||||
| using System.IO; | ||||
| using System.Reflection; | ||||
| using System.Threading; | ||||
| using log4net; | ||||
| using Nini.Config; | ||||
| using OpenMetaverse; | ||||
|  | @ -50,9 +48,10 @@ namespace OpenSim.Framework.Capabilities | |||
|     /// </summary> | ||||
|     public delegate IClientAPI GetClientDelegate(UUID agentID); | ||||
| 
 | ||||
|     public class Caps : IDisposable | ||||
|     public class Caps | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| //        private static readonly ILog m_log = | ||||
| //            LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private string m_httpListenerHostName; | ||||
|         private uint m_httpListenPort; | ||||
|  | @ -64,16 +63,11 @@ namespace OpenSim.Framework.Capabilities | |||
|         public string CapsObjectPath { get { return m_capsObjectPath; } } | ||||
| 
 | ||||
|         private CapsHandlers m_capsHandlers; | ||||
| 
 | ||||
|         private ConcurrentDictionary<string, PollServiceEventArgs> m_pollServiceHandlers | ||||
|             = new ConcurrentDictionary<string, PollServiceEventArgs>(); | ||||
| 
 | ||||
|         private Dictionary<string, string> m_externalCapsHandlers = new Dictionary<string, string>(); | ||||
|         private Dictionary<string, string> m_externalCapsHandlers; | ||||
| 
 | ||||
|         private IHttpServer m_httpListener; | ||||
|         private UUID m_agentID; | ||||
|         private string m_regionName; | ||||
|         private ManualResetEvent m_capsActive = new ManualResetEvent(false); | ||||
| 
 | ||||
|         public UUID AgentID | ||||
|         { | ||||
|  | @ -120,19 +114,6 @@ namespace OpenSim.Framework.Capabilities | |||
|             get { return m_externalCapsHandlers; } | ||||
|         } | ||||
| 
 | ||||
|         [Flags] | ||||
|         public enum CapsFlags:uint | ||||
|         { | ||||
|             None =          0, | ||||
|             SentSeeds =     1, | ||||
| 
 | ||||
|             ObjectAnim =    0x100, | ||||
|             WLEnv =         0x200, | ||||
|             AdvEnv =        0x400 | ||||
|         } | ||||
| 
 | ||||
|         public CapsFlags Flags { get; set;} | ||||
| 
 | ||||
|         public Caps(IHttpServer httpServer, string httpListen, uint httpPort, string capsPath, | ||||
|                     UUID agent, string regionName) | ||||
|         { | ||||
|  | @ -150,37 +131,9 @@ namespace OpenSim.Framework.Capabilities | |||
|             } | ||||
| 
 | ||||
|             m_agentID = agent; | ||||
|             m_capsHandlers = new CapsHandlers(httpServer, httpListen, httpPort); | ||||
|             m_capsHandlers = new CapsHandlers(httpServer, httpListen, httpPort, (httpServer == null) ? false : httpServer.UseSSL); | ||||
|             m_externalCapsHandlers = new Dictionary<string, string>(); | ||||
|             m_regionName = regionName; | ||||
|             Flags = CapsFlags.None; | ||||
|             m_capsActive.Reset(); | ||||
|         } | ||||
| 
 | ||||
|         ~Caps() | ||||
|         { | ||||
|             Flags = CapsFlags.None; | ||||
|             if (m_capsActive!= null) | ||||
|             { | ||||
|                 m_capsActive.Dispose(); | ||||
|                 m_capsActive = null; | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         public void Dispose() | ||||
|         { | ||||
|             Dispose(true); | ||||
|             GC.SuppressFinalize(this); | ||||
|         } | ||||
| 
 | ||||
|         public void Dispose(bool disposing) | ||||
|         { | ||||
|             Flags = CapsFlags.None; | ||||
|             if (m_capsActive != null) | ||||
|             { | ||||
|                 DeregisterHandlers(); | ||||
|                 m_capsActive.Dispose(); | ||||
|                 m_capsActive = null; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|  | @ -190,45 +143,8 @@ namespace OpenSim.Framework.Capabilities | |||
|         /// <param name="handler"></param> | ||||
|         public void RegisterHandler(string capName, IRequestHandler handler) | ||||
|         { | ||||
|             //m_log.DebugFormat("[CAPS]: Registering handler for \"{0}\": path {1}", capName, handler.Path); | ||||
|             m_capsHandlers[capName] = handler; | ||||
|         } | ||||
| 
 | ||||
|         public void RegisterSimpleHandler(string capName, ISimpleStreamHandler handler, bool addToListener = true) | ||||
|         { | ||||
|             //m_log.DebugFormat("[CAPS]: Registering handler for \"{0}\": path {1}", capName, handler.Path); | ||||
|             m_capsHandlers.AddSimpleHandler(capName, handler, addToListener); | ||||
|         } | ||||
| 
 | ||||
|         public void RegisterPollHandler(string capName, PollServiceEventArgs pollServiceHandler) | ||||
|         { | ||||
| //            m_log.DebugFormat( | ||||
| //                "[CAPS]: Registering handler with name {0}, url {1} for {2}", | ||||
| //                capName, pollServiceHandler.Url, m_agentID, m_regionName); | ||||
| 
 | ||||
|             if(!m_pollServiceHandlers.TryAdd(capName, pollServiceHandler)) | ||||
|             { | ||||
|                 m_log.ErrorFormat( | ||||
|                     "[CAPS]: Handler with name {0} already registered (ulr {1}, agent {2}, region {3}", | ||||
|                     capName, pollServiceHandler.Url, m_agentID, m_regionName); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             m_httpListener.AddPollServiceHTTPHandler(pollServiceHandler); | ||||
| 
 | ||||
| //            uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; | ||||
| //            string protocol = "http"; | ||||
| //            string hostName = m_httpListenerHostName; | ||||
| // | ||||
| //            if (MainServer.Instance.UseSSL) | ||||
| //            { | ||||
| //                hostName = MainServer.Instance.SSLCommonName; | ||||
| //                port = MainServer.Instance.SSLPort; | ||||
| //                protocol = "https"; | ||||
| //            } | ||||
| 
 | ||||
| //            RegisterHandler( | ||||
| //                capName, String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, pollServiceHandler.Url)); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|  | @ -247,80 +163,13 @@ namespace OpenSim.Framework.Capabilities | |||
|         /// </summary> | ||||
|         public void DeregisterHandlers() | ||||
|         { | ||||
|             foreach (string capsName in m_capsHandlers.Caps) | ||||
|             if (m_capsHandlers != null) | ||||
|             { | ||||
|                 m_capsHandlers.Remove(capsName); | ||||
|             } | ||||
| 
 | ||||
|             foreach (PollServiceEventArgs handler in m_pollServiceHandlers.Values) | ||||
|             { | ||||
|                 m_httpListener.RemovePollServiceHTTPHandler(handler.Url); | ||||
|             } | ||||
|             m_pollServiceHandlers.Clear(); | ||||
|         } | ||||
| 
 | ||||
|         public bool TryGetPollHandler(string name, out PollServiceEventArgs pollHandler) | ||||
|         { | ||||
|             return m_pollServiceHandlers.TryGetValue(name, out pollHandler); | ||||
|         } | ||||
| 
 | ||||
|         public Dictionary<string, PollServiceEventArgs> GetPollHandlers() | ||||
|         { | ||||
|             return new Dictionary<string, PollServiceEventArgs>(m_pollServiceHandlers); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Return an LLSD-serializable Hashtable describing the | ||||
|         /// capabilities and their handler details. | ||||
|         /// </summary> | ||||
|         /// <param name="excludeSeed">If true, then exclude the seed cap.</param> | ||||
|         public Hashtable GetCapsDetails(bool excludeSeed, List<string> requestedCaps) | ||||
|         { | ||||
|             Hashtable caps = CapsHandlers.GetCapsDetails(excludeSeed, requestedCaps); | ||||
| 
 | ||||
|             lock (m_pollServiceHandlers) | ||||
|             { | ||||
|                 foreach (KeyValuePair <string, PollServiceEventArgs> kvp in m_pollServiceHandlers) | ||||
|                 foreach (string capsName in m_capsHandlers.Caps) | ||||
|                 { | ||||
|                     if (!requestedCaps.Contains(kvp.Key)) | ||||
|                         continue; | ||||
| 
 | ||||
|                         string hostName = m_httpListenerHostName; | ||||
|                         uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; | ||||
|                         string protocol = "http"; | ||||
| 
 | ||||
|                         if (MainServer.Instance.UseSSL) | ||||
|                         { | ||||
|                             hostName = MainServer.Instance.SSLCommonName; | ||||
|                             port = MainServer.Instance.SSLPort; | ||||
|                             protocol = "https"; | ||||
|                         } | ||||
|                         caps[kvp.Key] = string.Format("{0}://{1}:{2}{3}", protocol, hostName, port, kvp.Value.Url); | ||||
|                     m_capsHandlers.Remove(capsName); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // Add the external too | ||||
|             foreach (KeyValuePair<string, string> kvp in ExternalCapsHandlers) | ||||
|             { | ||||
|                 if (!requestedCaps.Contains(kvp.Key)) | ||||
|                     continue; | ||||
| 
 | ||||
|                 caps[kvp.Key] = kvp.Value; | ||||
|             } | ||||
| 
 | ||||
| 
 | ||||
|             return caps; | ||||
|         } | ||||
| 
 | ||||
|         public void Activate() | ||||
|         { | ||||
|             m_capsActive.Set(); | ||||
|         } | ||||
| 
 | ||||
|         public bool WaitForActivation() | ||||
|         { | ||||
|             // Wait for 30s. If that elapses, return false and run without caps | ||||
|             return m_capsActive.WaitOne(120000); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -27,7 +27,6 @@ | |||
| 
 | ||||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| using System.Collections.Concurrent; | ||||
| using OpenSim.Framework.Servers; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| 
 | ||||
|  | @ -40,8 +39,7 @@ namespace OpenSim.Framework.Capabilities | |||
|     /// </summary> | ||||
|     public class CapsHandlers | ||||
|     { | ||||
|         private Dictionary<string, IRequestHandler> m_capsHandlers = new Dictionary<string, IRequestHandler>(); | ||||
|         private ConcurrentDictionary<string, ISimpleStreamHandler> m_capsSimpleHandlers = new ConcurrentDictionary<string, ISimpleStreamHandler>(); | ||||
|         private Dictionary <string, IRequestHandler> m_capsHandlers = new Dictionary<string, IRequestHandler>(); | ||||
|         private IHttpServer m_httpListener; | ||||
|         private string m_httpListenerHostName; | ||||
|         private uint m_httpListenerPort; | ||||
|  | @ -55,15 +53,31 @@ namespace OpenSim.Framework.Capabilities | |||
|         /// <param name="httpListener">base HTTP server</param> | ||||
|         /// <param name="httpListenerHostname">host name of the HTTP server</param> | ||||
|         /// <param name="httpListenerPort">HTTP port</param> | ||||
|         public CapsHandlers(IHttpServer httpListener, string httpListenerHostname, uint httpListenerPort) | ||||
|            { | ||||
|         public CapsHandlers(BaseHttpServer httpListener, string httpListenerHostname, uint httpListenerPort) | ||||
|             : this(httpListener,httpListenerHostname,httpListenerPort, false) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         /// <summary></summary> | ||||
|         /// CapsHandlers is a cap handler container but also takes | ||||
|         /// care of adding and removing cap handlers to and from the | ||||
|         /// supplied BaseHttpServer. | ||||
|         /// </summary> | ||||
|         /// <param name="httpListener">base HTTP server</param> | ||||
|         /// <param name="httpListenerHostname">host name of the HTTP | ||||
|         /// server</param> | ||||
|         /// <param name="httpListenerPort">HTTP port</param> | ||||
|         public CapsHandlers(IHttpServer httpListener, string httpListenerHostname, uint httpListenerPort, bool https) | ||||
|         { | ||||
|             m_httpListener = httpListener; | ||||
|             m_httpListenerHostName = httpListenerHostname; | ||||
|             m_httpListenerPort = httpListenerPort; | ||||
|             if (httpListener != null && httpListener.UseSSL) | ||||
|                 m_useSSL = true; | ||||
|             else | ||||
|                 m_useSSL = false; | ||||
|             m_useSSL = https; | ||||
|             if (httpListener != null && m_useSSL) | ||||
|             { | ||||
|                 m_httpListenerHostName = httpListener.SSLCommonName; | ||||
|                 m_httpListenerPort = httpListener.SSLPort; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|  | @ -75,35 +89,16 @@ namespace OpenSim.Framework.Capabilities | |||
|         { | ||||
|             lock (m_capsHandlers) | ||||
|             { | ||||
|                 if(m_capsHandlers.ContainsKey(capsName)) | ||||
|                 { | ||||
|                     m_httpListener.RemoveStreamHandler("POST", m_capsHandlers[capsName].Path); | ||||
|                     m_httpListener.RemoveStreamHandler("PUT", m_capsHandlers[capsName].Path); | ||||
|                     m_httpListener.RemoveStreamHandler("GET", m_capsHandlers[capsName].Path); | ||||
|                     m_httpListener.RemoveStreamHandler("DELETE", m_capsHandlers[capsName].Path); | ||||
|                     m_capsHandlers.Remove(capsName); | ||||
|                 } | ||||
|                 m_httpListener.RemoveStreamHandler("POST", m_capsHandlers[capsName].Path); | ||||
|                 m_httpListener.RemoveStreamHandler("GET", m_capsHandlers[capsName].Path); | ||||
|                 m_capsHandlers.Remove(capsName); | ||||
|             } | ||||
|             if(m_capsSimpleHandlers.TryRemove(capsName, out ISimpleStreamHandler hdr)) | ||||
|             { | ||||
|                 m_httpListener.RemoveSimpleStreamHandler(hdr.Path); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void AddSimpleHandler(string capName, ISimpleStreamHandler handler, bool addToListener = true) | ||||
|         { | ||||
|             if(ContainsCap(capName)) | ||||
|                 Remove(capName); | ||||
|             if(m_capsSimpleHandlers.TryAdd(capName, handler) && addToListener) | ||||
|                 m_httpListener.AddSimpleStreamHandler(handler); | ||||
|         } | ||||
| 
 | ||||
|         public bool ContainsCap(string cap) | ||||
|         { | ||||
|             lock (m_capsHandlers) | ||||
|                 if (m_capsHandlers.ContainsKey(cap)) | ||||
|                     return true; | ||||
|             return m_capsSimpleHandlers.ContainsKey(cap); | ||||
|                 return m_capsHandlers.ContainsKey(cap); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|  | @ -130,14 +125,11 @@ namespace OpenSim.Framework.Capabilities | |||
|                     if (m_capsHandlers.ContainsKey(idx)) | ||||
|                     { | ||||
|                         m_httpListener.RemoveStreamHandler("POST", m_capsHandlers[idx].Path); | ||||
|                         m_httpListener.RemoveStreamHandler("PUT", m_capsHandlers[idx].Path); | ||||
|                         m_httpListener.RemoveStreamHandler("GET", m_capsHandlers[idx].Path); | ||||
|                         m_httpListener.RemoveStreamHandler("DELETE", m_capsHandlers[idx].Path); | ||||
|                         m_capsHandlers.Remove(idx); | ||||
|                     } | ||||
| 
 | ||||
|      | ||||
|                     if (null == value) return; | ||||
| 
 | ||||
|      | ||||
|                     m_capsHandlers[idx] = value; | ||||
|                     m_httpListener.AddStreamHandler(value); | ||||
|                 } | ||||
|  | @ -154,9 +146,8 @@ namespace OpenSim.Framework.Capabilities | |||
|             { | ||||
|                 lock (m_capsHandlers) | ||||
|                 { | ||||
|                     string[] __keys = new string[m_capsHandlers.Keys.Count + m_capsSimpleHandlers.Keys.Count]; | ||||
|                     string[] __keys = new string[m_capsHandlers.Keys.Count]; | ||||
|                     m_capsHandlers.Keys.CopyTo(__keys, 0); | ||||
|                     m_capsSimpleHandlers.Keys.CopyTo(__keys, m_capsHandlers.Keys.Count); | ||||
|                     return __keys; | ||||
|                 } | ||||
|             } | ||||
|  | @ -167,58 +158,28 @@ namespace OpenSim.Framework.Capabilities | |||
|         /// capabilities and their handler details. | ||||
|         /// </summary> | ||||
|         /// <param name="excludeSeed">If true, then exclude the seed cap.</param> | ||||
|         public Hashtable GetCapsDetails(bool excludeSeed, List<string> requestedCaps) | ||||
|         public Hashtable GetCapsDetails(bool excludeSeed) | ||||
|         { | ||||
|             Hashtable caps = new Hashtable(); | ||||
|             string protocol = "http://"; | ||||
|              | ||||
|             if (m_useSSL) | ||||
|                 protocol = "https://"; | ||||
| 
 | ||||
|             string protocol = m_useSSL ? "https://" : "http://"; | ||||
|             string baseUrl = protocol + m_httpListenerHostName + ":" + m_httpListenerPort.ToString(); | ||||
| 
 | ||||
|             if (requestedCaps == null) | ||||
|             { | ||||
|                 lock (m_capsHandlers) | ||||
|                 { | ||||
|                     foreach (KeyValuePair<string, ISimpleStreamHandler> kvp in m_capsSimpleHandlers) | ||||
|                         caps[kvp.Key] = baseUrl + kvp.Value.Path; | ||||
|                     foreach (KeyValuePair<string, IRequestHandler> kvp in m_capsHandlers) | ||||
|                         caps[kvp.Key] = baseUrl + kvp.Value.Path; | ||||
|                 } | ||||
|                 return caps; | ||||
|             } | ||||
| 
 | ||||
|             lock (m_capsHandlers) | ||||
|             { | ||||
|                 for(int i = 0; i < requestedCaps.Count; ++i) | ||||
|                 foreach (string capsName in m_capsHandlers.Keys) | ||||
|                 { | ||||
|                     string capsName = requestedCaps[i]; | ||||
|                     if (excludeSeed && "SEED" == capsName) | ||||
|                         continue; | ||||
| 
 | ||||
|                     if (m_capsSimpleHandlers.TryGetValue(capsName, out ISimpleStreamHandler shdr)) | ||||
|                     { | ||||
|                         caps[capsName] = baseUrl + shdr.Path; | ||||
|                         continue; | ||||
|                     } | ||||
|                     if (m_capsHandlers.TryGetValue(capsName, out IRequestHandler chdr)) | ||||
|                     { | ||||
|                         caps[capsName] = baseUrl + chdr.Path; | ||||
|                     } | ||||
|                     caps[capsName] = baseUrl + m_capsHandlers[capsName].Path; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return caps; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Returns a copy of the dictionary of all the HTTP cap handlers | ||||
|         /// </summary> | ||||
|         /// <returns> | ||||
|         /// The dictionary copy.  The key is the capability name, the value is the HTTP handler. | ||||
|         /// </returns> | ||||
|         public Dictionary<string, IRequestHandler> GetCapsHandlers() | ||||
|         { | ||||
|             lock (m_capsHandlers) | ||||
|                 return new Dictionary<string, IRequestHandler>(m_capsHandlers); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -1,449 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Linq; | ||||
| using System.Reflection; | ||||
| using System.Text; | ||||
| using log4net; | ||||
| using Nini.Config; | ||||
| using OpenMetaverse; | ||||
| using OpenMetaverse.StructuredData; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Capabilities; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Services.Interfaces; | ||||
| using OSDMap = OpenMetaverse.StructuredData.OSDMap; | ||||
| using OSDArray = OpenMetaverse.StructuredData.OSDArray; | ||||
| 
 | ||||
| namespace OpenSim.Capabilities.Handlers | ||||
| { | ||||
|     public class FetchInvDescHandler | ||||
|     { | ||||
|         private static readonly ILog m_log = | ||||
|             LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private static byte[] EmptyResponse = Util.UTF8NBGetbytes("<llsd><map><key>folders</key><array /></map></llsd>"); | ||||
|         private IInventoryService m_InventoryService; | ||||
|         private ILibraryService m_LibraryService; | ||||
|         private IScene m_Scene; | ||||
| 
 | ||||
|         public FetchInvDescHandler(IInventoryService invService, ILibraryService libService, IScene s) | ||||
|         { | ||||
|             m_InventoryService = invService; | ||||
|             m_LibraryService = libService; | ||||
|             m_Scene = s; | ||||
|         } | ||||
| 
 | ||||
|         public void FetchInventoryDescendentsRequest(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, ExpiringKey<UUID> BadRequests) | ||||
|         { | ||||
|             //m_log.DebugFormat("[XXX]: FetchInventoryDescendentsRequest in {0}, {1}", (m_Scene == null) ? "none" : m_Scene.Name, request); | ||||
| 
 | ||||
|             List<LLSDFetchInventoryDescendents> folders = null; | ||||
|             List<UUID> bad_folders = new List<UUID>(); | ||||
|             try | ||||
|             { | ||||
|                 OSDArray foldersrequested = null; | ||||
|                 OSD tmp = OSDParser.DeserializeLLSDXml(httpRequest.InputStream); | ||||
|                 OSDMap map = (OSDMap)tmp; | ||||
|                 if(map.TryGetValue("folders", out tmp) && tmp is OSDArray) | ||||
|                     foldersrequested = tmp as OSDArray; | ||||
| 
 | ||||
|                 if (foldersrequested == null || foldersrequested.Count == 0) | ||||
|                 { | ||||
|                     httpResponse.RawBuffer = EmptyResponse; | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 folders = new List<LLSDFetchInventoryDescendents>(foldersrequested.Count); | ||||
|                 for (int i = 0; i < foldersrequested.Count; i++) | ||||
|                 { | ||||
|                     OSDMap mfolder = foldersrequested[i] as OSDMap; | ||||
|                     UUID id = mfolder["folder_id"].AsUUID(); | ||||
|                     if(BadRequests.ContainsKey(id)) | ||||
|                     { | ||||
|                         bad_folders.Add(id); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); | ||||
|                         try | ||||
|                         { | ||||
|                             llsdRequest.folder_id = id; | ||||
|                             llsdRequest.owner_id = mfolder["owner_id"].AsUUID(); | ||||
|                             llsdRequest.sort_order = mfolder["sort_order"].AsInteger(); | ||||
|                             llsdRequest.fetch_folders = mfolder["fetch_folders"].AsBoolean(); | ||||
|                             llsdRequest.fetch_items = mfolder["fetch_items"].AsBoolean(); | ||||
|                         } | ||||
|                         catch (Exception e) | ||||
|                         { | ||||
|                             m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e.Message); | ||||
|                             continue; | ||||
|                         } | ||||
|                         folders.Add(llsdRequest); | ||||
|                     } | ||||
|                 } | ||||
|                 foldersrequested = null; | ||||
|                 tmp = null; | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 m_log.ErrorFormat("[FETCH INV DESC]: fail parsing request: {0}", e.Message); | ||||
|                 httpResponse.RawBuffer = EmptyResponse; | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (folders == null || folders.Count == 0) | ||||
|             { | ||||
|                 if(bad_folders.Count == 0) | ||||
|                 { | ||||
|                     httpResponse.RawBuffer = EmptyResponse; | ||||
|                     return; | ||||
|                 } | ||||
|                 StringBuilder sb = osStringBuilderCache.Acquire(); | ||||
|                 sb.Append("<llsd><map><key>folders</key><array /></map><map><key>bad_folders</key><array>"); | ||||
|                 foreach (UUID bad in bad_folders) | ||||
|                 { | ||||
|                     sb.Append("<map><key>folder_id</key><uuid>"); | ||||
|                     sb.Append(bad.ToString()); | ||||
|                     sb.Append("</uuid><key>error</key><string>Unknown</string></map>"); | ||||
|                 } | ||||
|                 sb.Append("</array></map></llsd>"); | ||||
|                 httpResponse.RawBuffer = Util.UTF8NBGetbytes(osStringBuilderCache.GetStringAndRelease(sb)); | ||||
|             } | ||||
| 
 | ||||
|             int total_folders = 0; | ||||
|             int total_items = 0; | ||||
| 
 | ||||
|             List<InventoryCollection> invcollSet = Fetch(folders, bad_folders, ref total_folders, ref total_items); | ||||
|             //m_log.DebugFormat("[XXX]: Got {0} folders from a request of {1}", invcollSet.Count, folders.Count); | ||||
| 
 | ||||
|             int invcollSetCount = 0; | ||||
|             if (invcollSet != null) | ||||
|                 invcollSetCount = invcollSet.Count; | ||||
| 
 | ||||
|             int mem = 8192 + ((256 * invcollSetCount + | ||||
|                                 384 * total_folders + | ||||
|                                 1024 * total_items + | ||||
|                                 128 * bad_folders.Count) & 0x7ffff000); | ||||
| 
 | ||||
|             StringBuilder lastresponse = new StringBuilder(mem); | ||||
|             lastresponse.Append("<llsd>"); | ||||
| 
 | ||||
|             if (invcollSetCount > 0) | ||||
|             { | ||||
|                 lastresponse.Append("<map><key>folders</key><array>"); | ||||
|                 int i = 0; | ||||
|                 InventoryCollection thiscoll; | ||||
|                 for (i = 0; i < invcollSetCount; i++) | ||||
|                 { | ||||
|                     thiscoll = invcollSet[i]; | ||||
|                     invcollSet[i] = null; | ||||
| 
 | ||||
|                     LLSDxmlEncode.AddMap(lastresponse); | ||||
|                     LLSDxmlEncode.AddElem("agent_id", thiscoll.OwnerID, lastresponse); | ||||
|                     LLSDxmlEncode.AddElem("descendents", thiscoll.Descendents, lastresponse); | ||||
|                     LLSDxmlEncode.AddElem("folder_id", thiscoll.FolderID, lastresponse); | ||||
| 
 | ||||
|                     if (thiscoll.Folders == null || thiscoll.Folders.Count == 0) | ||||
|                         LLSDxmlEncode.AddEmptyArray("categories", lastresponse); | ||||
|                     else | ||||
|                     { | ||||
|                         LLSDxmlEncode.AddArray("categories", lastresponse); | ||||
|                         foreach (InventoryFolderBase invFolder in thiscoll.Folders) | ||||
|                         { | ||||
|                             LLSDxmlEncode.AddMap(lastresponse); | ||||
| 
 | ||||
|                             LLSDxmlEncode.AddElem("folder_id", invFolder.ID, lastresponse); | ||||
|                             LLSDxmlEncode.AddElem("parent_id", invFolder.ParentID, lastresponse); | ||||
|                             LLSDxmlEncode.AddElem("name", invFolder.Name, lastresponse); | ||||
|                             LLSDxmlEncode.AddElem("type", invFolder.Type, lastresponse); | ||||
|                             LLSDxmlEncode.AddElem("preferred_type", (int)-1, lastresponse); | ||||
|                             LLSDxmlEncode.AddElem("version", invFolder.Version, lastresponse); | ||||
| 
 | ||||
|                             LLSDxmlEncode.AddEndMap(lastresponse); | ||||
|                         } | ||||
|                         LLSDxmlEncode.AddEndArray(lastresponse); | ||||
|                     } | ||||
| 
 | ||||
|                     if (thiscoll.Items == null || thiscoll.Items.Count == 0) | ||||
|                         LLSDxmlEncode.AddEmptyArray("items", lastresponse); | ||||
|                     else | ||||
|                     { | ||||
|                         LLSDxmlEncode.AddArray("items", lastresponse); | ||||
|                         foreach (InventoryItemBase invItem in thiscoll.Items) | ||||
|                         { | ||||
|                             invItem.ToLLSDxml(lastresponse); | ||||
|                         } | ||||
| 
 | ||||
|                         LLSDxmlEncode.AddEndArray(lastresponse); | ||||
|                     } | ||||
| 
 | ||||
|                     LLSDxmlEncode.AddElem("owner_id", thiscoll.OwnerID, lastresponse); | ||||
|                     LLSDxmlEncode.AddElem("version", thiscoll.Version, lastresponse); | ||||
| 
 | ||||
|                     LLSDxmlEncode.AddEndMap(lastresponse); | ||||
|                     invcollSet[i] = null; | ||||
|                 } | ||||
|                 lastresponse.Append("</array></map>"); | ||||
|                 thiscoll = null; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 lastresponse.Append("<map><key>folders</key><array /></map>"); | ||||
|             } | ||||
| 
 | ||||
|             //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Bad folders {0}", string.Join(", ", bad_folders)); | ||||
|             if (bad_folders.Count > 0) | ||||
|             { | ||||
|                 lastresponse.Append("<map><key>bad_folders</key><array>"); | ||||
|                 foreach (UUID bad in bad_folders) | ||||
|                 { | ||||
|                     BadRequests.Add(bad); | ||||
|                     lastresponse.Append("<map><key>folder_id</key><uuid>"); | ||||
|                     lastresponse.Append(bad.ToString()); | ||||
|                     lastresponse.Append("</uuid><key>error</key><string>Unknown</string></map>"); | ||||
|                 } | ||||
|                 lastresponse.Append("</array></map>"); | ||||
|             } | ||||
|             lastresponse.Append("</llsd>"); | ||||
| 
 | ||||
|             httpResponse.RawBuffer = Util.UTF8NBGetbytes(lastresponse.ToString()); | ||||
|         } | ||||
| 
 | ||||
|         private void AddLibraryFolders(List<LLSDFetchInventoryDescendents> libFolders, List<InventoryCollection> result, ref int total_folders, ref int total_items) | ||||
|         { | ||||
|             InventoryFolderImpl fold; | ||||
|             if (m_LibraryService == null || m_LibraryService.LibraryRootFolder == null) | ||||
|                 return; | ||||
|              | ||||
|             foreach (LLSDFetchInventoryDescendents f in libFolders) | ||||
|             { | ||||
|                 if ((fold = m_LibraryService.LibraryRootFolder.FindFolder(f.folder_id)) != null) | ||||
|                 { | ||||
|                     InventoryCollection Collection = new InventoryCollection(); | ||||
| //                        ret.Collection.Folders = new List<InventoryFolderBase>(); | ||||
|                     Collection.Folders = fold.RequestListOfFolders(); | ||||
|                     Collection.Items = fold.RequestListOfItems(); | ||||
|                     Collection.OwnerID = m_LibraryService.LibraryRootFolder.Owner; | ||||
|                     Collection.FolderID = f.folder_id; | ||||
|                     Collection.Version = fold.Version; | ||||
| 
 | ||||
|                     Collection.Descendents = Collection.Items.Count + Collection.Folders.Count; | ||||
|                     total_folders += Collection.Folders.Count; | ||||
|                     total_items += Collection.Items.Count; | ||||
|                     result.Add(Collection); | ||||
| 
 | ||||
|                     //m_log.DebugFormat("[XXX]: Added libfolder {0} ({1}) {2}", ret.Collection.FolderID, ret.Collection.OwnerID); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private List<InventoryCollection> Fetch(List<LLSDFetchInventoryDescendents> fetchFolders, List<UUID> bad_folders, ref int total_folders, ref int total_items) | ||||
|         { | ||||
|             //m_log.DebugFormat( | ||||
|             //    "[WEB FETCH INV DESC HANDLER]: Fetching {0} folders for owner {1}", fetchFolders.Count, fetchFolders[0].owner_id); | ||||
| 
 | ||||
|             // FIXME MAYBE: We're not handling sortOrder! | ||||
| 
 | ||||
|             List<InventoryCollection> result = new List<InventoryCollection>(32); | ||||
|             List<LLSDFetchInventoryDescendents> libFolders = new List<LLSDFetchInventoryDescendents>(32); | ||||
|             List<LLSDFetchInventoryDescendents> otherFolders = new List<LLSDFetchInventoryDescendents>(32); | ||||
|             HashSet<UUID> libIDs = new HashSet<UUID>(); | ||||
|             HashSet<UUID> otherIDs = new HashSet<UUID>(); | ||||
| 
 | ||||
|             bool dolib = (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null); | ||||
|             UUID libOwner = UUID.Zero; | ||||
|             if(dolib) | ||||
|                 libOwner = m_LibraryService.LibraryRootFolder.Owner; | ||||
| 
 | ||||
|             // Filter folder Zero right here. Some viewers (Firestorm) send request for folder Zero, which doesn't make sense | ||||
|             // and can kill the sim (all root folders have parent_id Zero) | ||||
|             // send something. | ||||
|             bool doneZeroID = false; | ||||
|             foreach(LLSDFetchInventoryDescendents f in fetchFolders) | ||||
|             { | ||||
|                 if (f.folder_id == UUID.Zero) | ||||
|                 { | ||||
|                     if(doneZeroID) | ||||
|                         continue; | ||||
|                     doneZeroID = true; | ||||
|                     InventoryCollection Collection = new InventoryCollection(); | ||||
|                     Collection.OwnerID = f.owner_id; | ||||
|                     Collection.Version = 0; | ||||
|                     Collection.FolderID = f.folder_id; | ||||
|                     Collection.Descendents = 0; | ||||
|                     result.Add(Collection); | ||||
|                     continue; | ||||
|                 } | ||||
|                 if(dolib && f.owner_id == libOwner) | ||||
|                 { | ||||
|                     if(libIDs.Contains(f.folder_id)) | ||||
|                         continue; | ||||
|                     libIDs.Add(f.folder_id); | ||||
|                     libFolders.Add(f); | ||||
|                     continue; | ||||
|                 } | ||||
|                 if(otherIDs.Contains(f.folder_id)) | ||||
|                     continue; | ||||
| 
 | ||||
|                 otherIDs.Add(f.folder_id); | ||||
|                 otherFolders.Add(f); | ||||
|             } | ||||
| 
 | ||||
|             fetchFolders.Clear(); | ||||
| 
 | ||||
|             if(otherFolders.Count > 0) | ||||
|             {  | ||||
|                 int i = 0; | ||||
| 
 | ||||
|                 //m_log.DebugFormat("[XXX]: {0}", string.Join(",", fids)); | ||||
| 
 | ||||
|                 InventoryCollection[] fetchedContents = m_InventoryService.GetMultipleFoldersContent(otherFolders[0].owner_id, otherIDs.ToArray()); | ||||
| 
 | ||||
|                 if (fetchedContents == null) | ||||
|                      return null; | ||||
|   | ||||
|                 if (fetchedContents.Length == 0) | ||||
|                 { | ||||
|                     foreach (LLSDFetchInventoryDescendents freq in otherFolders) | ||||
|                         BadFolder(freq, null, bad_folders); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     i = 0; | ||||
|                     // Do some post-processing. May need to fetch more from inv server for links | ||||
|                     foreach (InventoryCollection contents in fetchedContents) | ||||
|                     { | ||||
|                         // Find the original request | ||||
|                         LLSDFetchInventoryDescendents freq = otherFolders[i]; | ||||
|                         otherFolders[i]=null; | ||||
|                         i++; | ||||
| 
 | ||||
|                         if (BadFolder(freq, contents, bad_folders)) | ||||
|                             continue; | ||||
| 
 | ||||
|                         if(!freq.fetch_folders) | ||||
|                             contents.Folders.Clear(); | ||||
|                         if(!freq.fetch_items) | ||||
|                             contents.Items.Clear(); | ||||
| 
 | ||||
|                         contents.Descendents = contents.Items.Count + contents.Folders.Count; | ||||
|   | ||||
|                         // Next: link management | ||||
|                         ProcessLinks(freq, contents); | ||||
| 
 | ||||
|                         total_folders += contents.Folders.Count; | ||||
|                         total_items += contents.Items.Count; | ||||
|                         result.Add(contents); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if(dolib && libFolders.Count > 0) | ||||
|             { | ||||
|                 AddLibraryFolders(libFolders, result, ref total_folders, ref total_items);            | ||||
|             } | ||||
| 
 | ||||
|             return result; | ||||
|         } | ||||
| 
 | ||||
|         private bool BadFolder(LLSDFetchInventoryDescendents freq, InventoryCollection contents, List<UUID> bad_folders) | ||||
|         { | ||||
|             if (contents == null) | ||||
|             { | ||||
|                 bad_folders.Add(freq.folder_id); | ||||
|                 return true; | ||||
|             } | ||||
| 
 | ||||
|             // The inventory server isn't sending FolderID in the collection... | ||||
|             // Must fetch it individually | ||||
|             if (contents.FolderID == UUID.Zero) | ||||
|             { | ||||
|                 InventoryFolderBase containingFolder = m_InventoryService.GetFolder(freq.owner_id, freq.folder_id); | ||||
|                 if (containingFolder == null) | ||||
|                 { | ||||
|                     m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Unable to fetch folder {0}", freq.folder_id); | ||||
|                     bad_folders.Add(freq.folder_id); | ||||
|                     return true; | ||||
|                 } | ||||
|                 contents.FolderID = containingFolder.ID; | ||||
|                 contents.OwnerID = containingFolder.Owner; | ||||
|                 contents.Version = containingFolder.Version; | ||||
|             } | ||||
| 
 | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         private void ProcessLinks(LLSDFetchInventoryDescendents freq, InventoryCollection contents) | ||||
|         { | ||||
|             if (contents.Items == null || contents.Items.Count == 0) | ||||
|                 return; | ||||
| 
 | ||||
|             // viewers are lasy and want a copy of the linked item sent before the link to it | ||||
| 
 | ||||
|             // look for item links | ||||
|             List<UUID> itemIDs = new List<UUID>(); | ||||
|             foreach (InventoryItemBase item in contents.Items) | ||||
|             { | ||||
|                 //m_log.DebugFormat("[XXX]:   {0} {1}", item.Name, item.AssetType); | ||||
|                 if (item.AssetType == (int)AssetType.Link) | ||||
|                     itemIDs.Add(item.AssetID); | ||||
|             } | ||||
| 
 | ||||
|             // get the linked if any | ||||
|             if (itemIDs.Count > 0) | ||||
|             { | ||||
|                 InventoryItemBase[] linked = m_InventoryService.GetMultipleItems(freq.owner_id, itemIDs.ToArray()); | ||||
|                      | ||||
|                 if (linked != null) | ||||
|                 { | ||||
|                     List<InventoryItemBase> linkedItems = new List<InventoryItemBase>(linked.Length); | ||||
|                     // check for broken | ||||
|                     foreach (InventoryItemBase linkedItem in linked) | ||||
|                     { | ||||
|                         // Take care of genuinely broken links where the target doesn't exist | ||||
|                         // HACK: Also, don't follow up links that just point to other links.  In theory this is legitimate, | ||||
|                         // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles | ||||
|                         // rather than having to keep track of every folder requested in the recursion. | ||||
|                         if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link) | ||||
|                         { | ||||
|                             linkedItems.Add(linkedItem); | ||||
|                             //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Added {0} {1} {2}", linkedItem.Name, linkedItem.AssetType, linkedItem.Folder); | ||||
|                         } | ||||
|                     } | ||||
|                     // insert them | ||||
|                     if(linkedItems.Count > 0) | ||||
|                         contents.Items.InsertRange(0, linkedItems); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -1,166 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System.Net; | ||||
| using System.Reflection; | ||||
| using System.Text; | ||||
| using OpenMetaverse; | ||||
| using OpenMetaverse.StructuredData; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Services.Interfaces; | ||||
| using OSDArray = OpenMetaverse.StructuredData.OSDArray; | ||||
| using OSDMap = OpenMetaverse.StructuredData.OSDMap; | ||||
| 
 | ||||
| using log4net; | ||||
| 
 | ||||
| namespace OpenSim.Capabilities.Handlers | ||||
| { | ||||
|     public class FetchInventory2Handler | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private IInventoryService m_inventoryService; | ||||
|         private UUID m_agentID; | ||||
| 
 | ||||
|         public FetchInventory2Handler(IInventoryService invService, UUID agentId) | ||||
|         { | ||||
|             m_inventoryService = invService; | ||||
|             m_agentID = agentId; | ||||
|         } | ||||
| 
 | ||||
|         public string FetchInventoryRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||||
|         { | ||||
|             //m_log.DebugFormat("[FETCH INVENTORY HANDLER]: Received FetchInventory capability request {0}", request); | ||||
| 
 | ||||
|             OSDMap requestmap = (OSDMap)OSDParser.DeserializeLLSDXml(Utils.StringToBytes(request)); | ||||
|             OSDArray itemsRequested = (OSDArray)requestmap["items"]; | ||||
| 
 | ||||
|             UUID[] itemIDs = new UUID[itemsRequested.Count]; | ||||
|             int i = 0; | ||||
| 
 | ||||
|             foreach (OSDMap osdItemId in itemsRequested) | ||||
|             { | ||||
|                 itemIDs[i++] = osdItemId["item_id"].AsUUID(); | ||||
|             } | ||||
| 
 | ||||
|             InventoryItemBase[] items = null; | ||||
| 
 | ||||
|             if (m_agentID != UUID.Zero) | ||||
|             { | ||||
|                 items = m_inventoryService.GetMultipleItems(m_agentID, itemIDs); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 items = new InventoryItemBase[itemsRequested.Count]; | ||||
|                 foreach (UUID id in itemIDs) | ||||
|                     items[i++] = m_inventoryService.GetItem(UUID.Zero, id); | ||||
|             } | ||||
| 
 | ||||
|             StringBuilder lsl = LLSDxmlEncode.Start(4096); | ||||
|             LLSDxmlEncode.AddMap(lsl); | ||||
| 
 | ||||
|             if(m_agentID == UUID.Zero && items.Length > 0) | ||||
|                 LLSDxmlEncode.AddElem("agent_id", items[0].Owner, lsl); | ||||
|             else | ||||
|                 LLSDxmlEncode.AddElem("agent_id", m_agentID, lsl); | ||||
| 
 | ||||
|             if(items == null || items.Length == 0) | ||||
|             { | ||||
|                 LLSDxmlEncode.AddEmptyArray("items", lsl); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 LLSDxmlEncode.AddArray("items", lsl); | ||||
|                 foreach (InventoryItemBase item in items) | ||||
|                 { | ||||
|                     if (item != null) | ||||
|                         item.ToLLSDxml(lsl, 0xff); | ||||
|                 } | ||||
|                 LLSDxmlEncode.AddEndArray(lsl); | ||||
|             }             | ||||
| 
 | ||||
|             LLSDxmlEncode.AddEndMap(lsl); | ||||
|             return LLSDxmlEncode.End(lsl); | ||||
|         } | ||||
| 
 | ||||
|         public void FetchInventorySimpleRequest(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, OSDMap requestmap, ExpiringKey<UUID> BadRequests) | ||||
|         { | ||||
|             //m_log.DebugFormat("[FETCH INVENTORY HANDLER]: Received FetchInventory capability request {0}", request); | ||||
| 
 | ||||
|             if(BadRequests == null) | ||||
|             { | ||||
|                 httpResponse.StatusCode = (int)HttpStatusCode.NotFound; | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             OSDArray itemsRequested = (OSDArray)requestmap["items"]; | ||||
| 
 | ||||
|             UUID[] itemIDs = new UUID[itemsRequested.Count]; | ||||
|             int i = 0; | ||||
|             foreach (OSDMap osdItemId in itemsRequested) | ||||
|             { | ||||
|                 UUID id = osdItemId["item_id"].AsUUID(); | ||||
|                 if(!BadRequests.ContainsKey(id)) | ||||
|                     itemIDs[i++] = id; | ||||
|             } | ||||
| 
 | ||||
|             InventoryItemBase[] items = null; | ||||
|             try | ||||
|             { | ||||
|                 // badrequests still not filled | ||||
|                 items = m_inventoryService.GetMultipleItems(m_agentID, itemIDs); | ||||
|             } | ||||
|             catch{ } | ||||
| 
 | ||||
|             StringBuilder lsl = LLSDxmlEncode.Start(4096); | ||||
|             LLSDxmlEncode.AddMap(lsl); | ||||
| 
 | ||||
|             LLSDxmlEncode.AddElem("agent_id", m_agentID, lsl); | ||||
| 
 | ||||
|             if (items == null || items.Length == 0) | ||||
|             { | ||||
|                 LLSDxmlEncode.AddEmptyArray("items", lsl); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 LLSDxmlEncode.AddArray("items", lsl); | ||||
|                 foreach (InventoryItemBase item in items) | ||||
|                 { | ||||
|                     if (item != null) | ||||
|                         item.ToLLSDxml(lsl, 0xff); | ||||
|                 } | ||||
|                 LLSDxmlEncode.AddEndArray(lsl); | ||||
|             } | ||||
| 
 | ||||
|             LLSDxmlEncode.AddEndMap(lsl); | ||||
|             httpResponse.RawBuffer = Util.UTF8.GetBytes(LLSDxmlEncode.End(lsl)); | ||||
|             httpResponse.StatusCode = (int)HttpStatusCode.OK; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -1,170 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Net; | ||||
| using System.Text.RegularExpressions; | ||||
| using log4net; | ||||
| using log4net.Config; | ||||
| using NUnit.Framework; | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Capabilities.Handlers; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Region.Framework.Scenes; | ||||
| using OpenSim.Services.Interfaces; | ||||
| using OpenSim.Tests.Common; | ||||
| 
 | ||||
| namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests | ||||
| { | ||||
|     [TestFixture] | ||||
|     public class FetchInventory2HandlerTests : OpenSimTestCase | ||||
|     { | ||||
|         private UUID m_userID = UUID.Random(); | ||||
|         private Scene m_scene; | ||||
|         private UUID m_rootFolderID; | ||||
|         private UUID m_notecardsFolder; | ||||
|         private UUID m_objectsFolder; | ||||
| 
 | ||||
|         private void Init() | ||||
|         { | ||||
|             // Create an inventory that looks like this: | ||||
|             // | ||||
|             // /My Inventory | ||||
|             //   <other system folders> | ||||
|             //   /Objects | ||||
|             //      Object 1 | ||||
|             //      Object 2 | ||||
|             //      Object 3 | ||||
|             //   /Notecards | ||||
|             //      Notecard 1 | ||||
|             //      Notecard 2 | ||||
|             //      Notecard 3 | ||||
|             //      Notecard 4 | ||||
|             //      Notecard 5 | ||||
| 
 | ||||
|             m_scene = new SceneHelpers().SetupScene(); | ||||
| 
 | ||||
|             m_scene.InventoryService.CreateUserInventory(m_userID); | ||||
| 
 | ||||
|             m_rootFolderID = m_scene.InventoryService.GetRootFolder(m_userID).ID; | ||||
| 
 | ||||
|             InventoryFolderBase of = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Object); | ||||
|             m_objectsFolder = of.ID; | ||||
| 
 | ||||
|             // Add 3 objects | ||||
|             InventoryItemBase item; | ||||
|             for (int i = 1; i <= 3; i++) | ||||
|             { | ||||
|                 item = new InventoryItemBase(new UUID("b0000000-0000-0000-0000-0000000000b" + i), m_userID); | ||||
|                 item.AssetID = UUID.Random(); | ||||
|                 item.AssetType = (int)AssetType.Object; | ||||
|                 item.Folder = m_objectsFolder; | ||||
|                 item.Name = "Object " + i; | ||||
|                 m_scene.InventoryService.AddItem(item); | ||||
|             } | ||||
| 
 | ||||
|             InventoryFolderBase ncf = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Notecard); | ||||
|             m_notecardsFolder = ncf.ID; | ||||
| 
 | ||||
|             // Add 5 notecards | ||||
|             for (int i = 1; i <= 5; i++) | ||||
|             { | ||||
|                 item = new InventoryItemBase(new UUID("10000000-0000-0000-0000-00000000000" + i), m_userID); | ||||
|                 item.AssetID = UUID.Random(); | ||||
|                 item.AssetType = (int)AssetType.Notecard; | ||||
|                 item.Folder = m_notecardsFolder; | ||||
|                 item.Name = "Notecard " + i; | ||||
|                 m_scene.InventoryService.AddItem(item); | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void Test_001_RequestOne() | ||||
|         { | ||||
|             TestHelpers.InMethod(); | ||||
| 
 | ||||
|             Init(); | ||||
| 
 | ||||
|             FetchInventory2Handler handler = new FetchInventory2Handler(m_scene.InventoryService, m_userID); | ||||
|             TestOSHttpRequest req = new TestOSHttpRequest(); | ||||
|             TestOSHttpResponse resp = new TestOSHttpResponse(); | ||||
| 
 | ||||
|             string request = "<llsd><map><key>items</key><array><map><key>item_id</key><uuid>"; | ||||
|             request += "10000000-0000-0000-0000-000000000001"; // Notecard 1 | ||||
|             request += "</uuid></map></array></map></llsd>"; | ||||
| 
 | ||||
|             string llsdresponse = handler.FetchInventoryRequest(request, "/FETCH", string.Empty, req, resp); | ||||
| 
 | ||||
|             Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); | ||||
|             Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response"); | ||||
|             Assert.That(llsdresponse.Contains(m_userID.ToString()), Is.True, "Response should contain userID"); | ||||
| 
 | ||||
|             Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000001"), Is.True, "Response does not contain item uuid"); | ||||
|             Assert.That(llsdresponse.Contains("Notecard 1"), Is.True, "Response does not contain item Name"); | ||||
|             Console.WriteLine(llsdresponse); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void Test_002_RequestMany() | ||||
|         { | ||||
|             TestHelpers.InMethod(); | ||||
| 
 | ||||
|             Init(); | ||||
| 
 | ||||
|             FetchInventory2Handler handler = new FetchInventory2Handler(m_scene.InventoryService, m_userID); | ||||
|             TestOSHttpRequest req = new TestOSHttpRequest(); | ||||
|             TestOSHttpResponse resp = new TestOSHttpResponse(); | ||||
| 
 | ||||
|             string request = "<llsd><map><key>items</key><array>"; | ||||
|             request += "<map><key>item_id</key><uuid>10000000-0000-0000-0000-000000000001</uuid></map>"; // Notecard 1 | ||||
|             request += "<map><key>item_id</key><uuid>10000000-0000-0000-0000-000000000002</uuid></map>"; // Notecard 2 | ||||
|             request += "<map><key>item_id</key><uuid>10000000-0000-0000-0000-000000000003</uuid></map>"; // Notecard 3 | ||||
|             request += "<map><key>item_id</key><uuid>10000000-0000-0000-0000-000000000004</uuid></map>"; // Notecard 4 | ||||
|             request += "<map><key>item_id</key><uuid>10000000-0000-0000-0000-000000000005</uuid></map>"; // Notecard 5 | ||||
|             request += "</array></map></llsd>"; | ||||
| 
 | ||||
|             string llsdresponse = handler.FetchInventoryRequest(request, "/FETCH", string.Empty, req, resp); | ||||
| 
 | ||||
|             Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); | ||||
|             Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response"); | ||||
|             Assert.That(llsdresponse.Contains(m_userID.ToString()), Is.True, "Response should contain userID"); | ||||
| 
 | ||||
|             Console.WriteLine(llsdresponse); | ||||
|             Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000001"), Is.True, "Response does not contain notecard 1"); | ||||
|             Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000002"), Is.True, "Response does not contain notecard 2"); | ||||
|             Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000003"), Is.True, "Response does not contain notecard 3"); | ||||
|             Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000004"), Is.True, "Response does not contain notecard 4"); | ||||
|             Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000005"), Is.True, "Response does not contain notecard 5"); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -1,300 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.IO; | ||||
| using System.Text.RegularExpressions; | ||||
| using log4net; | ||||
| using log4net.Config; | ||||
| using NUnit.Framework; | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Capabilities.Handlers; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Region.Framework.Scenes; | ||||
| using OpenSim.Services.Interfaces; | ||||
| using OpenSim.Tests.Common; | ||||
| 
 | ||||
| namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests | ||||
| { | ||||
|     [TestFixture] | ||||
|     public class FetchInventoryDescendents2HandlerTests : OpenSimTestCase | ||||
|     { | ||||
|         private UUID m_userID = new UUID("00000000-0000-0000-0000-000000000001"); | ||||
|         private Scene m_scene; | ||||
|         private UUID m_rootFolderID; | ||||
|         private int m_rootDescendents; | ||||
|         private UUID m_notecardsFolder; | ||||
|         private UUID m_objectsFolder; | ||||
| 
 | ||||
|         private void Init() | ||||
|         { | ||||
|             // Create an inventory that looks like this: | ||||
|             // | ||||
|             // /My Inventory | ||||
|             //   <other system folders> | ||||
|             //   /Objects | ||||
|             //      Some Object | ||||
|             //   /Notecards | ||||
|             //      Notecard 1 | ||||
|             //      Notecard 2 | ||||
|             //   /Test Folder | ||||
|             //      Link to notecard  -> /Notecards/Notecard 2 | ||||
|             //      Link to Objects folder -> /Objects | ||||
| 
 | ||||
|             m_scene = new SceneHelpers().SetupScene(); | ||||
| 
 | ||||
|             m_scene.InventoryService.CreateUserInventory(m_userID); | ||||
| 
 | ||||
|             m_rootFolderID = m_scene.InventoryService.GetRootFolder(m_userID).ID; | ||||
| 
 | ||||
|             InventoryFolderBase of = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Object); | ||||
|             m_objectsFolder = of.ID; | ||||
| 
 | ||||
|             // Add an object | ||||
|             InventoryItemBase item = new InventoryItemBase(new UUID("b0000000-0000-0000-0000-00000000000b"), m_userID); | ||||
|             item.AssetID = UUID.Random(); | ||||
|             item.AssetType = (int)AssetType.Object; | ||||
|             item.Folder = m_objectsFolder; | ||||
|             item.Name = "Some Object"; | ||||
|             m_scene.InventoryService.AddItem(item); | ||||
| 
 | ||||
|             InventoryFolderBase ncf = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Notecard); | ||||
|             m_notecardsFolder = ncf.ID; | ||||
| 
 | ||||
|             // Add a notecard | ||||
|             item = new InventoryItemBase(new UUID("10000000-0000-0000-0000-000000000001"), m_userID); | ||||
|             item.AssetID = UUID.Random(); | ||||
|             item.AssetType = (int)AssetType.Notecard; | ||||
|             item.Folder = m_notecardsFolder; | ||||
|             item.Name = "Test Notecard 1"; | ||||
|             m_scene.InventoryService.AddItem(item); | ||||
|             // Add another notecard | ||||
|             item.ID = new UUID("20000000-0000-0000-0000-000000000002"); | ||||
|             item.AssetID = new UUID("a0000000-0000-0000-0000-00000000000a"); | ||||
|             item.Name = "Test Notecard 2"; | ||||
|             m_scene.InventoryService.AddItem(item); | ||||
| 
 | ||||
|             // Add a folder | ||||
|             InventoryFolderBase folder = new InventoryFolderBase(new UUID("f0000000-0000-0000-0000-00000000000f"), "Test Folder", m_userID, m_rootFolderID); | ||||
|             folder.Type = (short)FolderType.None; | ||||
|             m_scene.InventoryService.AddFolder(folder); | ||||
| 
 | ||||
|             // Add a link to notecard 2 in Test Folder | ||||
|             item.AssetID = item.ID; // use item ID of notecard 2 | ||||
|             item.ID = new UUID("40000000-0000-0000-0000-000000000004"); | ||||
|             item.AssetType = (int)AssetType.Link; | ||||
|             item.Folder = folder.ID; | ||||
|             item.Name = "Link to notecard"; | ||||
|             m_scene.InventoryService.AddItem(item); | ||||
| 
 | ||||
|             // Add a link to the Objects folder in Test Folder | ||||
|             item.AssetID = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Object).ID; // use item ID of Objects folder | ||||
|             item.ID = new UUID("50000000-0000-0000-0000-000000000005"); | ||||
|             item.AssetType = (int)AssetType.LinkFolder; | ||||
|             item.Folder = folder.ID; | ||||
|             item.Name = "Link to Objects folder"; | ||||
|             m_scene.InventoryService.AddItem(item); | ||||
| 
 | ||||
|             InventoryCollection coll = m_scene.InventoryService.GetFolderContent(m_userID, m_rootFolderID); | ||||
|             m_rootDescendents = coll.Items.Count + coll.Folders.Count; | ||||
|             Console.WriteLine("Number of descendents: " + m_rootDescendents); | ||||
|         } | ||||
| 
 | ||||
|         private string dorequest(FetchInvDescHandler handler, string request) | ||||
|         { | ||||
|             TestOSHttpRequest req = new TestOSHttpRequest(); | ||||
|             TestOSHttpResponse resp = new TestOSHttpResponse(); | ||||
|             using(ExpiringKey<UUID> bad = new ExpiringKey<UUID>(5000)) // bad but this is test | ||||
|             using (MemoryStream ms = new MemoryStream(Utils.StringToBytes(request), false)) | ||||
|             { | ||||
|                 req.InputStream = ms; | ||||
|                 handler.FetchInventoryDescendentsRequest(req, resp, bad); | ||||
|             } | ||||
|             return Util.UTF8.GetString(resp.RawBuffer); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void Test_001_SimpleFolder() | ||||
|         { | ||||
|             TestHelpers.InMethod(); | ||||
| 
 | ||||
|             Init(); | ||||
| 
 | ||||
|             FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene); | ||||
| 
 | ||||
|             string request = "<llsd><map><key>folders</key><array><map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>"; | ||||
|             request += m_rootFolderID; | ||||
|             request += "</uuid><key>owner_id</key><uuid>"; | ||||
|             request += m_userID.ToString(); | ||||
|             request += "</uuid><key>sort_order</key><integer>1</integer></map></array></map></llsd>"; | ||||
| 
 | ||||
|             string llsdresponse = dorequest(handler, request); | ||||
| 
 | ||||
|             Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); | ||||
|             Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response"); | ||||
|             Assert.That(llsdresponse.Contains(m_userID.ToString()), Is.True, "Response should contain userID"); | ||||
| 
 | ||||
|             string descendents = "descendents</key><integer>" + m_rootDescendents + "</integer>"; | ||||
|             Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents"); | ||||
|             Console.WriteLine(llsdresponse); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void Test_002_MultipleFolders() | ||||
|         { | ||||
|             TestHelpers.InMethod(); | ||||
| 
 | ||||
|             FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene); | ||||
| 
 | ||||
|             string request = "<llsd><map><key>folders</key><array>"; | ||||
|             request += "<map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>"; | ||||
|             request += m_rootFolderID; | ||||
|             request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000001</uuid><key>sort_order</key><integer>1</integer></map>"; | ||||
|             request += "<map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>"; | ||||
|             request += m_notecardsFolder; | ||||
|             request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000001</uuid><key>sort_order</key><integer>1</integer></map>"; | ||||
|             request += "</array></map></llsd>"; | ||||
| 
 | ||||
|             string llsdresponse = dorequest(handler, request); | ||||
|             Console.WriteLine(llsdresponse); | ||||
| 
 | ||||
|             string descendents = "descendents</key><integer>" + m_rootDescendents + "</integer>"; | ||||
|             Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents for root folder"); | ||||
|             descendents = "descendents</key><integer>2</integer>"; | ||||
|             Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents for Notecard folder"); | ||||
| 
 | ||||
|             Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000001"), Is.True, "Notecard 1 is missing from response"); | ||||
|             Assert.That(llsdresponse.Contains("20000000-0000-0000-0000-000000000002"), Is.True, "Notecard 2 is missing from response"); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void Test_003_Links() | ||||
|         { | ||||
|             TestHelpers.InMethod(); | ||||
| 
 | ||||
|             FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene); | ||||
| 
 | ||||
|             string request = "<llsd><map><key>folders</key><array><map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>"; | ||||
|             request += "f0000000-0000-0000-0000-00000000000f"; | ||||
|             request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000001</uuid><key>sort_order</key><integer>1</integer></map></array></map></llsd>"; | ||||
| 
 | ||||
|             string llsdresponse = dorequest(handler, request); | ||||
|             Console.WriteLine(llsdresponse); | ||||
| 
 | ||||
|             string descendents = "descendents</key><integer>2</integer>"; | ||||
|             Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents for Test Folder"); | ||||
| 
 | ||||
|             // Make sure that the note card link is included | ||||
|             Assert.That(llsdresponse.Contains("Link to notecard"), Is.True, "Link to notecard is missing"); | ||||
| 
 | ||||
|             //Make sure the notecard item itself is included | ||||
|             Assert.That(llsdresponse.Contains("Test Notecard 2"), Is.True, "Notecard 2 item (the source) is missing"); | ||||
| 
 | ||||
|             // Make sure that the source item is before the link item | ||||
|             int pos1 = llsdresponse.IndexOf("Test Notecard 2"); | ||||
|             int pos2 = llsdresponse.IndexOf("Link to notecard"); | ||||
|             Assert.Less(pos1, pos2, "Source of link is after link"); | ||||
| 
 | ||||
|             // Make sure the folder link is included | ||||
|             Assert.That(llsdresponse.Contains("Link to Objects folder"), Is.True, "Link to Objects folder is missing"); | ||||
| 
 | ||||
| /* contents of link folder are not supposed to be listed | ||||
|             // Make sure the objects inside the Objects folder are included | ||||
|             // Note: I'm not entirely sure this is needed, but that's what I found in the implementation | ||||
|             Assert.That(llsdresponse.Contains("Some Object"), Is.True, "Some Object item (contents of the source) is missing"); | ||||
| */ | ||||
|             // Make sure that the source item is before the link item | ||||
|             pos1 = llsdresponse.IndexOf("Some Object"); | ||||
|             pos2 = llsdresponse.IndexOf("Link to Objects folder"); | ||||
|             Assert.Less(pos1, pos2, "Contents of source of folder link is after folder link"); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void Test_004_DuplicateFolders() | ||||
|         { | ||||
|             TestHelpers.InMethod(); | ||||
| 
 | ||||
|             FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene); | ||||
| 
 | ||||
|             string request = "<llsd><map><key>folders</key><array>"; | ||||
|             request += "<map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>"; | ||||
|             request += m_rootFolderID; | ||||
|             request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000000</uuid><key>sort_order</key><integer>1</integer></map>"; | ||||
|             request += "<map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>"; | ||||
|             request += m_notecardsFolder; | ||||
|             request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000000</uuid><key>sort_order</key><integer>1</integer></map>"; | ||||
|             request += "<map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>"; | ||||
|             request += m_rootFolderID; | ||||
|             request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000000</uuid><key>sort_order</key><integer>1</integer></map>"; | ||||
|             request += "<map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>"; | ||||
|             request += m_notecardsFolder; | ||||
|             request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000000</uuid><key>sort_order</key><integer>1</integer></map>"; | ||||
|             request += "</array></map></llsd>"; | ||||
| 
 | ||||
|             string llsdresponse = dorequest(handler, request); | ||||
|             Console.WriteLine(llsdresponse); | ||||
| 
 | ||||
|             string root_folder = "<key>folder_id</key><uuid>" + m_rootFolderID + "</uuid>"; | ||||
|             string notecards_folder = "<key>folder_id</key><uuid>" + m_notecardsFolder + "</uuid>"; | ||||
| 
 | ||||
|             Assert.That(llsdresponse.Contains(root_folder), "Missing root folder"); | ||||
|             Assert.That(llsdresponse.Contains(notecards_folder), "Missing notecards folder"); | ||||
|             int count = Regex.Matches(llsdresponse, root_folder).Count; | ||||
|             Assert.AreEqual(1, count, "More than 1 root folder in response"); | ||||
|             count = Regex.Matches(llsdresponse, notecards_folder).Count; | ||||
|             Assert.AreEqual(2, count, "More than 1 notecards folder in response"); // Notecards will also be under root, so 2 | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|         public void Test_005_FolderZero() | ||||
|         { | ||||
| 
 | ||||
|             TestHelpers.InMethod(); | ||||
| 
 | ||||
|             Init(); | ||||
| 
 | ||||
|             FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene); | ||||
| 
 | ||||
|             string request = "<llsd><map><key>folders</key><array><map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>"; | ||||
|             request += UUID.Zero; | ||||
|             request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000000</uuid><key>sort_order</key><integer>1</integer></map></array></map></llsd>"; | ||||
| 
 | ||||
|             string llsdresponse = dorequest(handler, request); | ||||
| 
 | ||||
|             Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); | ||||
|             Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response"); | ||||
|             // we do return a answer now | ||||
|             //Assert.That(llsdresponse.Contains("bad_folders</key><array><uuid>00000000-0000-0000-0000-000000000000"), Is.True, "Folder Zero should be a bad folder"); | ||||
| 
 | ||||
|             Console.WriteLine(llsdresponse); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,148 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| using System.Reflection; | ||||
| using log4net; | ||||
| using Nini.Config; | ||||
| using OpenMetaverse; | ||||
| using OpenMetaverse.StructuredData; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Capabilities; | ||||
| using OpenSim.Region.Framework.Interfaces; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Services.Interfaces; | ||||
| using Caps = OpenSim.Framework.Capabilities.Caps; | ||||
| using OSDArray = OpenMetaverse.StructuredData.OSDArray; | ||||
| using OSDMap = OpenMetaverse.StructuredData.OSDMap; | ||||
| 
 | ||||
| namespace OpenSim.Capabilities.Handlers | ||||
| { | ||||
|     public class FetchInventory2Handler | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private IInventoryService m_inventoryService; | ||||
| 
 | ||||
|         public FetchInventory2Handler(IInventoryService invService) | ||||
|         { | ||||
|             m_inventoryService = invService; | ||||
|         } | ||||
| 
 | ||||
|         public string FetchInventoryRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||||
|         { | ||||
| //            m_log.DebugFormat("[FETCH INVENTORY HANDLER]: Received FetchInventory capabilty request"); | ||||
| 
 | ||||
|             OSDMap requestmap = (OSDMap)OSDParser.DeserializeLLSDXml(Utils.StringToBytes(request)); | ||||
|             OSDArray itemsRequested = (OSDArray)requestmap["items"]; | ||||
| 
 | ||||
|             string reply; | ||||
|             LLSDFetchInventory llsdReply = new LLSDFetchInventory(); | ||||
| 
 | ||||
|             foreach (OSDMap osdItemId in itemsRequested) | ||||
|             { | ||||
|                 UUID itemId = osdItemId["item_id"].AsUUID(); | ||||
| 
 | ||||
|                 InventoryItemBase item = m_inventoryService.GetItem(new InventoryItemBase(itemId)); | ||||
| 
 | ||||
|                 if (item != null) | ||||
|                 { | ||||
|                     // We don't know the agent that this request belongs to so we'll use the agent id of the item | ||||
|                     // which will be the same for all items. | ||||
|                     llsdReply.agent_id = item.Owner; | ||||
| 
 | ||||
|                     llsdReply.items.Array.Add(ConvertInventoryItem(item)); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             reply = LLSDHelpers.SerialiseLLSDReply(llsdReply); | ||||
| 
 | ||||
|             return reply; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Convert an internal inventory item object into an LLSD object. | ||||
|         /// </summary> | ||||
|         /// <param name="invItem"></param> | ||||
|         /// <returns></returns> | ||||
|         private LLSDInventoryItem ConvertInventoryItem(InventoryItemBase invItem) | ||||
|         { | ||||
|             LLSDInventoryItem llsdItem = new LLSDInventoryItem(); | ||||
|             llsdItem.asset_id = invItem.AssetID; | ||||
|             llsdItem.created_at = invItem.CreationDate; | ||||
|             llsdItem.desc = invItem.Description; | ||||
|             llsdItem.flags = (int)invItem.Flags; | ||||
|             llsdItem.item_id = invItem.ID; | ||||
|             llsdItem.name = invItem.Name; | ||||
|             llsdItem.parent_id = invItem.Folder; | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 llsdItem.type = Utils.AssetTypeToString((AssetType)invItem.AssetType); | ||||
|                 llsdItem.inv_type = Utils.InventoryTypeToString((InventoryType)invItem.InvType); | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 m_log.ErrorFormat( | ||||
|                     "[WEB FETCH INV DESC HANDLER]: Problem setting asset {0} inventory {1} types while converting inventory item {2}: {3}", | ||||
|                     invItem.AssetType, invItem.InvType, invItem.Name, e.Message); | ||||
|             } | ||||
| 
 | ||||
|             llsdItem.permissions = new LLSDPermissions(); | ||||
|             llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid; | ||||
|             llsdItem.permissions.base_mask = (int)invItem.CurrentPermissions; | ||||
|             llsdItem.permissions.everyone_mask = (int)invItem.EveryOnePermissions; | ||||
|             llsdItem.permissions.group_id = invItem.GroupID; | ||||
|             llsdItem.permissions.group_mask = (int)invItem.GroupPermissions; | ||||
|             llsdItem.permissions.is_owner_group = invItem.GroupOwned; | ||||
|             llsdItem.permissions.next_owner_mask = (int)invItem.NextPermissions; | ||||
|             llsdItem.permissions.owner_id = invItem.Owner; | ||||
|             llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions; | ||||
|             llsdItem.sale_info = new LLSDSaleInfo(); | ||||
|             llsdItem.sale_info.sale_price = invItem.SalePrice; | ||||
|             switch (invItem.SaleType) | ||||
|             { | ||||
|                 default: | ||||
|                     llsdItem.sale_info.sale_type = "not"; | ||||
|                     break; | ||||
|                 case 1: | ||||
|                     llsdItem.sale_info.sale_type = "original"; | ||||
|                     break; | ||||
|                 case 2: | ||||
|                     llsdItem.sale_info.sale_type = "copy"; | ||||
|                     break; | ||||
|                 case 3: | ||||
|                     llsdItem.sale_info.sale_type = "contents"; | ||||
|                     break; | ||||
|             } | ||||
| 
 | ||||
|             return llsdItem; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -61,10 +61,9 @@ namespace OpenSim.Capabilities.Handlers | |||
|             if (m_InventoryService == null) | ||||
|                 throw new Exception(String.Format("Failed to load InventoryService from {0}; config is {1}", invService, m_ConfigName)); | ||||
| 
 | ||||
|             FetchInventory2Handler fiHandler = new FetchInventory2Handler(m_InventoryService, UUID.Zero); | ||||
|             FetchInventory2Handler fiHandler = new FetchInventory2Handler(m_InventoryService); | ||||
|             IRequestHandler reqHandler | ||||
|                 = new RestStreamHandler( | ||||
|                     "POST", "/CAPS/FetchInventory/", fiHandler.FetchInventoryRequest, "FetchInventory", null); | ||||
|                 = new RestStreamHandler("POST", "/CAPS/FetchInventory/", fiHandler.FetchInventoryRequest); | ||||
|             server.AddStreamHandler(reqHandler); | ||||
|         } | ||||
|     } | ||||
|  | @ -1,190 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| using System.Net; | ||||
| using System.Reflection; | ||||
| using log4net; | ||||
| using Nini.Config; | ||||
| using OpenMetaverse; | ||||
| using OpenMetaverse.StructuredData; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Servers; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Services.Interfaces; | ||||
| using Caps = OpenSim.Framework.Capabilities.Caps; | ||||
| 
 | ||||
| namespace OpenSim.Capabilities.Handlers | ||||
| { | ||||
|     public class GetAssetsHandler | ||||
|     { | ||||
|         private static readonly ILog m_log = | ||||
|                    LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private static readonly Dictionary<string, AssetType> queryTypes = new Dictionary<string, AssetType>() | ||||
|         { | ||||
|             {"texture_id", AssetType.Texture}, | ||||
|             {"sound_id", AssetType.Sound}, | ||||
|             {"callcard_id", AssetType.CallingCard}, | ||||
|             {"landmark_id", AssetType.Landmark}, | ||||
|             {"script_id", AssetType.LSLText}, | ||||
|             {"clothing_id", AssetType.Clothing}, | ||||
|             {"object_id", AssetType.Object}, | ||||
|             {"notecard_id", AssetType.Notecard}, | ||||
|             {"lsltext_id", AssetType.LSLText}, | ||||
|             {"lslbyte_id", AssetType.LSLBytecode}, | ||||
|             {"txtr_tga_id", AssetType.TextureTGA}, | ||||
|             {"bodypart_id", AssetType.Bodypart}, | ||||
|             {"snd_wav_id", AssetType.SoundWAV}, | ||||
|             {"img_tga_id", AssetType.ImageTGA}, | ||||
|             {"jpeg_id", AssetType.ImageJPEG}, | ||||
|             {"animatn_id", AssetType.Animation}, | ||||
|             {"gesture_id", AssetType.Gesture}, | ||||
|             {"mesh_id", AssetType.Mesh}, | ||||
|             {"settings_id", AssetType.Settings} | ||||
|         }; | ||||
| 
 | ||||
|         private IAssetService m_assetService; | ||||
| 
 | ||||
|         public GetAssetsHandler(IAssetService assService) | ||||
|         { | ||||
|             m_assetService = assService; | ||||
|         } | ||||
| 
 | ||||
|         public void Handle(OSHttpRequest req, OSHttpResponse response) | ||||
|         { | ||||
|             response.ContentType = "text/plain"; | ||||
| 
 | ||||
|             if (m_assetService == null) | ||||
|             { | ||||
|                 response.StatusCode = (int)HttpStatusCode.ServiceUnavailable; | ||||
|                 response.KeepAlive = false; | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             response.StatusCode = (int)HttpStatusCode.BadRequest; | ||||
| 
 | ||||
|             var queries = req.QueryAsDictionary; | ||||
|             if(queries.Count == 0) | ||||
|                 return; | ||||
| 
 | ||||
|             AssetType type = AssetType.Unknown; | ||||
|             string assetStr = string.Empty; | ||||
|             foreach (KeyValuePair<string,string> kvp in queries) | ||||
|             { | ||||
|                 if (queryTypes.ContainsKey(kvp.Key)) | ||||
|                 { | ||||
|                     type = queryTypes[kvp.Key]; | ||||
|                     assetStr = kvp.Value; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if(type == AssetType.Unknown) | ||||
|             { | ||||
|                 //m_log.Warn("[GETASSET]: Unknown type: " + query); | ||||
|                 m_log.Warn("[GETASSET]: Unknown type"); | ||||
|                 response.StatusCode = (int)HttpStatusCode.NotFound; | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (String.IsNullOrEmpty(assetStr)) | ||||
|                 return; | ||||
| 
 | ||||
|             UUID assetID = UUID.Zero; | ||||
|             if(!UUID.TryParse(assetStr, out assetID)) | ||||
|                 return; | ||||
| 
 | ||||
|             AssetBase asset = m_assetService.Get(assetID.ToString()); | ||||
|             if(asset == null) | ||||
|             { | ||||
|                 // m_log.Warn("[GETASSET]: not found: " + query + " " + assetStr); | ||||
|                 response.StatusCode = (int)HttpStatusCode.NotFound; | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (asset.Type != (sbyte)type) | ||||
|                 return; | ||||
| 
 | ||||
|             int len = asset.Data.Length; | ||||
| 
 | ||||
|             string range = null; | ||||
|             if (req.Headers["Range"] != null) | ||||
|                 range = req.Headers["Range"]; | ||||
|             else if (req.Headers["range"] != null) | ||||
|                 range = req.Headers["range"]; | ||||
| 
 | ||||
|             // range request | ||||
|             int start, end; | ||||
|             if (Util.TryParseHttpRange(range, out start, out end)) | ||||
|             { | ||||
|                 // Before clamping start make sure we can satisfy it in order to avoid | ||||
|                 // sending back the last byte instead of an error status | ||||
|                 if (start >= asset.Data.Length) | ||||
|                 { | ||||
|                     response.StatusCode = (int)HttpStatusCode.RequestedRangeNotSatisfiable; | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 if (end == -1) | ||||
|                     end = asset.Data.Length - 1; | ||||
|                 else | ||||
|                     end = Utils.Clamp(end, 0, asset.Data.Length - 1); | ||||
| 
 | ||||
|                 start = Utils.Clamp(start, 0, end); | ||||
|                 len = end - start + 1; | ||||
| 
 | ||||
|                 //m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); | ||||
|                 response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, asset.Data.Length)); | ||||
|                 response.StatusCode = (int)HttpStatusCode.PartialContent; | ||||
|                 response.RawBufferStart = start; | ||||
|             } | ||||
|             else | ||||
|                 response.StatusCode = (int)HttpStatusCode.OK; | ||||
| 
 | ||||
|             response.ContentType = asset.Metadata.ContentType; | ||||
|             response.RawBuffer = asset.Data; | ||||
|             response.RawBufferLen = len; | ||||
|             if (type == AssetType.Mesh || type == AssetType.Texture) | ||||
|             { | ||||
|                 if(len > 8196) | ||||
|                 { | ||||
|                     //if(type == AssetType.Texture && ((asset.Flags & AssetFlags.AvatarBake)!= 0)) | ||||
|                     //    responsedata["prio"] = 1; | ||||
|                     //else | ||||
|                     response.Priority = 2; | ||||
|                 } | ||||
|                 else | ||||
|                     response.Priority = 1; | ||||
|             } | ||||
|             else | ||||
|                 response.Priority = -1; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -43,112 +43,73 @@ using Caps = OpenSim.Framework.Capabilities.Caps; | |||
| 
 | ||||
| namespace OpenSim.Capabilities.Handlers | ||||
| { | ||||
|     public class GetMeshHandler | ||||
|     public class GetMeshHandler  | ||||
|     { | ||||
|         private static readonly ILog m_log = | ||||
|                    LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
| //        private static readonly ILog m_log = | ||||
| //            LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
|          | ||||
|         private IAssetService m_assetService; | ||||
| 
 | ||||
|         public const string DefaultFormat = "vnd.ll.mesh"; | ||||
| 
 | ||||
|         public GetMeshHandler(IAssetService assService) | ||||
|         { | ||||
|             m_assetService = assService; | ||||
|         } | ||||
|         public Hashtable Handle(Hashtable request) | ||||
|         { | ||||
|             return ProcessGetMesh(request, UUID.Zero, null); ; | ||||
|         } | ||||
| 
 | ||||
|         public Hashtable ProcessGetMesh(Hashtable request, UUID AgentId, Caps cap) | ||||
|         { | ||||
|             Hashtable responsedata = new Hashtable(); | ||||
|             if (m_assetService == null) | ||||
|             { | ||||
|                 responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.ServiceUnavailable; | ||||
|                 responsedata["str_response_string"] = "The asset service is unavailable"; | ||||
|                 responsedata["keepalive"] = false; | ||||
|                 return responsedata; | ||||
|             } | ||||
| 
 | ||||
|             responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.BadRequest; | ||||
|             responsedata["int_response_code"] = 400; //501; //410; //404; | ||||
|             responsedata["content_type"] = "text/plain"; | ||||
|             responsedata["int_bytes"] = 0; | ||||
|             responsedata["keepalive"] = false; | ||||
|             responsedata["str_response_string"] = "Request wasn't what was expected"; | ||||
| 
 | ||||
|             string meshStr = string.Empty; | ||||
| 
 | ||||
|             if (request.ContainsKey("mesh_id")) | ||||
|                 meshStr = request["mesh_id"].ToString(); | ||||
| 
 | ||||
|             if (String.IsNullOrEmpty(meshStr)) | ||||
|                 return responsedata; | ||||
| 
 | ||||
|             UUID meshID = UUID.Zero; | ||||
|             if(!UUID.TryParse(meshStr, out meshID)) | ||||
|                 return responsedata; | ||||
| 
 | ||||
|             AssetBase mesh = m_assetService.Get(meshID.ToString()); | ||||
|             if(mesh == null) | ||||
|             if (!String.IsNullOrEmpty(meshStr) && UUID.TryParse(meshStr, out meshID)) | ||||
|             { | ||||
|                 responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound; | ||||
|                 responsedata["str_response_string"] = "Mesh not found."; | ||||
|                 return responsedata; | ||||
|             } | ||||
| 
 | ||||
|             if (mesh.Type != (SByte)AssetType.Mesh) | ||||
|             { | ||||
|                 responsedata["str_response_string"] = "Asset isn't a mesh."; | ||||
|                 return responsedata; | ||||
|             } | ||||
| 
 | ||||
|             string range = String.Empty; | ||||
| 
 | ||||
|             if (((Hashtable)request["headers"])["range"] != null) | ||||
|                range = (string)((Hashtable)request["headers"])["range"]; | ||||
|             else if (((Hashtable)request["headers"])["Range"] != null) | ||||
|                 range = (string)((Hashtable)request["headers"])["Range"]; | ||||
| 
 | ||||
|             responsedata["content_type"] = "application/vnd.ll.mesh"; | ||||
|             if (String.IsNullOrEmpty(range)) | ||||
|             { | ||||
|                 // full mesh | ||||
|                 responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data); | ||||
|                 responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.OK; | ||||
|                 return responsedata; | ||||
|             } | ||||
| 
 | ||||
|             // range request | ||||
|             int start, end; | ||||
|             if (Util.TryParseHttpRange(range, out start, out end)) | ||||
|             { | ||||
|                 // Before clamping start make sure we can satisfy it in order to avoid | ||||
|                 // sending back the last byte instead of an error status | ||||
|                 if (start >= mesh.Data.Length) | ||||
|                 if (m_assetService == null) | ||||
|                 { | ||||
|                     responsedata["str_response_string"] = "This range doesnt exist."; | ||||
|                     responsedata["int_response_code"] = 404; //501; //410; //404; | ||||
|                     responsedata["content_type"] = "text/plain"; | ||||
|                     responsedata["keepalive"] = false; | ||||
|                     responsedata["str_response_string"] = "The asset service is unavailable.  So is your mesh."; | ||||
|                     return responsedata; | ||||
|                 } | ||||
| 
 | ||||
|                 end = Utils.Clamp(end, 0, mesh.Data.Length - 1); | ||||
|                 start = Utils.Clamp(start, 0, end); | ||||
|                 int len = end - start + 1; | ||||
|                 AssetBase mesh = m_assetService.Get(meshID.ToString()); | ||||
| 
 | ||||
|                 //m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); | ||||
|                 Hashtable headers = new Hashtable(); | ||||
|                 headers["Content-Range"] = String.Format("bytes {0}-{1}/{2}", start, end, mesh.Data.Length); | ||||
|                 responsedata["headers"] = headers; | ||||
|                 responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.PartialContent; | ||||
| 
 | ||||
|                 byte[] d = new byte[len]; | ||||
|                 Array.Copy(mesh.Data, start, d, 0, len); | ||||
|                 responsedata["bin_response_data"] = d; | ||||
|                 responsedata["int_bytes"] = len; | ||||
|                 return responsedata; | ||||
|                 if (mesh != null) | ||||
|                 { | ||||
|                     if (mesh.Type == (SByte)AssetType.Mesh) | ||||
|                     { | ||||
|                         responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data); | ||||
|                         responsedata["content_type"] = "application/vnd.ll.mesh"; | ||||
|                         responsedata["int_response_code"] = 200; | ||||
|                     } | ||||
|                     // Optionally add additional mesh types here | ||||
|                     else | ||||
|                     { | ||||
|                         responsedata["int_response_code"] = 404; //501; //410; //404; | ||||
|                         responsedata["content_type"] = "text/plain"; | ||||
|                         responsedata["keepalive"] = false; | ||||
|                         responsedata["str_response_string"] = "Unfortunately, this asset isn't a mesh."; | ||||
|                         return responsedata; | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     responsedata["int_response_code"] = 404; //501; //410; //404; | ||||
|                     responsedata["content_type"] = "text/plain"; | ||||
|                     responsedata["keepalive"] = false; | ||||
|                     responsedata["str_response_string"] = "Your Mesh wasn't found.  Sorry!"; | ||||
|                     return responsedata; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             m_log.Warn("[GETMESH]: Failed to parse a range from GetMesh request, sending full asset: " + (string)request["uri"]); | ||||
|             responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data); | ||||
|             responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.OK; | ||||
|             return responsedata; | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -25,13 +25,16 @@ | |||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using Nini.Config; | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Server.Base; | ||||
| using OpenSim.Server.Handlers.Base; | ||||
| using OpenSim.Services.Interfaces; | ||||
| using System; | ||||
| using System.Collections; | ||||
| using Nini.Config; | ||||
| using OpenSim.Server.Base; | ||||
| using OpenSim.Services.Interfaces; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Server.Handlers.Base; | ||||
| using OpenSim.Framework.Servers; | ||||
| 
 | ||||
| using OpenMetaverse; | ||||
| 
 | ||||
| namespace OpenSim.Capabilities.Handlers | ||||
| { | ||||
|  | @ -62,17 +65,14 @@ namespace OpenSim.Capabilities.Handlers | |||
|             if (m_AssetService == null) | ||||
|                 throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName)); | ||||
| 
 | ||||
|             string rurl = serverConfig.GetString("GetMeshRedirectURL"); | ||||
| 
 | ||||
|             GetMeshHandler gmeshHandler = new GetMeshHandler(m_AssetService); | ||||
|             IRequestHandler reqHandler | ||||
|                 = new RestHTTPHandler( | ||||
|                     "GET", | ||||
|                     "/" + UUID.Random(), | ||||
|                     httpMethod => gmeshHandler.ProcessGetMesh(httpMethod, UUID.Zero, null), | ||||
|                     "GetMesh", | ||||
|                     null); | ||||
|             server.AddStreamHandler(reqHandler); ; | ||||
|             IRequestHandler reqHandler = new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(), | ||||
|                                                        delegate(Hashtable m_dhttpMethod) | ||||
|                                                        { | ||||
|                                                            return gmeshHandler.ProcessGetMesh(m_dhttpMethod, UUID.Zero, null); | ||||
|                                                        }); | ||||
|             server.AddStreamHandler(reqHandler); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -47,92 +47,87 @@ using Caps = OpenSim.Framework.Capabilities.Caps; | |||
| 
 | ||||
| namespace OpenSim.Capabilities.Handlers | ||||
| { | ||||
|     public class GetTextureHandler | ||||
|     public class GetTextureHandler : BaseStreamHandler | ||||
|     { | ||||
|         private static readonly ILog m_log = | ||||
|             LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private IAssetService m_assetService; | ||||
| 
 | ||||
|         public const string DefaultFormat = "x-j2c"; | ||||
| 
 | ||||
|         public GetTextureHandler(IAssetService assService) | ||||
|         // TODO: Change this to a config option | ||||
|         const string REDIRECT_URL = null; | ||||
| 
 | ||||
|         public GetTextureHandler(string path, IAssetService assService) : | ||||
|                 base("GET", path) | ||||
|         { | ||||
|             m_assetService = assService; | ||||
|         } | ||||
| 
 | ||||
|         public Hashtable Handle(Hashtable request) | ||||
|         public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||||
|         { | ||||
|             Hashtable ret = new Hashtable(); | ||||
|             ret["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound; | ||||
|             ret["content_type"] = "text/plain"; | ||||
|             ret["int_bytes"] = 0; | ||||
|             string textureStr = (string)request["texture_id"]; | ||||
|             string format = (string)request["format"]; | ||||
|             // Try to parse the texture ID from the request URL | ||||
|             NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); | ||||
|             string textureStr = query.GetOne("texture_id"); | ||||
|             string format = query.GetOne("format"); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[GETTEXTURE]: called {0}", textureStr); | ||||
| 
 | ||||
|             if (m_assetService == null) | ||||
|             { | ||||
|                 m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service"); | ||||
|                 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; | ||||
|                 return null; | ||||
|             } | ||||
| 
 | ||||
|             UUID textureID; | ||||
|             if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID)) | ||||
|             { | ||||
| //                m_log.DebugFormat("[GETTEXTURE]: Received request for texture id {0}", textureID); | ||||
| 
 | ||||
|                  | ||||
|                 string[] formats; | ||||
|                 if (!string.IsNullOrEmpty(format)) | ||||
|                 if (format != null && format != string.Empty) | ||||
|                 { | ||||
|                     formats = new string[1] { format.ToLower() }; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     formats = new string[1] { DefaultFormat }; // default | ||||
|                     if (((Hashtable)request["headers"])["Accept"] != null) | ||||
|                         formats = WebUtil.GetPreferredImageTypes((string)((Hashtable)request["headers"])["Accept"]); | ||||
|                     formats = WebUtil.GetPreferredImageTypes(httpRequest.Headers.Get("Accept")); | ||||
|                     if (formats.Length == 0) | ||||
|                         formats = new string[1] { DefaultFormat }; // default | ||||
| 
 | ||||
|                 } | ||||
|                 // OK, we have an array with preferred formats, possibly with only one entry | ||||
|                 bool foundtexture = false; | ||||
| 
 | ||||
|                 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; | ||||
|                 foreach (string f in formats) | ||||
|                 { | ||||
|                     foundtexture = FetchTexture(request, ret, textureID, f); | ||||
|                     if (foundtexture) | ||||
|                     if (FetchTexture(httpRequest, httpResponse, textureID, f)) | ||||
|                         break; | ||||
|                 } | ||||
|                 if (!foundtexture) | ||||
|                 { | ||||
|                     ret["int_response_code"] = 404; | ||||
|                     ret["error_status_text"] = "not found"; | ||||
|                     ret["str_response_string"] = "not found"; | ||||
|                     ret["content_type"] = "text/plain"; | ||||
|                     ret["int_bytes"] = 0; | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + (string)request["uri"]); | ||||
|                 m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + httpRequest.Url); | ||||
|             } | ||||
| 
 | ||||
| //            m_log.DebugFormat( | ||||
| //                "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}", | ||||
| //                textureID, httpResponse.StatusCode, httpResponse.ContentLength); | ||||
|             return ret; | ||||
| 
 | ||||
|             httpResponse.Send(); | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// | ||||
|         ///  | ||||
|         /// </summary> | ||||
|         /// <param name="httpRequest"></param> | ||||
|         /// <param name="httpResponse"></param> | ||||
|         /// <param name="textureID"></param> | ||||
|         /// <param name="format"></param> | ||||
|         /// <returns>False for "caller try another codec"; true otherwise</returns> | ||||
|         private bool FetchTexture(Hashtable request, Hashtable response, UUID textureID, string format) | ||||
|         private bool FetchTexture(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, UUID textureID, string format) | ||||
|         { | ||||
| //            m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format); | ||||
|             AssetBase texture; | ||||
|  | @ -141,142 +136,135 @@ namespace OpenSim.Capabilities.Handlers | |||
|             if (format != DefaultFormat) | ||||
|                 fullID = fullID + "-" + format; | ||||
| 
 | ||||
|             // try the cache | ||||
|             texture = m_assetService.GetCached(fullID); | ||||
| 
 | ||||
|             if (texture == null) | ||||
|             if (!String.IsNullOrEmpty(REDIRECT_URL)) | ||||
|             { | ||||
|                 //m_log.DebugFormat("[GETTEXTURE]: texture was not in the cache"); | ||||
| 
 | ||||
|                 // Fetch locally or remotely. Misses return a 404 | ||||
|                 texture = m_assetService.Get(textureID.ToString()); | ||||
|                 // Only try to fetch locally cached textures. Misses are redirected | ||||
|                 texture = m_assetService.GetCached(fullID); | ||||
| 
 | ||||
|                 if (texture != null) | ||||
|                 { | ||||
|                     if (texture.Type != (sbyte)AssetType.Texture) | ||||
|                         return true; | ||||
| 
 | ||||
|                     if (format == DefaultFormat) | ||||
|                     { | ||||
|                         WriteTextureData(request, response, texture, format); | ||||
|                         return true; | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         AssetBase newTexture = new AssetBase(texture.ID + "-" + format, texture.Name, (sbyte)AssetType.Texture, texture.Metadata.CreatorID); | ||||
|                         newTexture.Data = ConvertTextureData(texture, format); | ||||
|                         if (newTexture.Data.Length == 0) | ||||
|                             return false; // !!! Caller try another codec, please! | ||||
| 
 | ||||
|                         newTexture.Flags = AssetFlags.Collectable; | ||||
|                         newTexture.Temporary = true; | ||||
|                         newTexture.Local = true; | ||||
|                         m_assetService.Store(newTexture); | ||||
|                         WriteTextureData(request, response, newTexture, format); | ||||
|                         httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; | ||||
|                         return true; | ||||
|                     } | ||||
|                     WriteTextureData(httpRequest, httpResponse, texture, format); | ||||
|                 } | ||||
|            } | ||||
|            else // it was on the cache | ||||
|            { | ||||
|                //m_log.DebugFormat("[GETTEXTURE]: texture was in the cache"); | ||||
|                WriteTextureData(request, response, texture, format); | ||||
|                return true; | ||||
|            } | ||||
|                 else | ||||
|                 { | ||||
|                     string textureUrl = REDIRECT_URL + textureID.ToString(); | ||||
|                     m_log.Debug("[GETTEXTURE]: Redirecting texture request to " + textureUrl); | ||||
|                     httpResponse.RedirectLocation = textureUrl; | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
|             else // no redirect | ||||
|             { | ||||
|                 // try the cache | ||||
|                 texture = m_assetService.GetCached(fullID); | ||||
| 
 | ||||
|             //response = new Hashtable(); | ||||
|                 if (texture == null) | ||||
|                 { | ||||
|                     //m_log.DebugFormat("[GETTEXTURE]: texture was not in the cache"); | ||||
| 
 | ||||
|                     // Fetch locally or remotely. Misses return a 404 | ||||
|                     texture = m_assetService.Get(textureID.ToString()); | ||||
| 
 | ||||
|                     if (texture != null) | ||||
|                     { | ||||
|                         if (texture.Type != (sbyte)AssetType.Texture) | ||||
|                         { | ||||
|                             httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; | ||||
|                             return true; | ||||
|                         } | ||||
|                         if (format == DefaultFormat) | ||||
|                         { | ||||
|                             WriteTextureData(httpRequest, httpResponse, texture, format); | ||||
|                             return true; | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             AssetBase newTexture = new AssetBase(texture.ID + "-" + format, texture.Name, (sbyte)AssetType.Texture, texture.Metadata.CreatorID); | ||||
|                             newTexture.Data = ConvertTextureData(texture, format); | ||||
|                             if (newTexture.Data.Length == 0) | ||||
|                                 return false; // !!! Caller try another codec, please! | ||||
| 
 | ||||
|                             newTexture.Flags = AssetFlags.Collectable; | ||||
|                             newTexture.Temporary = true; | ||||
|                             m_assetService.Store(newTexture); | ||||
|                             WriteTextureData(httpRequest, httpResponse, newTexture, format); | ||||
|                             return true; | ||||
|                         } | ||||
|                     } | ||||
|                } | ||||
|                else // it was on the cache | ||||
|                { | ||||
|                    //m_log.DebugFormat("[GETTEXTURE]: texture was in the cache"); | ||||
|                    WriteTextureData(httpRequest, httpResponse, texture, format); | ||||
|                    return true; | ||||
|                } | ||||
|             } | ||||
| 
 | ||||
|             //WriteTextureData(request,response,null,format); | ||||
|             // not found | ||||
|             //m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found"); | ||||
|             return false; | ||||
| //            m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found"); | ||||
|             httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         private void WriteTextureData(Hashtable request, Hashtable response, AssetBase texture, string format) | ||||
|         private void WriteTextureData(IOSHttpRequest request, IOSHttpResponse response, AssetBase texture, string format) | ||||
|         { | ||||
|             Hashtable headers = new Hashtable(); | ||||
|             response["headers"] = headers; | ||||
| 
 | ||||
|             string range = String.Empty; | ||||
| 
 | ||||
|             if (((Hashtable)request["headers"])["range"] != null) | ||||
|                 range = (string)((Hashtable)request["headers"])["range"]; | ||||
| 
 | ||||
|             else if (((Hashtable)request["headers"])["Range"] != null) | ||||
|                 range = (string)((Hashtable)request["headers"])["Range"]; | ||||
|             string range = request.Headers.GetOne("Range"); | ||||
| 
 | ||||
|             if (!String.IsNullOrEmpty(range)) // JP2's only | ||||
|             { | ||||
|                 // Range request | ||||
|                 int start, end; | ||||
|                 if (Util.TryParseHttpRange(range, out start, out end)) | ||||
|                 if (TryParseRange(range, out start, out end)) | ||||
|                 { | ||||
| 
 | ||||
|                     // Before clamping start make sure we can satisfy it in order to avoid | ||||
|                     // sending back the last byte instead of an error status | ||||
|                     if (start >= texture.Data.Length) | ||||
|                     { | ||||
| //                        m_log.DebugFormat( | ||||
| //                            "[GETTEXTURE]: Client requested range for texture {0} starting at {1} but texture has end of {2}", | ||||
| //                            texture.ID, start, texture.Data.Length); | ||||
| 
 | ||||
|                         // Stricly speaking, as per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html, we should be sending back | ||||
|                         // Requested Range Not Satisfiable (416) here.  However, it appears that at least recent implementations | ||||
|                         // of the Linden Lab viewer (3.2.1 and 3.3.4 and probably earlier), a viewer that has previously | ||||
|                         // received a very small texture  may attempt to fetch bytes from the server past the | ||||
|                         // range of data that it received originally.  Whether this happens appears to depend on whether | ||||
|                         // the viewer's estimation of how large a request it needs to make for certain discard levels | ||||
|                         // (http://wiki.secondlife.com/wiki/Image_System#Discard_Level_and_Mip_Mapping), chiefly discard | ||||
|                         // level 2.  If this estimate is greater than the total texture size, returning a RequestedRangeNotSatisfiable | ||||
|                         // here will cause the viewer to treat the texture as bad and never display the full resolution | ||||
|                         // However, if we return PartialContent (or OK) instead, the viewer will display that resolution. | ||||
| 
 | ||||
| //                        response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable; | ||||
|                         // viewers don't seem to handle RequestedRangeNotSatisfiable and keep retrying with same parameters | ||||
|                         response["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound; | ||||
|                         response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable; | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         // Handle the case where no second range value was given.  This is equivalent to requesting | ||||
|                         // the rest of the entity. | ||||
|                         if (end == -1) | ||||
|                             end = int.MaxValue; | ||||
| 
 | ||||
|                         end = Utils.Clamp(end, 0, texture.Data.Length - 1); | ||||
|                         start = Utils.Clamp(start, 0, end); | ||||
|                         int len = end - start + 1; | ||||
| 
 | ||||
| //                        m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); | ||||
|                         //m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); | ||||
| 
 | ||||
|                         response["content-type"] = texture.Metadata.ContentType; | ||||
|                         response["int_response_code"] = (int)System.Net.HttpStatusCode.PartialContent; | ||||
|                         headers["Content-Range"] = String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length); | ||||
|                         // Always return PartialContent, even if the range covered the entire data length | ||||
|                         // We were accidentally sending back 404 before in this situation | ||||
|                         // https://issues.apache.org/bugzilla/show_bug.cgi?id=51878 supports sending 206 even if the | ||||
|                         // entire range is requested, and viewer 3.2.2 (and very probably earlier) seems fine with this. | ||||
|                         response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; | ||||
| 
 | ||||
|                         byte[] d = new byte[len]; | ||||
|                         Array.Copy(texture.Data, start, d, 0, len); | ||||
|                         response["bin_response_data"] = d; | ||||
|                         response["int_bytes"] = len; | ||||
|                         response.ContentLength = len; | ||||
|                         response.ContentType = texture.Metadata.ContentType; | ||||
|                         response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length)); | ||||
|      | ||||
|                         response.Body.Write(texture.Data, start, len); | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range); | ||||
|                     response["int_response_code"] = (int)System.Net.HttpStatusCode.BadRequest; | ||||
|                     response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest; | ||||
|                 } | ||||
|             } | ||||
|             else // JP2's or other formats | ||||
|             { | ||||
|                 // Full content request | ||||
|                 response["int_response_code"] = (int)System.Net.HttpStatusCode.OK; | ||||
|                 response.StatusCode = (int)System.Net.HttpStatusCode.OK; | ||||
|                 response.ContentLength = texture.Data.Length; | ||||
|                 if (format == DefaultFormat) | ||||
|                     response["content_type"] = texture.Metadata.ContentType; | ||||
|                     response.ContentType = texture.Metadata.ContentType; | ||||
|                 else | ||||
|                     response["content_type"] = "image/" + format; | ||||
| 
 | ||||
|                 response["bin_response_data"] = texture.Data; | ||||
|                 response["int_bytes"] = texture.Data.Length; | ||||
| 
 | ||||
| //                response.Body.Write(texture.Data, 0, texture.Data.Length); | ||||
|                     response.ContentType = "image/" + format; | ||||
|                 response.Body.Write(texture.Data, 0, texture.Data.Length); | ||||
|             } | ||||
| 
 | ||||
| //            if (response.StatusCode < 200 || response.StatusCode > 299) | ||||
|  | @ -289,41 +277,58 @@ namespace OpenSim.Capabilities.Handlers | |||
| //                    texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length); | ||||
|         } | ||||
| 
 | ||||
|         private bool TryParseRange(string header, out int start, out int end) | ||||
|         { | ||||
|             if (header.StartsWith("bytes=")) | ||||
|             { | ||||
|                 string[] rangeValues = header.Substring(6).Split('-'); | ||||
|                 if (rangeValues.Length == 2) | ||||
|                 { | ||||
|                     if (Int32.TryParse(rangeValues[0], out start) && Int32.TryParse(rangeValues[1], out end)) | ||||
|                         return true; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             start = end = 0; | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         private byte[] ConvertTextureData(AssetBase texture, string format) | ||||
|         { | ||||
|             m_log.DebugFormat("[GETTEXTURE]: Converting texture {0} to {1}", texture.ID, format); | ||||
|             byte[] data = new byte[0]; | ||||
| 
 | ||||
|             MemoryStream imgstream = new MemoryStream(); | ||||
|             Bitmap mTexture = null; | ||||
|             ManagedImage managedImage = null; | ||||
|             Image image = null; | ||||
|             Bitmap mTexture = new Bitmap(1, 1); | ||||
|             ManagedImage managedImage; | ||||
|             Image image = (Image)mTexture; | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular data | ||||
| 
 | ||||
|                 imgstream = new MemoryStream(); | ||||
| 
 | ||||
|                 // Decode image to System.Drawing.Image | ||||
|                 if (OpenJPEG.DecodeToImage(texture.Data, out managedImage, out image) && image != null) | ||||
|                 if (OpenJPEG.DecodeToImage(texture.Data, out managedImage, out image)) | ||||
|                 { | ||||
|                     // Save to bitmap | ||||
|                     mTexture = new Bitmap(image); | ||||
| 
 | ||||
|                     using(EncoderParameters myEncoderParameters = new EncoderParameters()) | ||||
|                     { | ||||
|                         myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality,95L); | ||||
|                     EncoderParameters myEncoderParameters = new EncoderParameters(); | ||||
|                     myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 95L); | ||||
| 
 | ||||
|                         // Save bitmap to stream | ||||
|                         ImageCodecInfo codec = GetEncoderInfo("image/" + format); | ||||
|                         if (codec != null) | ||||
|                         { | ||||
|                             mTexture.Save(imgstream, codec, myEncoderParameters); | ||||
|                     // Save bitmap to stream | ||||
|                     ImageCodecInfo codec = GetEncoderInfo("image/" + format); | ||||
|                     if (codec != null) | ||||
|                     { | ||||
|                         mTexture.Save(imgstream, codec, myEncoderParameters); | ||||
|                         // Write the stream to a byte array for output | ||||
|                             data = imgstream.ToArray(); | ||||
|                         } | ||||
|                         else | ||||
|                             m_log.WarnFormat("[GETTEXTURE]: No such codec {0}", format); | ||||
|                         data = imgstream.ToArray(); | ||||
|                     } | ||||
|                     else | ||||
|                         m_log.WarnFormat("[GETTEXTURE]: No such codec {0}", format); | ||||
| 
 | ||||
|                 } | ||||
|             } | ||||
|             catch (Exception e) | ||||
|  | @ -340,10 +345,11 @@ namespace OpenSim.Capabilities.Handlers | |||
|                 if (image != null) | ||||
|                     image.Dispose(); | ||||
| 
 | ||||
|                 if(managedImage != null) | ||||
|                     managedImage.Clear(); | ||||
|                 if (imgstream != null) | ||||
|                 { | ||||
|                     imgstream.Close(); | ||||
|                     imgstream.Dispose(); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return data; | ||||
|  | @ -362,4 +368,4 @@ namespace OpenSim.Capabilities.Handlers | |||
|             return null; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| } | ||||
|  | @ -1,394 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections; | ||||
| using System.Collections.Specialized; | ||||
| using System.Drawing; | ||||
| using System.Drawing.Imaging; | ||||
| using System.Reflection; | ||||
| using System.IO; | ||||
| using System.Net; | ||||
| using System.Web; | ||||
| using log4net; | ||||
| using Nini.Config; | ||||
| using OpenMetaverse; | ||||
| using OpenMetaverse.StructuredData; | ||||
| using OpenMetaverse.Imaging; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Servers; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Region.Framework.Interfaces; | ||||
| using OpenSim.Services.Interfaces; | ||||
| using Caps = OpenSim.Framework.Capabilities.Caps; | ||||
| 
 | ||||
| namespace OpenSim.Capabilities.Handlers | ||||
| { | ||||
|     public class GetTextureRobustHandler : BaseStreamHandler | ||||
|     { | ||||
|         private static readonly ILog m_log = | ||||
|             LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
|         private IAssetService m_assetService; | ||||
| 
 | ||||
|         public const string DefaultFormat = "x-j2c"; | ||||
| 
 | ||||
|         // TODO: Change this to a config option | ||||
|         private string m_RedirectURL = null; | ||||
| 
 | ||||
|         public GetTextureRobustHandler(string path, IAssetService assService, string name, string description, string redirectURL) | ||||
|             : base("GET", path, name, description) | ||||
|         { | ||||
|             m_assetService = assService; | ||||
|             m_RedirectURL = redirectURL; | ||||
|             if (m_RedirectURL != null && !m_RedirectURL.EndsWith("/")) | ||||
|                 m_RedirectURL += "/"; | ||||
|         } | ||||
| 
 | ||||
|         protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||||
|         { | ||||
|             // Try to parse the texture ID from the request URL | ||||
|             NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); | ||||
|             string textureStr = query.GetOne("texture_id"); | ||||
|             string format = query.GetOne("format"); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[GETTEXTURE]: called {0}", textureStr); | ||||
| 
 | ||||
|             if (m_assetService == null) | ||||
|             { | ||||
|                 m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service"); | ||||
|                 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; | ||||
|                 return null; | ||||
|             } | ||||
| 
 | ||||
|             UUID textureID; | ||||
|             if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID)) | ||||
|             { | ||||
| //                m_log.DebugFormat("[GETTEXTURE]: Received request for texture id {0}", textureID); | ||||
| 
 | ||||
|                 string[] formats; | ||||
|                 if (!string.IsNullOrEmpty(format)) | ||||
|                 { | ||||
|                     formats = new string[1] { format.ToLower() }; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     formats = WebUtil.GetPreferredImageTypes(httpRequest.Headers.Get("Accept")); | ||||
|                     if (formats.Length == 0) | ||||
|                         formats = new string[1] { DefaultFormat }; // default | ||||
| 
 | ||||
|                 } | ||||
|                 // OK, we have an array with preferred formats, possibly with only one entry | ||||
| 
 | ||||
|                 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; | ||||
|                 foreach (string f in formats) | ||||
|                 { | ||||
|                     if (FetchTexture(httpRequest, httpResponse, textureID, f)) | ||||
|                         break; | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + httpRequest.Url); | ||||
|             } | ||||
| 
 | ||||
| //            m_log.DebugFormat( | ||||
| //                "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}", | ||||
| //                textureID, httpResponse.StatusCode, httpResponse.ContentLength); | ||||
| 
 | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// | ||||
|         /// </summary> | ||||
|         /// <param name="httpRequest"></param> | ||||
|         /// <param name="httpResponse"></param> | ||||
|         /// <param name="textureID"></param> | ||||
|         /// <param name="format"></param> | ||||
|         /// <returns>False for "caller try another codec"; true otherwise</returns> | ||||
|         private bool FetchTexture(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, UUID textureID, string format) | ||||
|         { | ||||
|             // m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format); | ||||
|             if(!String.IsNullOrEmpty(m_RedirectURL)) | ||||
|             { | ||||
|                 string textureUrl = m_RedirectURL + "?texture_id=" + textureID.ToString(); | ||||
|                 m_log.Debug("[GETTEXTURE]: Redirecting texture request to " + textureUrl); | ||||
|                 httpResponse.StatusCode = (int)HttpStatusCode.Moved; | ||||
|                 httpResponse.AddHeader("Location:", textureUrl); | ||||
|                 return true; | ||||
|             } | ||||
| 
 | ||||
|             // Fetch,  Misses or invalid return a 404 | ||||
|             AssetBase texture = m_assetService.Get(textureID.ToString()); | ||||
|             if (texture != null) | ||||
|             { | ||||
|                 if (texture.Type != (sbyte)AssetType.Texture) | ||||
|                 { | ||||
|                     httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; | ||||
|                     return true; | ||||
|                 } | ||||
|                 if (format == DefaultFormat) | ||||
|                 { | ||||
|                     WriteTextureData(httpRequest, httpResponse, texture, format); | ||||
|                     return true; | ||||
|                 } | ||||
| 
 | ||||
|                 // need to convert format | ||||
|                 AssetBase newTexture = new AssetBase(texture.ID + "-" + format, texture.Name, (sbyte)AssetType.Texture, texture.Metadata.CreatorID); | ||||
|                 newTexture.Data = ConvertTextureData(texture, format); | ||||
|                 if (newTexture.Data.Length == 0) | ||||
|                     return false; // !!! Caller try another codec, please! | ||||
| 
 | ||||
|                 newTexture.Flags = AssetFlags.Collectable; | ||||
|                 newTexture.Temporary = true; | ||||
|                 newTexture.Local = true; | ||||
|                 WriteTextureData(httpRequest, httpResponse, newTexture, format); | ||||
|                 return true; | ||||
|             } | ||||
| 
 | ||||
|             // not found | ||||
|             // m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found"); | ||||
|             httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         private void WriteTextureData(IOSHttpRequest request, IOSHttpResponse response, AssetBase texture, string format) | ||||
|         { | ||||
|             string range = request.Headers.GetOne("Range"); | ||||
| 
 | ||||
|             if (!String.IsNullOrEmpty(range)) // JP2's only | ||||
|             { | ||||
|                 // Range request | ||||
|                 int start, end; | ||||
|                 if (TryParseRange(range, out start, out end)) | ||||
|                 { | ||||
|                     // Before clamping start make sure we can satisfy it in order to avoid | ||||
|                     // sending back the last byte instead of an error status | ||||
|                     if (start >= texture.Data.Length) | ||||
|                     { | ||||
| //                        m_log.DebugFormat( | ||||
| //                            "[GETTEXTURE]: Client requested range for texture {0} starting at {1} but texture has end of {2}", | ||||
| //                            texture.ID, start, texture.Data.Length); | ||||
| 
 | ||||
|                         // Stricly speaking, as per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html, we should be sending back | ||||
|                         // Requested Range Not Satisfiable (416) here.  However, it appears that at least recent implementations | ||||
|                         // of the Linden Lab viewer (3.2.1 and 3.3.4 and probably earlier), a viewer that has previously | ||||
|                         // received a very small texture  may attempt to fetch bytes from the server past the | ||||
|                         // range of data that it received originally.  Whether this happens appears to depend on whether | ||||
|                         // the viewer's estimation of how large a request it needs to make for certain discard levels | ||||
|                         // (http://wiki.secondlife.com/wiki/Image_System#Discard_Level_and_Mip_Mapping), chiefly discard | ||||
|                         // level 2.  If this estimate is greater than the total texture size, returning a RequestedRangeNotSatisfiable | ||||
|                         // here will cause the viewer to treat the texture as bad and never display the full resolution | ||||
|                         // However, if we return PartialContent (or OK) instead, the viewer will display that resolution. | ||||
| 
 | ||||
| //                        response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable; | ||||
| //                        response.AddHeader("Content-Range", String.Format("bytes */{0}", texture.Data.Length)); | ||||
| //                        response.StatusCode = (int)System.Net.HttpStatusCode.OK; | ||||
|                         response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; | ||||
|                         response.ContentType = texture.Metadata.ContentType; | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         // Handle the case where no second range value was given.  This is equivalent to requesting | ||||
|                         // the rest of the entity. | ||||
|                         if (end == -1) | ||||
|                             end = int.MaxValue; | ||||
| 
 | ||||
|                         end = Utils.Clamp(end, 0, texture.Data.Length - 1); | ||||
|                         start = Utils.Clamp(start, 0, end); | ||||
|                         int len = end - start + 1; | ||||
| 
 | ||||
| //                        m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); | ||||
| 
 | ||||
|                         // Always return PartialContent, even if the range covered the entire data length | ||||
|                         // We were accidentally sending back 404 before in this situation | ||||
|                         // https://issues.apache.org/bugzilla/show_bug.cgi?id=51878 supports sending 206 even if the | ||||
|                         // entire range is requested, and viewer 3.2.2 (and very probably earlier) seems fine with this. | ||||
|                         // | ||||
|                         // We also do not want to send back OK even if the whole range was satisfiable since this causes | ||||
|                         // HTTP textures on at least Imprudence 1.4.0-beta2 to never display the final texture quality. | ||||
| //                        if (end > maxEnd) | ||||
| //                            response.StatusCode = (int)System.Net.HttpStatusCode.OK; | ||||
| //                        else | ||||
|                         response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; | ||||
| 
 | ||||
|                         response.ContentLength = len; | ||||
|                         response.ContentType = texture.Metadata.ContentType; | ||||
|                         response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length)); | ||||
|                         response.RawBuffer = texture.Data; | ||||
|                         response.RawBufferStart = start; | ||||
|                         response.RawBufferLen = len; | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range); | ||||
|                     response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest; | ||||
|                 } | ||||
|             } | ||||
|             else // JP2's or other formats | ||||
|             { | ||||
|                 // Full content request | ||||
|                 response.StatusCode = (int)System.Net.HttpStatusCode.OK; | ||||
|                 response.ContentLength = texture.Data.Length; | ||||
|                 if (format == DefaultFormat) | ||||
|                     response.ContentType = texture.Metadata.ContentType; | ||||
|                 else | ||||
|                     response.ContentType = "image/" + format; | ||||
|                 response.RawBuffer = texture.Data; | ||||
|                 response.RawBufferStart = 0; | ||||
|                 response.RawBufferLen = texture.Data.Length; | ||||
|             } | ||||
| 
 | ||||
|             //            if (response.StatusCode < 200 || response.StatusCode > 299) | ||||
|             //                m_log.WarnFormat( | ||||
|             //                    "[GETTEXTURE]: For texture {0} requested range {1} responded {2} with content length {3} (actual {4})", | ||||
|             //                    texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length); | ||||
|             //            else | ||||
|             //                m_log.DebugFormat( | ||||
|             //                    "[GETTEXTURE]: For texture {0} requested range {1} responded {2} with content length {3} (actual {4})", | ||||
|             //                    texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Parse a range header. | ||||
|         /// </summary> | ||||
|         /// <remarks> | ||||
|         /// As per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html, | ||||
|         /// this obeys range headers with two values (e.g. 533-4165) and no second value (e.g. 533-). | ||||
|         /// Where there is no value, -1 is returned. | ||||
|         /// FIXME: Need to cover the case where only a second value is specified (e.g. -4165), probably by returning -1 | ||||
|         /// for start.</remarks> | ||||
|         /// <returns></returns> | ||||
|         /// <param name='header'></param> | ||||
|         /// <param name='start'>Start of the range.  Undefined if this was not a number.</param> | ||||
|         /// <param name='end'>End of the range.  Will be -1 if no end specified.  Undefined if there was a raw string but this was not a number.</param> | ||||
|         private bool TryParseRange(string header, out int start, out int end) | ||||
|         { | ||||
|             start = end = 0; | ||||
| 
 | ||||
|             if (header.StartsWith("bytes=")) | ||||
|             { | ||||
|                 string[] rangeValues = header.Substring(6).Split('-'); | ||||
| 
 | ||||
|                 if (rangeValues.Length == 2) | ||||
|                 { | ||||
|                     if (!Int32.TryParse(rangeValues[0], out start)) | ||||
|                         return false; | ||||
| 
 | ||||
|                     string rawEnd = rangeValues[1]; | ||||
| 
 | ||||
|                     if (rawEnd == "") | ||||
|                     { | ||||
|                         end = -1; | ||||
|                         return true; | ||||
|                     } | ||||
|                     else if (Int32.TryParse(rawEnd, out end)) | ||||
|                     { | ||||
|                         return true; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             start = end = 0; | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         private byte[] ConvertTextureData(AssetBase texture, string format) | ||||
|         { | ||||
|             m_log.DebugFormat("[GETTEXTURE]: Converting texture {0} to {1}", texture.ID, format); | ||||
|             byte[] data = new byte[0]; | ||||
| 
 | ||||
|             MemoryStream imgstream = new MemoryStream(); | ||||
|             Bitmap mTexture = null; | ||||
|             ManagedImage managedImage = null; | ||||
|             Image image = null; | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular data | ||||
|                 // Decode image to System.Drawing.Image | ||||
|                 if (OpenJPEG.DecodeToImage(texture.Data, out managedImage, out image) && image != null) | ||||
|                 { | ||||
|                     // Save to bitmap | ||||
|                     mTexture = new Bitmap(image); | ||||
| 
 | ||||
|                     using(EncoderParameters myEncoderParameters = new EncoderParameters()) | ||||
|                     { | ||||
|                         myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality,95L); | ||||
| 
 | ||||
|                         // Save bitmap to stream | ||||
|                         ImageCodecInfo codec = GetEncoderInfo("image/" + format); | ||||
|                         if (codec != null) | ||||
|                         { | ||||
|                             mTexture.Save(imgstream, codec, myEncoderParameters); | ||||
|                             // Write the stream to a byte array for output | ||||
|                             data = imgstream.ToArray(); | ||||
|                         } | ||||
|                         else | ||||
|                             m_log.WarnFormat("[GETTEXTURE]: No such codec {0}", format); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 m_log.WarnFormat("[GETTEXTURE]: Unable to convert texture {0} to {1}: {2}", texture.ID, format, e.Message); | ||||
|             } | ||||
|             finally | ||||
|             { | ||||
|                 // Reclaim memory, these are unmanaged resources | ||||
|                 // If we encountered an exception, one or more of these will be null | ||||
|                 if (mTexture != null) | ||||
|                     mTexture.Dispose(); | ||||
| 
 | ||||
|                 if (image != null) | ||||
|                     image.Dispose(); | ||||
| 
 | ||||
|                 if(managedImage != null) | ||||
|                     managedImage.Clear(); | ||||
| 
 | ||||
|                 if (imgstream != null) | ||||
|                     imgstream.Dispose(); | ||||
|             } | ||||
| 
 | ||||
|             return data; | ||||
|         } | ||||
| 
 | ||||
|         // From msdn | ||||
|         private static ImageCodecInfo GetEncoderInfo(String mimeType) | ||||
|         { | ||||
|             ImageCodecInfo[] encoders; | ||||
|             encoders = ImageCodecInfo.GetImageEncoders(); | ||||
|             for (int j = 0; j < encoders.Length; ++j) | ||||
|             { | ||||
|                 if (encoders[j].MimeType == mimeType) | ||||
|                     return encoders[j]; | ||||
|             } | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -33,7 +33,6 @@ using OpenSim.Framework.Servers.HttpServer; | |||
| using OpenSim.Server.Handlers.Base; | ||||
| using OpenMetaverse; | ||||
| 
 | ||||
| 
 | ||||
| namespace OpenSim.Capabilities.Handlers | ||||
| { | ||||
|     public class GetTextureServerConnector : ServiceConnector | ||||
|  | @ -63,11 +62,8 @@ namespace OpenSim.Capabilities.Handlers | |||
|             if (m_AssetService == null) | ||||
|                 throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName)); | ||||
| 
 | ||||
|             string rurl = serverConfig.GetString("GetTextureRedirectURL"); | ||||
|             ; | ||||
|             server.AddStreamHandler( | ||||
|                 new GetTextureRobustHandler("/CAPS/GetTexture", m_AssetService, "GetTexture", null, rurl)); | ||||
|             server.AddStreamHandler(new GetTextureHandler("/CAPS/GetTexture/" /*+ UUID.Random() */, m_AssetService)); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -37,12 +37,12 @@ using OpenSim.Framework; | |||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Region.Framework.Scenes; | ||||
| using OpenSim.Tests.Common; | ||||
| using OpenSim.Tests.Common.Mock; | ||||
| 
 | ||||
| /* | ||||
| namespace OpenSim.Capabilities.Handlers.GetTexture.Tests | ||||
| { | ||||
|     [TestFixture] | ||||
|     public class GetTextureHandlerTests : OpenSimTestCase | ||||
|     public class GetTextureHandlerTests | ||||
|     { | ||||
|         [Test] | ||||
|         public void TestTextureNotFound() | ||||
|  | @ -50,9 +50,9 @@ namespace OpenSim.Capabilities.Handlers.GetTexture.Tests | |||
|             TestHelpers.InMethod(); | ||||
| 
 | ||||
|             // Overkill - we only really need the asset service, not a whole scene. | ||||
|             Scene scene = new SceneHelpers().SetupScene(); | ||||
|             Scene scene = SceneHelpers.SetupScene(); | ||||
| 
 | ||||
|             GetTextureHandler handler = new GetTextureHandler("/gettexture", scene.AssetService, "TestGetTexture", null, null); | ||||
|             GetTextureHandler handler = new GetTextureHandler(null, scene.AssetService); | ||||
|             TestOSHttpRequest req = new TestOSHttpRequest(); | ||||
|             TestOSHttpResponse resp = new TestOSHttpResponse(); | ||||
|             req.Url = new Uri("http://localhost/?texture_id=00000000-0000-1111-9999-000000000012"); | ||||
|  | @ -60,5 +60,4 @@ namespace OpenSim.Capabilities.Handlers.GetTexture.Tests | |||
|             Assert.That(resp.StatusCode, Is.EqualTo((int)System.Net.HttpStatusCode.NotFound)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| */ | ||||
| } | ||||
|  | @ -1,33 +0,0 @@ | |||
| using System.Reflection; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Runtime.InteropServices; | ||||
| 
 | ||||
| // General Information about an assembly is controlled through the following | ||||
| // set of attributes. Change these attribute values to modify the information | ||||
| // associated with an assembly. | ||||
| [assembly: AssemblyTitle("OpenSim.Capabilities.Handlers")] | ||||
| [assembly: AssemblyDescription("")] | ||||
| [assembly: AssemblyConfiguration("")] | ||||
| [assembly: AssemblyCompany("http://opensimulator.org")] | ||||
| [assembly: AssemblyProduct("OpenSim")] | ||||
| [assembly: AssemblyCopyright("OpenSimulator developers")] | ||||
| [assembly: AssemblyTrademark("")] | ||||
| [assembly: AssemblyCulture("")] | ||||
| 
 | ||||
| // Setting ComVisible to false makes the types in this assembly not visible | ||||
| // to COM components.  If you need to access a type in this assembly from | ||||
| // COM, set the ComVisible attribute to true on that type. | ||||
| [assembly: ComVisible(false)] | ||||
| 
 | ||||
| // The following GUID is for the ID of the typelib if this project is exposed to COM | ||||
| [assembly: Guid("32350823-e1df-45e3-b7fa-0a58b4372433")] | ||||
| 
 | ||||
| // Version information for an assembly consists of the following four values: | ||||
| // | ||||
| //      Major Version | ||||
| //      Minor Version | ||||
| //      Build Number | ||||
| //      Revision | ||||
| // | ||||
| [assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)] | ||||
| 
 | ||||
|  | @ -0,0 +1,181 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections; | ||||
| using System.Collections.Specialized; | ||||
| using System.Drawing; | ||||
| using System.Drawing.Imaging; | ||||
| using System.Reflection; | ||||
| using System.IO; | ||||
| using System.Web; | ||||
| using log4net; | ||||
| using Nini.Config; | ||||
| using OpenMetaverse; | ||||
| using OpenMetaverse.StructuredData; | ||||
| using OpenMetaverse.Imaging; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Capabilities; | ||||
| using OpenSim.Framework.Servers; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Region.Framework.Interfaces; | ||||
| using OpenSim.Services.Interfaces; | ||||
| using Caps = OpenSim.Framework.Capabilities.Caps; | ||||
| 
 | ||||
| namespace OpenSim.Capabilities.Handlers | ||||
| { | ||||
|     public class UploadBakedTextureHandler | ||||
|     { | ||||
|         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private Caps m_HostCapsObj; | ||||
|         private IAssetService m_assetService; | ||||
|         private bool m_persistBakedTextures; | ||||
| 
 | ||||
|         public UploadBakedTextureHandler(Caps caps, IAssetService assetService, bool persistBakedTextures) | ||||
|         { | ||||
|             m_HostCapsObj = caps; | ||||
|             m_assetService = assetService; | ||||
|             m_persistBakedTextures = persistBakedTextures; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Handle a request from the client for a Uri to upload a baked texture. | ||||
|         /// </summary> | ||||
|         /// <param name="request"></param> | ||||
|         /// <param name="path"></param> | ||||
|         /// <param name="param"></param> | ||||
|         /// <param name="httpRequest"></param> | ||||
|         /// <param name="httpResponse"></param> | ||||
|         /// <returns>The upload response if the request is successful, null otherwise.</returns> | ||||
|         public string UploadBakedTexture( | ||||
|             string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; | ||||
|                 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); | ||||
| 
 | ||||
|                 BakedTextureUploader uploader = | ||||
|                     new BakedTextureUploader(capsBase + uploaderPath, m_HostCapsObj.HttpListener); | ||||
|                 uploader.OnUpLoad += BakedTextureUploaded; | ||||
| 
 | ||||
|                 m_HostCapsObj.HttpListener.AddStreamHandler( | ||||
|                         new BinaryStreamHandler("POST", capsBase + uploaderPath, | ||||
|                         uploader.uploaderCaps)); | ||||
| 
 | ||||
|                 string protocol = "http://"; | ||||
| 
 | ||||
|                 if (m_HostCapsObj.SSLCaps) | ||||
|                     protocol = "https://"; | ||||
| 
 | ||||
|                 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + | ||||
|                         m_HostCapsObj.Port.ToString() + capsBase + uploaderPath; | ||||
| 
 | ||||
|                 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); | ||||
|                 uploadResponse.uploader = uploaderURL; | ||||
|                 uploadResponse.state = "upload"; | ||||
| 
 | ||||
|                 return LLSDHelpers.SerialiseLLSDReply(uploadResponse); | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 m_log.ErrorFormat("[UPLOAD BAKED TEXTURE HANDLER]: {0}{1}", e.Message, e.StackTrace); | ||||
|             } | ||||
| 
 | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Called when a baked texture has been successfully uploaded by a client. | ||||
|         /// </summary> | ||||
|         /// <param name="assetID"></param> | ||||
|         /// <param name="data"></param> | ||||
|         private void BakedTextureUploaded(UUID assetID, byte[] data) | ||||
|         { | ||||
| //            m_log.DebugFormat("[UPLOAD BAKED TEXTURE HANDLER]: Received baked texture {0}", assetID.ToString()); | ||||
| 
 | ||||
|             AssetBase asset; | ||||
|             asset = new AssetBase(assetID, "Baked Texture", (sbyte)AssetType.Texture, m_HostCapsObj.AgentID.ToString()); | ||||
|             asset.Data = data; | ||||
|             asset.Temporary = true; | ||||
|             asset.Local = !m_persistBakedTextures; // Local assets aren't persisted, non-local are | ||||
|             m_assetService.Store(asset); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     class BakedTextureUploader | ||||
|     { | ||||
| //        private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         public event Action<UUID, byte[]> OnUpLoad; | ||||
| 
 | ||||
|         private string uploaderPath = String.Empty; | ||||
|         private UUID newAssetID; | ||||
|         private IHttpServer httpListener; | ||||
| 
 | ||||
|         public BakedTextureUploader(string path, IHttpServer httpServer) | ||||
|         { | ||||
|             newAssetID = UUID.Random(); | ||||
|             uploaderPath = path; | ||||
|             httpListener = httpServer; | ||||
|             //                m_log.InfoFormat("[CAPS] baked texture upload starting for {0}",newAssetID); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Handle raw uploaded baked texture data. | ||||
|         /// </summary> | ||||
|         /// <param name="data"></param> | ||||
|         /// <param name="path"></param> | ||||
|         /// <param name="param"></param> | ||||
|         /// <returns></returns> | ||||
|         public string uploaderCaps(byte[] data, string path, string param) | ||||
|         { | ||||
|             Action<UUID, byte[]> handlerUpLoad = OnUpLoad; | ||||
| 
 | ||||
|             // Don't do this asynchronously, otherwise it's possible for the client to send set appearance information | ||||
|             // on another thread which might send out avatar updates before the asset has been put into the asset | ||||
|             // service. | ||||
|             if (handlerUpLoad != null) | ||||
|                 handlerUpLoad(newAssetID, data); | ||||
| 
 | ||||
|             string res = String.Empty; | ||||
|             LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); | ||||
|             uploadComplete.new_asset = newAssetID.ToString(); | ||||
|             uploadComplete.new_inventory_item = UUID.Zero; | ||||
|             uploadComplete.state = "complete"; | ||||
| 
 | ||||
|             res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); | ||||
| 
 | ||||
|             httpListener.RemoveStreamHandler("POST", uploaderPath); | ||||
| 
 | ||||
| //            m_log.DebugFormat("[BAKED TEXTURE UPLOADER]: baked texture upload completed for {0}", newAssetID); | ||||
| 
 | ||||
|             return res; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,412 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| using System.Reflection; | ||||
| using log4net; | ||||
| using Nini.Config; | ||||
| using OpenMetaverse; | ||||
| using OpenMetaverse.StructuredData; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Capabilities; | ||||
| using OpenSim.Region.Framework.Interfaces; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Services.Interfaces; | ||||
| using Caps = OpenSim.Framework.Capabilities.Caps; | ||||
| 
 | ||||
| namespace OpenSim.Capabilities.Handlers | ||||
| { | ||||
|     public class WebFetchInvDescHandler  | ||||
|     { | ||||
|         private static readonly ILog m_log = | ||||
|             LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         private IInventoryService m_InventoryService; | ||||
|         private ILibraryService m_LibraryService; | ||||
| //        private object m_fetchLock = new Object(); | ||||
| 
 | ||||
|         public WebFetchInvDescHandler(IInventoryService invService, ILibraryService libService)  | ||||
|         { | ||||
|             m_InventoryService = invService; | ||||
|             m_LibraryService = libService; | ||||
|         } | ||||
| 
 | ||||
|         public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||||
|         { | ||||
| //            lock (m_fetchLock) | ||||
| //            { | ||||
| //                m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Received request {0}", request); | ||||
|      | ||||
|                 // nasty temporary hack here, the linden client falsely | ||||
|                 // identifies the uuid 00000000-0000-0000-0000-000000000000 | ||||
|                 // as a string which breaks us | ||||
|                 // | ||||
|                 // correctly mark it as a uuid | ||||
|                 // | ||||
|                 request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>"); | ||||
|      | ||||
|                 // another hack <integer>1</integer> results in a | ||||
|                 // System.ArgumentException: Object type System.Int32 cannot | ||||
|                 // be converted to target type: System.Boolean | ||||
|                 // | ||||
|                 request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>"); | ||||
|                 request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>"); | ||||
|      | ||||
|                 Hashtable hash = new Hashtable(); | ||||
|                 try | ||||
|                 { | ||||
|                     hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); | ||||
|                 } | ||||
|                 catch (LLSD.LLSDParseException e) | ||||
|                 { | ||||
|                     m_log.ErrorFormat("[WEB FETCH INV DESC HANDLER]: Fetch error: {0}{1}" + e.Message, e.StackTrace); | ||||
|                     m_log.Error("Request: " + request); | ||||
|                 } | ||||
|      | ||||
|                 ArrayList foldersrequested = (ArrayList)hash["folders"]; | ||||
|      | ||||
|                 string response = ""; | ||||
| 
 | ||||
|                 for (int i = 0; i < foldersrequested.Count; i++) | ||||
|                 { | ||||
|                     string inventoryitemstr = ""; | ||||
|                     Hashtable inventoryhash = (Hashtable)foldersrequested[i]; | ||||
| 
 | ||||
|                     LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); | ||||
| 
 | ||||
|                     try | ||||
|                     { | ||||
|                         LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); | ||||
|                     } | ||||
|                     catch (Exception e) | ||||
|                     { | ||||
|                         m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e); | ||||
|                     } | ||||
|                     LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); | ||||
| 
 | ||||
|                     inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); | ||||
|                     inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", ""); | ||||
|                     inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", ""); | ||||
| 
 | ||||
|                     response += inventoryitemstr; | ||||
|                 } | ||||
| 
 | ||||
|                 if (response.Length == 0) | ||||
|                 { | ||||
|                     // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants. | ||||
|                     // Therefore, I'm concluding that the client only has so many threads available to do requests | ||||
|                     // and when a thread stalls..   is stays stalled. | ||||
|                     // Therefore we need to return something valid | ||||
|                     response = "<llsd><map><key>folders</key><array /></map></llsd>"; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>"; | ||||
|                 } | ||||
| 
 | ||||
| //                m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Replying to CAPS fetch inventory request"); | ||||
|                 //m_log.Debug("[WEB FETCH INV DESC HANDLER] "+response); | ||||
| 
 | ||||
|                 return response; | ||||
| 
 | ||||
| //            } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Construct an LLSD reply packet to a CAPS inventory request | ||||
|         /// </summary> | ||||
|         /// <param name="invFetch"></param> | ||||
|         /// <returns></returns> | ||||
|         private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch) | ||||
|         { | ||||
|             LLSDInventoryDescendents reply = new LLSDInventoryDescendents(); | ||||
|             LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents(); | ||||
|             contents.agent_id = invFetch.owner_id; | ||||
|             contents.owner_id = invFetch.owner_id; | ||||
|             contents.folder_id = invFetch.folder_id; | ||||
| 
 | ||||
|             reply.folders.Array.Add(contents); | ||||
|             InventoryCollection inv = new InventoryCollection(); | ||||
|             inv.Folders = new List<InventoryFolderBase>(); | ||||
|             inv.Items = new List<InventoryItemBase>(); | ||||
|             int version = 0; | ||||
| 
 | ||||
|             inv | ||||
|                 = Fetch( | ||||
|                     invFetch.owner_id, invFetch.folder_id, invFetch.owner_id, | ||||
|                     invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version); | ||||
| 
 | ||||
|             if (inv.Folders != null) | ||||
|             { | ||||
|                 foreach (InventoryFolderBase invFolder in inv.Folders) | ||||
|                 { | ||||
|                     contents.categories.Array.Add(ConvertInventoryFolder(invFolder)); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (inv.Items != null) | ||||
|             { | ||||
|                 foreach (InventoryItemBase invItem in inv.Items) | ||||
|                 { | ||||
|                     contents.items.Array.Add(ConvertInventoryItem(invItem)); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             contents.descendents = contents.items.Array.Count + contents.categories.Array.Count; | ||||
|             contents.version = version; | ||||
| 
 | ||||
| //            m_log.DebugFormat( | ||||
| //                "[WEB FETCH INV DESC HANDLER]: Replying to request for folder {0} (fetch items {1}, fetch folders {2}) with {3} items and {4} folders for agent {5}", | ||||
| //                invFetch.folder_id, | ||||
| //                invFetch.fetch_items, | ||||
| //                invFetch.fetch_folders, | ||||
| //                contents.items.Array.Count, | ||||
| //                contents.categories.Array.Count, | ||||
| //                invFetch.owner_id); | ||||
| 
 | ||||
|             return reply; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Handle the caps inventory descendents fetch. | ||||
|         /// </summary> | ||||
|         /// <param name="agentID"></param> | ||||
|         /// <param name="folderID"></param> | ||||
|         /// <param name="ownerID"></param> | ||||
|         /// <param name="fetchFolders"></param> | ||||
|         /// <param name="fetchItems"></param> | ||||
|         /// <param name="sortOrder"></param> | ||||
|         /// <param name="version"></param> | ||||
|         /// <returns>An empty InventoryCollection if the inventory look up failed</returns> | ||||
|         private InventoryCollection Fetch( | ||||
|             UUID agentID, UUID folderID, UUID ownerID, | ||||
|             bool fetchFolders, bool fetchItems, int sortOrder, out int version) | ||||
|         { | ||||
| //            m_log.DebugFormat( | ||||
| //                "[WEB FETCH INV DESC HANDLER]: Fetching folders ({0}), items ({1}) from {2} for agent {3}", | ||||
| //                fetchFolders, fetchItems, folderID, agentID); | ||||
| 
 | ||||
|             // FIXME MAYBE: We're not handling sortOrder! | ||||
| 
 | ||||
|             version = 0; | ||||
|             InventoryFolderImpl fold; | ||||
|             if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null && agentID == m_LibraryService.LibraryRootFolder.Owner) | ||||
|             { | ||||
|                 if ((fold = m_LibraryService.LibraryRootFolder.FindFolder(folderID)) != null) | ||||
|                 { | ||||
|                     InventoryCollection ret = new InventoryCollection(); | ||||
|                     ret.Folders = new List<InventoryFolderBase>(); | ||||
|                     ret.Items = fold.RequestListOfItems(); | ||||
| 
 | ||||
|                     return ret; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             InventoryCollection contents = new InventoryCollection(); | ||||
| 
 | ||||
|             if (folderID != UUID.Zero) | ||||
|             { | ||||
|                 contents = m_InventoryService.GetFolderContent(agentID, folderID); | ||||
|                 InventoryFolderBase containingFolder = new InventoryFolderBase(); | ||||
|                 containingFolder.ID = folderID; | ||||
|                 containingFolder.Owner = agentID; | ||||
|                 containingFolder = m_InventoryService.GetFolder(containingFolder); | ||||
| 
 | ||||
|                 if (containingFolder != null) | ||||
|                 { | ||||
| //                    m_log.DebugFormat( | ||||
| //                        "[WEB FETCH INV DESC HANDLER]: Retrieved folder {0} {1} for agent id {2}", | ||||
| //                        containingFolder.Name, containingFolder.ID, agentID); | ||||
| 
 | ||||
|                     version = containingFolder.Version; | ||||
| 
 | ||||
| //                    if (fetchItems) | ||||
| //                    { | ||||
| //                        List<InventoryItemBase> linkedItemsToAdd = new List<InventoryItemBase>(); | ||||
| // | ||||
| //                        foreach (InventoryItemBase item in contents.Items) | ||||
| //                        { | ||||
| //                            if (item.AssetType == (int)AssetType.Link) | ||||
| //                            { | ||||
| //                                InventoryItemBase linkedItem = m_InventoryService.GetItem(new InventoryItemBase(item.AssetID)); | ||||
| // | ||||
| //                                // Take care of genuinely broken links where the target doesn't exist | ||||
| //                                // HACK: Also, don't follow up links that just point to other links.  In theory this is legitimate, | ||||
| //                                // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles | ||||
| //                                // rather than having to keep track of every folder requested in the recursion. | ||||
| //                                if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link) | ||||
| //                                    linkedItemsToAdd.Insert(0, linkedItem); | ||||
| //                            } | ||||
| //                        } | ||||
| // | ||||
| //                        foreach (InventoryItemBase linkedItem in linkedItemsToAdd) | ||||
| //                        { | ||||
| //                            m_log.DebugFormat( | ||||
| //                                "[WEB FETCH INV DESC HANDLER]: Inserted linked item {0} for link in folder {1} for agent {2}", | ||||
| //                                linkedItem.Name, folderID, agentID); | ||||
| // | ||||
| //                            contents.Items.Add(linkedItem); | ||||
| //                        } | ||||
| // | ||||
| //                        // If the folder requested contains links, then we need to send those folders first, otherwise the links | ||||
| //                        // will be broken in the viewer. | ||||
| //                        HashSet<UUID> linkedItemFolderIdsToSend = new HashSet<UUID>(); | ||||
| //                        foreach (InventoryItemBase item in contents.Items) | ||||
| //                        { | ||||
| //                            if (item.AssetType == (int)AssetType.Link) | ||||
| //                            { | ||||
| //                                InventoryItemBase linkedItem = m_InventoryService.GetItem(new InventoryItemBase(item.AssetID)); | ||||
| // | ||||
| //                                // Take care of genuinely broken links where the target doesn't exist | ||||
| //                                // HACK: Also, don't follow up links that just point to other links.  In theory this is legitimate, | ||||
| //                                // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles | ||||
| //                                // rather than having to keep track of every folder requested in the recursion. | ||||
| //                                if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link) | ||||
| //                                { | ||||
| //                                    // We don't need to send the folder if source and destination of the link are in the same | ||||
| //                                    // folder. | ||||
| //                                    if (linkedItem.Folder != containingFolder.ID) | ||||
| //                                        linkedItemFolderIdsToSend.Add(linkedItem.Folder); | ||||
| //                                } | ||||
| //                            } | ||||
| //                        } | ||||
| //     | ||||
| //                        foreach (UUID linkedItemFolderId in linkedItemFolderIdsToSend) | ||||
| //                        { | ||||
| //                            m_log.DebugFormat( | ||||
| //                                "[WEB FETCH INV DESC HANDLER]: Recursively fetching folder {0} linked by item in folder {1} for agent {2}", | ||||
| //                                linkedItemFolderId, folderID, agentID); | ||||
| // | ||||
| //                            int dummyVersion; | ||||
| //                            InventoryCollection linkedCollection | ||||
| //                                = Fetch( | ||||
| //                                    agentID, linkedItemFolderId, ownerID, fetchFolders, fetchItems, sortOrder, out dummyVersion); | ||||
| // | ||||
| //                            InventoryFolderBase linkedFolder = new InventoryFolderBase(linkedItemFolderId); | ||||
| //                            linkedFolder.Owner = agentID; | ||||
| //                            linkedFolder = m_InventoryService.GetFolder(linkedFolder); | ||||
| // | ||||
| ////                            contents.Folders.AddRange(linkedCollection.Folders); | ||||
| // | ||||
| //                            contents.Folders.Add(linkedFolder); | ||||
| //                            contents.Items.AddRange(linkedCollection.Items); | ||||
| //                        } | ||||
| //                    } | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 // Lost items don't really need a version | ||||
|                 version = 1; | ||||
|             } | ||||
| 
 | ||||
|             return contents; | ||||
| 
 | ||||
|         } | ||||
|         /// <summary> | ||||
|         /// Convert an internal inventory folder object into an LLSD object. | ||||
|         /// </summary> | ||||
|         /// <param name="invFolder"></param> | ||||
|         /// <returns></returns> | ||||
|         private LLSDInventoryFolder ConvertInventoryFolder(InventoryFolderBase invFolder) | ||||
|         { | ||||
|             LLSDInventoryFolder llsdFolder = new LLSDInventoryFolder(); | ||||
|             llsdFolder.folder_id = invFolder.ID; | ||||
|             llsdFolder.parent_id = invFolder.ParentID; | ||||
|             llsdFolder.name = invFolder.Name; | ||||
| 
 | ||||
|             if (invFolder.Type == (short)AssetType.Unknown || !Enum.IsDefined(typeof(AssetType), (sbyte)invFolder.Type)) | ||||
|                 llsdFolder.type = "-1"; | ||||
|             else | ||||
|                 llsdFolder.type = Utils.AssetTypeToString((AssetType)invFolder.Type); | ||||
|             llsdFolder.preferred_type = "-1"; | ||||
| 
 | ||||
|             return llsdFolder; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Convert an internal inventory item object into an LLSD object. | ||||
|         /// </summary> | ||||
|         /// <param name="invItem"></param> | ||||
|         /// <returns></returns> | ||||
|         private LLSDInventoryItem ConvertInventoryItem(InventoryItemBase invItem) | ||||
|         { | ||||
|             LLSDInventoryItem llsdItem = new LLSDInventoryItem(); | ||||
|             llsdItem.asset_id = invItem.AssetID; | ||||
|             llsdItem.created_at = invItem.CreationDate; | ||||
|             llsdItem.desc = invItem.Description; | ||||
|             llsdItem.flags = (int)invItem.Flags; | ||||
|             llsdItem.item_id = invItem.ID; | ||||
|             llsdItem.name = invItem.Name; | ||||
|             llsdItem.parent_id = invItem.Folder; | ||||
| 
 | ||||
|             try | ||||
|             { | ||||
|                 llsdItem.type = Utils.AssetTypeToString((AssetType)invItem.AssetType); | ||||
|                 llsdItem.inv_type = Utils.InventoryTypeToString((InventoryType)invItem.InvType); | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 m_log.ErrorFormat( | ||||
|                     "[WEB FETCH INV DESC HANDLER]: Problem setting asset {0} inventory {1} types while converting inventory item {2}: {3}", | ||||
|                     invItem.AssetType, invItem.InvType, invItem.Name, e.Message); | ||||
|             } | ||||
| 
 | ||||
|             llsdItem.permissions = new LLSDPermissions(); | ||||
|             llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid; | ||||
|             llsdItem.permissions.base_mask = (int)invItem.CurrentPermissions; | ||||
|             llsdItem.permissions.everyone_mask = (int)invItem.EveryOnePermissions; | ||||
|             llsdItem.permissions.group_id = invItem.GroupID; | ||||
|             llsdItem.permissions.group_mask = (int)invItem.GroupPermissions; | ||||
|             llsdItem.permissions.is_owner_group = invItem.GroupOwned; | ||||
|             llsdItem.permissions.next_owner_mask = (int)invItem.NextPermissions; | ||||
|             llsdItem.permissions.owner_id = invItem.Owner; | ||||
|             llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions; | ||||
|             llsdItem.sale_info = new LLSDSaleInfo(); | ||||
|             llsdItem.sale_info.sale_price = invItem.SalePrice; | ||||
|             switch (invItem.SaleType) | ||||
|             { | ||||
|                 default: | ||||
|                     llsdItem.sale_info.sale_type = "not"; | ||||
|                     break; | ||||
|                 case 1: | ||||
|                     llsdItem.sale_info.sale_type = "original"; | ||||
|                     break; | ||||
|                 case 2: | ||||
|                     llsdItem.sale_info.sale_type = "copy"; | ||||
|                     break; | ||||
|                 case 3: | ||||
|                     llsdItem.sale_info.sale_type = "contents"; | ||||
|                     break; | ||||
|             } | ||||
| 
 | ||||
|             return llsdItem; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -29,22 +29,19 @@ using System; | |||
| using Nini.Config; | ||||
| using OpenSim.Server.Base; | ||||
| using OpenSim.Services.Interfaces; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Server.Handlers.Base; | ||||
| using OpenMetaverse; | ||||
| using OpenMetaverse.StructuredData; | ||||
| 
 | ||||
| 
 | ||||
| namespace OpenSim.Capabilities.Handlers | ||||
| { | ||||
|     public class FetchInvDescServerConnector : ServiceConnector | ||||
|     public class WebFetchInvDescServerConnector : ServiceConnector | ||||
|     { | ||||
|         private IInventoryService m_InventoryService; | ||||
|         private ILibraryService m_LibraryService; | ||||
|         private string m_ConfigName = "CapsService"; | ||||
| 
 | ||||
|         public FetchInvDescServerConnector(IConfigSource config, IHttpServer server, string configName) : | ||||
|         public WebFetchInvDescServerConnector(IConfigSource config, IHttpServer server, string configName) : | ||||
|                 base(config, server, configName) | ||||
|         { | ||||
|             if (configName != String.Empty) | ||||
|  | @ -70,16 +67,10 @@ namespace OpenSim.Capabilities.Handlers | |||
|             m_LibraryService = | ||||
|                     ServerUtils.LoadPlugin<ILibraryService>(libService, args); | ||||
| 
 | ||||
|             ExpiringKey<UUID> m_badRequests = new ExpiringKey<UUID>(30000); | ||||
| 
 | ||||
|             FetchInvDescHandler webFetchHandler = new FetchInvDescHandler(m_InventoryService, m_LibraryService, null); | ||||
|             ISimpleStreamHandler reqHandler | ||||
|                 = new SimpleStreamHandler("/CAPS/WebFetchInvDesc/", delegate(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||||
|                 {  | ||||
|                     webFetchHandler.FetchInventoryDescendentsRequest(httpRequest, httpResponse, m_badRequests); | ||||
|                 }); | ||||
| 
 | ||||
|             server.AddSimpleStreamHandler(reqHandler); | ||||
|             WebFetchInvDescHandler webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService); | ||||
|             IRequestHandler reqHandler = new RestStreamHandler("POST", "/CAPS/WebFetchInvDesc/" /*+ UUID.Random()*/, webFetchHandler.FetchInventoryDescendentsRequest); | ||||
|             server.AddStreamHandler(reqHandler); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | @ -68,10 +68,7 @@ namespace OpenSim.Framework.Capabilities | |||
|         /// <returns></returns> | ||||
|         public static object LLSDDeserialize(byte[] b) | ||||
|         { | ||||
|             using (MemoryStream ms = new MemoryStream(b, false)) | ||||
|             { | ||||
|                 return LLSDDeserialize(ms); | ||||
|             } | ||||
|             return LLSDDeserialize(new MemoryStream(b, false)); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|  | @ -81,23 +78,21 @@ namespace OpenSim.Framework.Capabilities | |||
|         /// <returns></returns> | ||||
|         public static object LLSDDeserialize(Stream st) | ||||
|         { | ||||
|             using (XmlTextReader reader = new XmlTextReader(st)) | ||||
|             { | ||||
|                 reader.Read(); | ||||
|                 SkipWS(reader); | ||||
|             XmlTextReader reader = new XmlTextReader(st); | ||||
|             reader.Read(); | ||||
|             SkipWS(reader); | ||||
| 
 | ||||
|                 if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "llsd") | ||||
|                     throw new LLSDParseException("Expected <llsd>"); | ||||
|             if (reader.NodeType != XmlNodeType.Element || reader.LocalName != "llsd") | ||||
|                 throw new LLSDParseException("Expected <llsd>"); | ||||
| 
 | ||||
|                 reader.Read(); | ||||
|                 object ret = LLSDParseOne(reader); | ||||
|                 SkipWS(reader); | ||||
|             reader.Read(); | ||||
|             object ret = LLSDParseOne(reader); | ||||
|             SkipWS(reader); | ||||
| 
 | ||||
|                 if (reader.NodeType != XmlNodeType.EndElement || reader.LocalName != "llsd") | ||||
|                     throw new LLSDParseException("Expected </llsd>"); | ||||
|             if (reader.NodeType != XmlNodeType.EndElement || reader.LocalName != "llsd") | ||||
|                 throw new LLSDParseException("Expected </llsd>"); | ||||
| 
 | ||||
|                 return ret; | ||||
|             } | ||||
|             return ret; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|  | @ -107,17 +102,17 @@ namespace OpenSim.Framework.Capabilities | |||
|         /// <returns></returns> | ||||
|         public static byte[] LLSDSerialize(object obj) | ||||
|         { | ||||
|             using(StringWriter sw = new StringWriter()) | ||||
|             using(XmlTextWriter writer = new XmlTextWriter(sw)) | ||||
|             { | ||||
|                 writer.Formatting = Formatting.None; | ||||
|             StringWriter sw = new StringWriter(); | ||||
|             XmlTextWriter writer = new XmlTextWriter(sw); | ||||
|             writer.Formatting = Formatting.None; | ||||
| 
 | ||||
|                 writer.WriteStartElement(String.Empty, "llsd", String.Empty); | ||||
|                 LLSDWriteOne(writer, obj); | ||||
|                 writer.WriteEndElement(); | ||||
|                 writer.Flush(); | ||||
|                 return Util.UTF8.GetBytes(sw.ToString()); | ||||
|             }            | ||||
|             writer.WriteStartElement(String.Empty, "llsd", String.Empty); | ||||
|             LLSDWriteOne(writer, obj); | ||||
|             writer.WriteEndElement(); | ||||
| 
 | ||||
|             writer.Close(); | ||||
| 
 | ||||
|             return Util.UTF8.GetBytes(sw.ToString()); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|  | @ -566,7 +561,7 @@ namespace OpenSim.Framework.Capabilities | |||
|                         endPos = FindEnd(llsd, 1); | ||||
| 
 | ||||
|                         if (Double.TryParse(llsd.Substring(1, endPos - 1), NumberStyles.Float, | ||||
|                                             Culture.NumberFormatInfo, out value)) | ||||
|                                             Utils.EnUsCulture.NumberFormat, out value)) | ||||
|                             return value; | ||||
|                         else | ||||
|                             throw new LLSDParseException("Failed to parse double value type"); | ||||
|  |  | |||
|  | @ -30,20 +30,13 @@ using OpenMetaverse; | |||
| 
 | ||||
| namespace OpenSim.Framework.Capabilities | ||||
| { | ||||
| 
 | ||||
|     [LLSDType("MAP")] | ||||
|     public class LLSDAssetUploadComplete | ||||
|     { | ||||
|         public string new_asset = String.Empty; | ||||
|         public UUID new_inventory_item = UUID.Zero; | ||||
| //        public UUID new_texture_folder_id = UUID.Zero; | ||||
|         public string state = String.Empty; | ||||
|         public LLSDAssetUploadError error = null; | ||||
|         //public bool success = false; | ||||
|         public int new_next_owner_mask = 0; | ||||
|         public int new_group_mask = 0; | ||||
|         public int new_everyone_mask = 0; | ||||
|         public int inventory_item_flags = 0; | ||||
| 
 | ||||
|         public LLSDAssetUploadComplete() | ||||
|         { | ||||
|  |  | |||
|  | @ -30,28 +30,15 @@ using OpenMetaverse; | |||
| 
 | ||||
| namespace OpenSim.Framework.Capabilities | ||||
| { | ||||
|     [OSDMap] | ||||
|     public class LLSDAssetResource | ||||
|     { | ||||
|         public OSDArray instance_list = new OSDArray(); | ||||
|         public OSDArray texture_list = new OSDArray(); | ||||
|         public OSDArray mesh_list = new OSDArray(); | ||||
|         public string metric = String.Empty; | ||||
|     } | ||||
| 
 | ||||
|     [OSDMap] | ||||
|     public class LLSDAssetUploadRequest | ||||
|     { | ||||
|         public string asset_type = String.Empty; | ||||
|         public string description = String.Empty; | ||||
|         public UUID folder_id = UUID.Zero; | ||||
|         public UUID texture_folder_id = UUID.Zero; | ||||
|         public int next_owner_mask = 0; | ||||
|         public int group_mask = 0; | ||||
|         public int everyone_mask = 0; | ||||
|         public string inventory_type = String.Empty; | ||||
|         public string name = String.Empty; | ||||
|         public LLSDAssetResource asset_resources = new LLSDAssetResource(); | ||||
| 
 | ||||
|         public LLSDAssetUploadRequest() | ||||
|         { | ||||
|         } | ||||
|  |  | |||
|  | @ -26,51 +26,20 @@ | |||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using OpenMetaverse; | ||||
| 
 | ||||
| namespace OpenSim.Framework.Capabilities | ||||
| { | ||||
|     [OSDMap] | ||||
|     public class LLSDAssetUploadError | ||||
|     { | ||||
|         public string message = String.Empty; | ||||
|         public UUID identifier = UUID.Zero; | ||||
|     } | ||||
| 
 | ||||
|     [OSDMap] | ||||
|     public class LLSDAssetUploadResponsePricebrkDown | ||||
|     { | ||||
|         public int mesh_streaming; | ||||
|         public int mesh_physics; | ||||
|         public int mesh_instance; | ||||
|         public int texture; | ||||
|         public int model; | ||||
|     } | ||||
| 
 | ||||
|     [OSDMap] | ||||
|     public class LLSDAssetUploadResponseData | ||||
|     { | ||||
|         public double resource_cost; | ||||
|         public double model_streaming_cost; | ||||
|         public double simulation_cost; | ||||
|         public double physics_cost; | ||||
|         public LLSDAssetUploadResponsePricebrkDown upload_price_breakdown = new LLSDAssetUploadResponsePricebrkDown(); | ||||
|     } | ||||
| 
 | ||||
|     [OSDMap] | ||||
|     public class LLSDAssetUploadResponse | ||||
|     { | ||||
|         public string uploader = String.Empty; | ||||
|         public string state = String.Empty; | ||||
|         public int upload_price = 0; | ||||
|         public LLSDAssetUploadResponseData data = null; | ||||
|         public LLSDAssetUploadError error = null; | ||||
| 
 | ||||
|         public LLSDAssetUploadResponse() | ||||
|         { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     [OSDMap] | ||||
|     public class LLSDNewFileAngentInventoryVariablePriceReplyResponse | ||||
|     { | ||||
|  | @ -78,7 +47,7 @@ namespace OpenSim.Framework.Capabilities | |||
|         public string state; | ||||
|         public int upload_price; | ||||
|         public string rsvp; | ||||
| 
 | ||||
|          | ||||
|         public LLSDNewFileAngentInventoryVariablePriceReplyResponse() | ||||
|         { | ||||
|             state = "confirm_upload"; | ||||
|  |  | |||
|  | @ -1,51 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) Contributors, http://opensimulator.org/ | ||||
|  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  *     * Redistributions of source code must retain the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer. | ||||
|  *     * Redistributions in binary form must reproduce the above copyright | ||||
|  *       notice, this list of conditions and the following disclaimer in the | ||||
|  *       documentation and/or other materials provided with the distribution. | ||||
|  *     * Neither the name of the OpenSimulator Project nor the | ||||
|  *       names of its contributors may be used to endorse or promote products | ||||
|  *       derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
|  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
|  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using OpenMetaverse; | ||||
| 
 | ||||
| namespace OpenSim.Framework.Capabilities | ||||
| { | ||||
|     [OSDMap] | ||||
|     public class LLSDAvatarPicker | ||||
|     { | ||||
|         public string next_page_url; | ||||
|         // an array of LLSDPerson | ||||
|         public OSDArray agents = new OSDArray(); | ||||
|     } | ||||
| 
 | ||||
|     [OSDMap] | ||||
|     public class LLSDPerson | ||||
|     { | ||||
|         public string username; | ||||
|         public string display_name; | ||||
|         //'display_name_next_update':d"1970-01-01T00:00:00Z" | ||||
|         public string legacy_first_name; | ||||
|         public string legacy_last_name; | ||||
|         public UUID id; | ||||
|         public bool is_display_name_default; | ||||
|     } | ||||
| } | ||||
|  | @ -30,7 +30,6 @@ using System.Collections; | |||
| using System.IO; | ||||
| using System.Reflection; | ||||
| using System.Xml; | ||||
| using OpenMetaverse; | ||||
| 
 | ||||
| namespace OpenSim.Framework.Capabilities | ||||
| { | ||||
|  | @ -41,32 +40,17 @@ namespace OpenSim.Framework.Capabilities | |||
| 
 | ||||
|         public static string SerialiseLLSDReply(object obj) | ||||
|         { | ||||
|             using(StringWriter sw = new StringWriter()) | ||||
|             using(XmlTextWriter writer = new XmlTextWriter(sw)) | ||||
|             { | ||||
|                 writer.Formatting = Formatting.None; | ||||
|                 writer.WriteStartElement(String.Empty, "llsd", String.Empty); | ||||
|                 SerializeOSDType(writer, obj); | ||||
|                 writer.WriteEndElement(); | ||||
|                 writer.Flush(); | ||||
|             StringWriter sw = new StringWriter(); | ||||
|             XmlTextWriter writer = new XmlTextWriter(sw); | ||||
|             writer.Formatting = Formatting.None; | ||||
|             writer.WriteStartElement(String.Empty, "llsd", String.Empty); | ||||
|             SerializeOSDType(writer, obj); | ||||
|             writer.WriteEndElement(); | ||||
|             writer.Close(); | ||||
| 
 | ||||
|             //m_log.DebugFormat("[LLSD Helpers]: Generated serialized LLSD reply {0}", sw.ToString()); | ||||
| 
 | ||||
|                 return sw.ToString(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public static string SerialiseLLSDReplyNoHeader(object obj) | ||||
|         { | ||||
|             using(StringWriter sw = new StringWriter()) | ||||
|             using(XmlTextWriter writer = new XmlTextWriter(sw)) | ||||
|             { | ||||
|                 writer.Formatting = Formatting.None; | ||||
|                 SerializeOSDType(writer, obj); | ||||
|                 writer.Flush(); | ||||
|             //m_log.DebugFormat("[LLSD Helpers]: Generated serialized LLSD reply {0}", sw.ToString()); | ||||
| 
 | ||||
|                 return sw.ToString(); | ||||
|             } | ||||
|             return sw.ToString(); | ||||
|         } | ||||
| 
 | ||||
|         private static void SerializeOSDType(XmlTextWriter writer, object obj) | ||||
|  | @ -173,22 +157,6 @@ namespace OpenSim.Framework.Capabilities | |||
|                                     // the LLSD map/array types in the array need to be deserialised | ||||
|                                     // but first we need to know the right class to deserialise them into. | ||||
|                                 } | ||||
|                                 else if(enumerator.Value is Boolean && field.FieldType == typeof(int) ) | ||||
|                                 { | ||||
|                                     int i = (bool)enumerator.Value ? 1 : 0; | ||||
|                                     field.SetValue(obj, i); | ||||
|                                 } | ||||
|                                 else if(field.FieldType == typeof(bool) &&  enumerator.Value is int) | ||||
|                                 { | ||||
|                                     bool b = (int)enumerator.Value != 0; | ||||
|                                     field.SetValue(obj, b); | ||||
|                                 } | ||||
|                                 else if(field.FieldType == typeof(UUID) &&  enumerator.Value is string) | ||||
|                                 { | ||||
|                                     UUID u; | ||||
|                                     UUID.TryParse((string)enumerator.Value, out u); | ||||
|                                     field.SetValue(obj, u); | ||||
|                                 } | ||||
|                                 else | ||||
|                                 { | ||||
|                                     field.SetValue(obj, enumerator.Value); | ||||
|  |  | |||
|  | @ -35,8 +35,7 @@ namespace OpenSim.Framework.Capabilities | |||
|         public UUID folder_id; | ||||
|         public UUID parent_id; | ||||
|         public string name; | ||||
|         public int type; | ||||
|         public int preferred_type; | ||||
|         public int version; | ||||
|         public string type; | ||||
|         public string preferred_type; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -37,8 +37,8 @@ namespace OpenSim.Framework.Capabilities | |||
|         public UUID asset_id; | ||||
|         public UUID item_id; | ||||
|         public LLSDPermissions permissions; | ||||
|         public int type; | ||||
|         public int inv_type; | ||||
|         public string type; | ||||
|         public string inv_type; | ||||
|         public int flags; | ||||
| 
 | ||||
|         public LLSDSaleInfo sale_info; | ||||
|  | @ -65,7 +65,7 @@ namespace OpenSim.Framework.Capabilities | |||
|     public class LLSDSaleInfo | ||||
|     { | ||||
|         public int sale_price; | ||||
|         public int sale_type; | ||||
|         public string sale_type; | ||||
|     } | ||||
| 
 | ||||
|     [OSDMap] | ||||
|  | @ -87,12 +87,12 @@ namespace OpenSim.Framework.Capabilities | |||
|     [OSDMap] | ||||
|     public class LLSDInventoryFolderContents | ||||
|     { | ||||
|         public UUID agent_id; | ||||
|         public UUID agent_id;  | ||||
|         public int descendents; | ||||
|         public UUID folder_id; | ||||
|         public UUID folder_id;  | ||||
|         public OSDArray categories = new OSDArray(); | ||||
|         public OSDArray items = new OSDArray(); | ||||
|         public UUID owner_id; | ||||
|         public UUID owner_id;  | ||||
|         public int version; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -25,15 +25,17 @@ | |||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| using System; | ||||
| using OpenMetaverse; | ||||
| 
 | ||||
| namespace Robust32 | ||||
| namespace OpenSim.Framework.Capabilities | ||||
| { | ||||
|     class Program | ||||
|     [OSDMap] | ||||
|     public class LLSDItemUpdate | ||||
|     { | ||||
|         static void Main(string[] args) | ||||
|         public UUID item_id; | ||||
| 
 | ||||
|         public LLSDItemUpdate() | ||||
|         { | ||||
|                 global::OpenSim.Server.OpenSimServer.Main(args); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,51 @@ | |||
| /* | ||||
| * Copyright (c) Contributors, http://opensimulator.org/ | ||||
| * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
| * | ||||
| * Redistribution and use in source and binary forms, with or without | ||||
| * modification, are permitted provided that the following conditions are met: | ||||
| *     * Redistributions of source code must retain the above copyright | ||||
| *       notice, this list of conditions and the following disclaimer. | ||||
| *     * Redistributions in binary form must reproduce the above copyright | ||||
| *       notice, this list of conditions and the following disclaimer in the | ||||
| *       documentation and/or other materials provided with the distribution. | ||||
| *     * Neither the name of the OpenSimulator Project nor the | ||||
| *       names of its contributors may be used to endorse or promote products | ||||
| *       derived from this software without specific prior written permission. | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
| * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| * | ||||
| */ | ||||
| 
 | ||||
| using System.Collections; | ||||
| 
 | ||||
| namespace OpenSim.Framework.Capabilities | ||||
| { | ||||
|     [OSDMap] | ||||
|     public class LLSDParcelVoiceInfoResponse | ||||
|     { | ||||
|         public int parcel_local_id; | ||||
|         public string region_name; | ||||
|         public Hashtable voice_credentials; | ||||
| 
 | ||||
|         public LLSDParcelVoiceInfoResponse() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         public LLSDParcelVoiceInfoResponse(string region, int localID, Hashtable creds) | ||||
|         { | ||||
|             region_name = region; | ||||
|             parcel_local_id = localID; | ||||
|             voice_credentials = creds; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,42 @@ | |||
| /* | ||||
| * Copyright (c) Contributors, http://opensimulator.org/ | ||||
| * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
| * | ||||
| * Redistribution and use in source and binary forms, with or without | ||||
| * modification, are permitted provided that the following conditions are met: | ||||
| *     * Redistributions of source code must retain the above copyright | ||||
| *       notice, this list of conditions and the following disclaimer. | ||||
| *     * Redistributions in binary form must reproduce the above copyright | ||||
| *       notice, this list of conditions and the following disclaimer in the | ||||
| *       documentation and/or other materials provided with the distribution. | ||||
| *     * Neither the name of the OpenSimulator Project nor the | ||||
| *       names of its contributors may be used to endorse or promote products | ||||
| *       derived from this software without specific prior written permission. | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
| * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| * | ||||
| */ | ||||
| 
 | ||||
| using OpenMetaverse; | ||||
| 
 | ||||
| namespace OpenSim.Framework.Capabilities | ||||
| { | ||||
|     [LLSDType("MAP")] | ||||
|     public class LLSDRemoteParcelResponse | ||||
|     { | ||||
|         public UUID parcel_id; | ||||
| 
 | ||||
|         public LLSDRemoteParcelResponse() | ||||
|         { | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -39,16 +39,12 @@ namespace OpenSim.Framework.Capabilities | |||
|         private LLSDMethod<TRequest, TResponse> m_method; | ||||
| 
 | ||||
|         public LLSDStreamhandler(string httpMethod, string path, LLSDMethod<TRequest, TResponse> method) | ||||
|             : this(httpMethod, path, method, null, null) {} | ||||
| 
 | ||||
|         public LLSDStreamhandler( | ||||
|             string httpMethod, string path, LLSDMethod<TRequest, TResponse> method, string name, string description) | ||||
|             : base(httpMethod, path, name, description) | ||||
|             : base(httpMethod, path) | ||||
|         { | ||||
|             m_method = method; | ||||
|         } | ||||
| 
 | ||||
|         protected override byte[] ProcessRequest(string path, Stream request, | ||||
|         public override byte[] Handle(string path, Stream request, | ||||
|                                       IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||||
|         { | ||||
|             //Encoding encoding = Util.UTF8; | ||||
|  | @ -61,15 +57,14 @@ namespace OpenSim.Framework.Capabilities | |||
|             //    OpenMetaverse.StructuredData.LLSDParser.DeserializeXml(new XmlTextReader(request)); | ||||
| 
 | ||||
|             Hashtable hash = (Hashtable) LLSD.LLSDDeserialize(request); | ||||
|             if(hash == null) | ||||
|                 return new byte[0]; | ||||
| 
 | ||||
|             TRequest llsdRequest = new TRequest(); | ||||
|             LLSDHelpers.DeserialiseOSDMap(hash, llsdRequest); | ||||
| 
 | ||||
|             TResponse response = m_method(llsdRequest); | ||||
| 
 | ||||
|             return Util.UTF8NoBomEncoding.GetBytes(LLSDHelpers.SerialiseLLSDReply(response)); | ||||
|             Encoding encoding = new UTF8Encoding(false); | ||||
| 
 | ||||
|             return encoding.GetBytes(LLSDHelpers.SerialiseLLSDReply(response)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -26,17 +26,25 @@ | |||
|  */ | ||||
| 
 | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Framework; | ||||
| using System.Drawing; | ||||
| 
 | ||||
| namespace OpenSim.Region.Framework.Interfaces | ||||
| namespace OpenSim.Framework.Capabilities | ||||
| { | ||||
|     public interface IMapImageUploadModule | ||||
|     [OSDMap] | ||||
|     public class LLSDTaskScriptUpdate | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Upload a new maptile | ||||
|         /// The item containing the script to update | ||||
|         /// </summary> | ||||
|         void UploadMapTile(IScene scene); | ||||
|         void UploadMapTile(IScene scene, Bitmap mapTile); | ||||
|         public UUID item_id; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// The task containing the script | ||||
|         /// </summary> | ||||
|         public UUID task_id; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Signals whether the script is currently active | ||||
|         /// </summary> | ||||
|         public int is_script_running; | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,57 @@ | |||
| /* | ||||
| * Copyright (c) Contributors, http://opensimulator.org/ | ||||
| * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||
| * | ||||
| * Redistribution and use in source and binary forms, with or without | ||||
| * modification, are permitted provided that the following conditions are met: | ||||
| *     * Redistributions of source code must retain the above copyright | ||||
| *       notice, this list of conditions and the following disclaimer. | ||||
| *     * Redistributions in binary form must reproduce the above copyright | ||||
| *       notice, this list of conditions and the following disclaimer in the | ||||
| *       documentation and/or other materials provided with the distribution. | ||||
| *     * Neither the name of the OpenSimulator Project nor the | ||||
| *       names of its contributors may be used to endorse or promote products | ||||
| *       derived from this software without specific prior written permission. | ||||
| * | ||||
| * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||
| * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| * | ||||
| */ | ||||
| 
 | ||||
| namespace OpenSim.Framework.Capabilities | ||||
| { | ||||
|     [OSDMap] | ||||
|     public class LLSDVoiceAccountResponse | ||||
|     { | ||||
|         public string username; | ||||
|         public string password; | ||||
|         public string voice_sip_uri_hostname; | ||||
|         public string voice_account_server_name; | ||||
| 
 | ||||
|         public LLSDVoiceAccountResponse() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         public LLSDVoiceAccountResponse(string user, string pass) | ||||
|         { | ||||
|             username = user; | ||||
|             password = pass; | ||||
|         } | ||||
| 
 | ||||
|         public LLSDVoiceAccountResponse(string user, string pass, string sipUriHost, string accountServer) | ||||
|         { | ||||
|             username = user; | ||||
|             password = pass; | ||||
|             voice_sip_uri_hostname = sipUriHost; | ||||
|             voice_account_server_name = accountServer; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -1,33 +0,0 @@ | |||
| using System.Reflection; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Runtime.InteropServices; | ||||
| 
 | ||||
| // General Information about an assembly is controlled through the following | ||||
| // set of attributes. Change these attribute values to modify the information | ||||
| // associated with an assembly. | ||||
| [assembly: AssemblyTitle("OpenSim.Capabilities")] | ||||
| [assembly: AssemblyDescription("")] | ||||
| [assembly: AssemblyConfiguration("")] | ||||
| [assembly: AssemblyCompany("http://opensimulator.org")] | ||||
| [assembly: AssemblyProduct("OpenSim")] | ||||
| [assembly: AssemblyCopyright("OpenSimulator developers")] | ||||
| [assembly: AssemblyTrademark("")] | ||||
| [assembly: AssemblyCulture("")] | ||||
| 
 | ||||
| // Setting ComVisible to false makes the types in this assembly not visible | ||||
| // to COM components.  If you need to access a type in this assembly from | ||||
| // COM, set the ComVisible attribute to true on that type. | ||||
| [assembly: ComVisible(false)] | ||||
| 
 | ||||
| // The following GUID is for the ID of the typelib if this project is exposed to COM | ||||
| [assembly: Guid("7d1a55b1-8fab-42ff-9c83-066a9cc34d76")] | ||||
| 
 | ||||
| // Version information for an assembly consists of the following four values: | ||||
| // | ||||
| //      Major Version | ||||
| //      Minor Version | ||||
| //      Build Number | ||||
| //      Revision | ||||
| // | ||||
| [assembly: AssemblyVersion("0.7.6.*")] | ||||
| [assembly: AssemblyFileVersion("1.0.0.0")] | ||||
|  | @ -80,7 +80,7 @@ namespace OpenSim.ConsoleClient | |||
|             while (m_Server.Running) | ||||
|             { | ||||
|                 System.Threading.Thread.Sleep(500); | ||||
|                 MainConsole.Instance.Prompt(); | ||||
|                 // MainConsole.Instance.Prompt(); | ||||
|             } | ||||
| 
 | ||||
|             if (pidFile != String.Empty) | ||||
|  | @ -178,7 +178,7 @@ namespace OpenSim.ConsoleClient | |||
|                 Requester.MakeRequest(requestUrl, requestData, ReadResponses); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|              | ||||
|             List<string> lines = new List<string>(); | ||||
| 
 | ||||
|             foreach (XmlNode part in rootNodeL[0].ChildNodes) | ||||
|  | @ -202,7 +202,7 @@ namespace OpenSim.ConsoleClient | |||
|                 string[] parts = l.Split(new char[] {':'}, 3); | ||||
|                 if (parts.Length != 3) | ||||
|                     continue; | ||||
| 
 | ||||
|                  | ||||
|                 if (parts[2].StartsWith("+++") || parts[2].StartsWith("-++")) | ||||
|                     prompt = parts[2]; | ||||
|                 else | ||||
|  |  | |||
|  | @ -1,33 +0,0 @@ | |||
| using System.Reflection; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Runtime.InteropServices; | ||||
| 
 | ||||
| // General Information about an assembly is controlled through the following | ||||
| // set of attributes. Change these attribute values to modify the information | ||||
| // associated with an assembly. | ||||
| [assembly: AssemblyTitle("OpenSim.ConsoleClient")] | ||||
| [assembly: AssemblyDescription("")] | ||||
| [assembly: AssemblyConfiguration("")] | ||||
| [assembly: AssemblyCompany("http://opensimulator.org")] | ||||
| [assembly: AssemblyProduct("OpenSim")] | ||||
| [assembly: AssemblyCopyright("OpenSimulator developers")] | ||||
| [assembly: AssemblyTrademark("")] | ||||
| [assembly: AssemblyCulture("")] | ||||
| 
 | ||||
| // Setting ComVisible to false makes the types in this assembly not visible | ||||
| // to COM components.  If you need to access a type in this assembly from | ||||
| // COM, set the ComVisible attribute to true on that type. | ||||
| [assembly: ComVisible(false)] | ||||
| 
 | ||||
| // The following GUID is for the ID of the typelib if this project is exposed to COM | ||||
| [assembly: Guid("8945df94-2e5e-475b-88fa-35a7cdde6fd7")] | ||||
| 
 | ||||
| // Version information for an assembly consists of the following four values: | ||||
| // | ||||
| //      Major Version | ||||
| //      Minor Version | ||||
| //      Build Number | ||||
| //      Revision | ||||
| // | ||||
| [assembly: AssemblyVersion("0.7.6.*")] | ||||
| [assembly: AssemblyFileVersion("1.0.0.0")] | ||||
|  | @ -44,12 +44,13 @@ namespace OpenSim.ConsoleClient | |||
|                 ReplyDelegate action) | ||||
|         { | ||||
|             WebRequest request = WebRequest.Create(requestUrl); | ||||
|             WebResponse response = null; | ||||
| 
 | ||||
|             request.Method = "POST"; | ||||
| 
 | ||||
|             request.ContentType = "application/x-www-form-urlencoded"; | ||||
| 
 | ||||
|             byte[] buffer = Encoding.ASCII.GetBytes(data); | ||||
|             byte[] buffer = new System.Text.ASCIIEncoding().GetBytes(data); | ||||
|             int length = (int) buffer.Length; | ||||
|             request.ContentLength = length; | ||||
| 
 | ||||
|  | @ -63,18 +64,16 @@ namespace OpenSim.ConsoleClient | |||
|                 { | ||||
|                     string reply = String.Empty; | ||||
| 
 | ||||
|                     using (WebResponse response = request.EndGetResponse(ar)) | ||||
|                     { | ||||
|                         try | ||||
|                         { | ||||
|                             using (Stream s = response.GetResponseStream()) | ||||
|                                 using (StreamReader r = new StreamReader(s)) | ||||
|                                     reply = r.ReadToEnd(); | ||||
|                     response = request.EndGetResponse(ar); | ||||
| 
 | ||||
|                         } | ||||
|                         catch (System.InvalidOperationException) | ||||
|                         { | ||||
|                         } | ||||
|                     try | ||||
|                     { | ||||
|                         StreamReader r = new StreamReader(response.GetResponseStream()); | ||||
|                         reply = r.ReadToEnd(); | ||||
| 
 | ||||
|                     } | ||||
|                     catch (System.InvalidOperationException) | ||||
|                     { | ||||
|                     } | ||||
| 
 | ||||
|                     action(requestUrl, data, reply); | ||||
|  |  | |||
|  | @ -37,8 +37,9 @@ namespace OpenSim.Data | |||
|     public abstract class AssetDataBase : IAssetDataPlugin | ||||
|     { | ||||
|         public abstract AssetBase GetAsset(UUID uuid); | ||||
|         public abstract bool StoreAsset(AssetBase asset); | ||||
|         public abstract bool[] AssetsExist(UUID[] uuids); | ||||
|          | ||||
|         public abstract void StoreAsset(AssetBase asset); | ||||
|         public abstract bool ExistsAsset(UUID uuid); | ||||
| 
 | ||||
|         public abstract List<AssetMetadata> FetchAssetMetadataSet(int start, int count); | ||||
| 
 | ||||
|  |  | |||
|  | @ -38,7 +38,7 @@ namespace OpenSim.Data | |||
|         /// <summary>This function converts a value returned from the database in one of the | ||||
|         /// supported formats into a UUID.  This function is not actually DBMS-specific right | ||||
|         /// now | ||||
|         /// | ||||
|         ///  | ||||
|         /// </summary> | ||||
|         /// <param name="id"></param> | ||||
|         /// <returns></returns> | ||||
|  | @ -47,25 +47,24 @@ namespace OpenSim.Data | |||
|             if ((id == null) || (id == DBNull.Value)) | ||||
|                 return UUID.Zero; | ||||
| 
 | ||||
|             Type idtype = id.GetType(); | ||||
| 
 | ||||
|             if (idtype == typeof(Guid)) | ||||
|             if (id.GetType() == typeof(Guid)) | ||||
|                 return new UUID((Guid)id); | ||||
| 
 | ||||
|             if (id.GetType() == typeof(string)) | ||||
|             if (id.GetType() == typeof(byte[])) | ||||
|             { | ||||
|                 Guid gg;  | ||||
|                 if (Guid.TryParse((string)id, out gg)) | ||||
|                     return new UUID(gg); | ||||
|                 return UUID.Zero; | ||||
|                 if (((byte[])id).Length == 0) | ||||
|                     return UUID.Zero; | ||||
|                 else if (((byte[])id).Length == 16) | ||||
|                     return new UUID((byte[])id, 0); | ||||
|             } | ||||
|             else if (id.GetType() == typeof(string)) | ||||
|             { | ||||
|                 if (((string)id).Length == 0) | ||||
|                     return UUID.Zero; | ||||
|                 else if (((string)id).Length == 36) | ||||
|                     return new UUID((string)id); | ||||
|             } | ||||
| 
 | ||||
|             if (idtype == typeof(byte[])) | ||||
|             { | ||||
|                 if (((byte[])id).Length < 16) | ||||
|                     return UUID.Zero; | ||||
|                 return new UUID((byte[])id, 0); | ||||
|             } | ||||
|             throw new Exception("Failed to convert db value to UUID: " + id.ToString()); | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -34,8 +34,8 @@ namespace OpenSim.Data | |||
|     public interface IAssetDataPlugin : IPlugin | ||||
|     { | ||||
|         AssetBase GetAsset(UUID uuid); | ||||
|         bool StoreAsset(AssetBase asset); | ||||
|         bool[] AssetsExist(UUID[] uuids); | ||||
|         void StoreAsset(AssetBase asset); | ||||
|         bool ExistsAsset(UUID uuid); | ||||
|         List<AssetMetadata> FetchAssetMetadataSet(int start, int count); | ||||
|         void Initialise(string connect); | ||||
|         bool Delete(string id); | ||||
|  |  | |||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue