├── .all-contributorsrc ├── .appveyor.yml ├── .editorconfig ├── .github ├── funding.yml └── workflows │ ├── codeql-analysis.yml │ ├── dotnet.yml │ └── greetings.yml ├── .gitignore ├── LICENSE.md ├── Microsoft.Build.CommonTypes.xsd ├── Microsoft.Build.Core.xsd ├── Microsoft.Build.xsd ├── Properties └── launchSettings.json ├── README.md ├── RESTbot - API testing scaffolding.postman_collection.json ├── RESTbot.csproj ├── RESTbot.nuspec ├── assets ├── configuration │ ├── configuration.xml.sample │ └── log4net.config ├── images │ ├── RESTbot-512x420.png │ ├── RESTbot-logo-256x256.png │ ├── RESTbot-logo-github-card-1280x640.png │ ├── RESTbot-logo.png │ ├── RESTbot-logo.psd │ └── RESTbot.ico └── openmetaverse_data │ ├── avatar_lad.xml │ ├── avatar_skeleton.xml │ ├── blush_alpha.tga │ ├── body_skingrain.tga │ ├── bodyfreckles_alpha.tga │ ├── bump_face_wrinkles.tga │ ├── bump_head_base.tga │ ├── bump_lowerbody_base.tga │ ├── bump_pants_wrinkles.tga │ ├── bump_shirt_wrinkles.tga │ ├── bump_upperbody_base.tga │ ├── eyebrows_alpha.tga │ ├── eyeliner_alpha.tga │ ├── eyeshadow_inner_alpha.tga │ ├── eyeshadow_outer_alpha.tga │ ├── eyewhite.tga │ ├── facehair_chincurtains_alpha.tga │ ├── facehair_moustache_alpha.tga │ ├── facehair_sideburns_alpha.tga │ ├── facehair_soulpatch_alpha.tga │ ├── freckles_alpha.tga │ ├── glove_length_alpha.tga │ ├── gloves_fingers_alpha.tga │ ├── head_alpha.tga │ ├── head_color.tga │ ├── head_hair.tga │ ├── head_highlights_alpha.tga │ ├── head_shading_alpha.tga │ ├── head_skingrain.tga │ ├── jacket_length_lower_alpha.tga │ ├── jacket_length_upper_alpha.tga │ ├── jacket_open_lower_alpha.tga │ ├── jacket_open_upper_alpha.tga │ ├── lipgloss_alpha.tga │ ├── lips_mask.tga │ ├── lipstick_alpha.tga │ ├── lowerbody_color.tga │ ├── lowerbody_highlights_alpha.tga │ ├── lowerbody_shading_alpha.tga │ ├── nailpolish_alpha.tga │ ├── pants_length_alpha.tga │ ├── pants_waist_alpha.tga │ ├── rosyface_alpha.tga │ ├── rouge_alpha.tga │ ├── shirt_bottom_alpha.tga │ ├── shirt_collar_alpha.tga │ ├── shirt_collar_back_alpha.tga │ ├── shirt_sleeve_alpha.tga │ ├── shoe_height_alpha.tga │ ├── skirt_length_alpha.tga │ ├── skirt_slit_back_alpha.tga │ ├── skirt_slit_front_alpha.tga │ ├── skirt_slit_left_alpha.tga │ ├── skirt_slit_right_alpha.tga │ ├── underpants_trial_female.tga │ ├── underpants_trial_male.tga │ ├── undershirt_trial_female.tga │ ├── upperbody_color.tga │ ├── upperbody_highlights_alpha.tga │ ├── upperbody_shading_alpha.tga │ └── upperbodyfreckles_alpha.tga ├── global.json ├── restbot-plugins ├── AvatarsPlugin.cs ├── ChatPlugin.cs ├── GroupsPlugin.cs ├── InventoryPlugin.cs ├── ListenPlugin.cs ├── MovementPlugin.cs ├── PrimsPlugin.cs ├── ReaperPlugin.cs └── StatsPlugin.cs ├── restbot-src ├── Configuration.cs ├── DebugUtilities.cs ├── Program.cs ├── RestBot.cs ├── RestPlugin.cs ├── Server │ ├── HeaderConstructor.cs │ ├── HeaderLines.cs │ ├── HeaderParser.cs │ ├── Router.cs │ └── Server.cs └── Utilities.cs └── restbot-tools ├── launch-scripts └── systemd │ ├── README - for systemd.md │ └── restbot.service.sample ├── php-restbot-api ├── avatars.php ├── groups.php ├── include │ ├── avatars.php │ ├── config.php │ ├── db.php │ ├── funktions.php │ ├── groups.php │ ├── sl.php │ ├── sql.php │ └── util.php └── util.php └── test-scripts ├── api └── getname.lsl ├── dilation-meter.sh ├── perl ├── bot-dilation.pl ├── bot-getgroupprofile.pl ├── bot-getgrouproles.pl ├── bot-getgroups.pl ├── bot-getgroups2.pl ├── bot-getkey.pl ├── bot-getname.pl ├── bot-getonline.pl ├── bot-getprofile.pl ├── bot-givelandmark.pl ├── bot-groupinvitations.pl ├── bot-groupinvite.pl ├── bot-joingroup.pl ├── bot-leavegroup.pl ├── bot-location.pl ├── bot-parcel.pl ├── bot-parceleditname.pl ├── bot-regionhandle.pl ├── bot-rez.pl ├── bot-sit.pl ├── bot-sitground.pl ├── bot-stand.pl ├── bot-startanim.pl ├── bot-stats.pl ├── bot-status.pl ├── bot-stopanim.pl ├── bot-teleport.pl ├── botlogin.pl ├── botquit.pl └── botshutdown.pl └── php ├── bot-dilation.php └── bot-getkey.php /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "commitType": "docs", 8 | "commitConvention": "angular", 9 | "contributors": [ 10 | { 11 | "login": "iDJHost", 12 | "name": "iDJHost", 13 | "avatar_url": "https://avatars.githubusercontent.com/u/21136403?v=4", 14 | "profile": "https://github.com/iDJHost", 15 | "contributions": [ 16 | "test" 17 | ] 18 | } 19 | ], 20 | "contributorsPerLine": 7, 21 | "skipCi": true, 22 | "repoType": "github", 23 | "repoHost": "https://github.com", 24 | "projectName": "restbot", 25 | "projectOwner": "GwynethLlewelyn" 26 | } 27 | -------------------------------------------------------------------------------- /.appveyor.yml: -------------------------------------------------------------------------------- 1 | init: 2 | - ps: if ($env:APPVEYOR_REPO_TAG -eq "true") { $env:TAG_VERSION = "$env:APPVEYOR_REPO_TAG_NAME.$env:APPVEYOR_BUILD_NUMBER" } else { $env:TAG_VERSION = "v8.3.0.$env:APPVEYOR_BUILD_NUMBER-alpha" } 3 | - ps: $env:TAG_VERSION = $env:TAG_VERSION -replace 'v','' 4 | - ps: Write-Host "Setting version to '$env:TAG_VERSION'" 5 | - ps: Update-AppveyorBuild -Version "$env:TAG_VERSION" 6 | 7 | environment: 8 | matrix: 9 | - job_name: Linux Build 10 | platform: x64 11 | appveyor_build_worker_image: Ubuntu 12 | configuration: RESTbot 13 | 14 | matrix: 15 | allow_failures: 16 | - image: Ubuntu 17 | 18 | nuget: 19 | disable_publish_on_pr: true 20 | 21 | build: 22 | publish_nuget: false 23 | publish_nuget_symbols: false 24 | use_snupkg_format: true 25 | parallel: true 26 | verbosity: minimal 27 | 28 | before_build: 29 | - dotnet --info 30 | - dotnet restore RESTbot.csproj 31 | 32 | for: 33 | - 34 | matrix: 35 | only: 36 | - job_name: Linux Build -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # Unix-style newlines with a newline ending every file 5 | [*] 6 | end_of_line = lf 7 | charset = utf-8 8 | indent_style = tab 9 | indent_size = tab 10 | tab_width = 2 11 | trim_trailing_whitespace = true 12 | 13 | # The property below is not yet universally supported 14 | [*.md] 15 | max_line_length = 108 16 | word_wrap = true 17 | # Markdown sometimes uses two spaces at the end to 18 | # mark soft line breaks 19 | trim_trailing_whitespace = false 20 | 21 | [*.yml] 22 | end_of_line = lf 23 | charset = utf-8 24 | indent_style = space 25 | indent_size = 2 26 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.github/funding.yml: -------------------------------------------------------------------------------- 1 | github: [gwynethllewelyn] -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | # The branches below must be a subset of the branches above 8 | branches: [ master ] 9 | schedule: 10 | - cron: '45 10 * * 3' 11 | 12 | jobs: 13 | analyze: 14 | name: Analyze 15 | runs-on: ubuntu-latest 16 | permissions: 17 | actions: read 18 | contents: read 19 | security-events: write 20 | 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | language: [ 'csharp' ] 25 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 26 | # Learn more about CodeQL language support at https://git.io/codeql-language-support 27 | 28 | steps: 29 | - name: Checkout repository 30 | uses: actions/checkout@v2 31 | 32 | # Initializes the CodeQL tools for scanning. 33 | - name: Initialize CodeQL 34 | uses: github/codeql-action/init@v1 35 | with: 36 | languages: ${{ matrix.language }} 37 | # If you wish to specify custom queries, you can do so here or in a config file. 38 | # By default, queries listed here will override any specified in a config file. 39 | # Prefix the list here with "+" to use these queries and those in the config file. 40 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 41 | 42 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 43 | # If this step fails, then you should remove it and run the build manually (see below) 44 | - name: Autobuild 45 | uses: github/codeql-action/autobuild@v1 46 | 47 | # ℹ️ Command-line programs to run using the OS shell. 48 | # 📚 https://git.io/JvXDl 49 | 50 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 51 | # and modify them (or add more) to build your code if your project 52 | # uses a compiled language 53 | 54 | #- run: | 55 | # make bootstrap 56 | # make release 57 | 58 | - name: Perform CodeQL Analysis 59 | uses: github/codeql-action/analyze@v1 60 | -------------------------------------------------------------------------------- /.github/workflows/dotnet.yml: -------------------------------------------------------------------------------- 1 | name: .NET 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Setup .NET 17 | uses: actions/setup-dotnet@v3 18 | with: 19 | dotnet-version: 6.0.x 20 | - name: Restore dependencies 21 | run: dotnet restore 22 | - name: Build 23 | run: dotnet build --no-restore 24 | - name: Test 25 | run: dotnet test --no-build --verbosity normal 26 | -------------------------------------------------------------------------------- /.github/workflows/greetings.yml: -------------------------------------------------------------------------------- 1 | name: Greetings 2 | 3 | on: 4 | [pull_request, issues] 5 | 6 | jobs: 7 | greeting: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | issues: write 11 | pull-requests: write 12 | steps: 13 | - uses: actions/first-interaction@v1 14 | with: 15 | repo-token: ${{ secrets.GITHUB_TOKEN }} 16 | issue-message: 'Thank you for taking the time to improve RESTbot! We will review your contribution shortly.' 17 | pr-message: 'Thank you for taking the time to improve RESTbot! We will review your contribution shortly.' 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ~* 2 | # Stupid macOS temporary files 3 | 4 | # General 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | 13 | Icon? 14 | 15 | # Thumbnails 16 | ._* 17 | 18 | # Files that might appear in the root of a volume 19 | .DocumentRevisions-V100 20 | .fseventsd 21 | .Spotlight-V100 22 | .TemporaryItems 23 | .Trashes 24 | .VolumeIcon.icns 25 | .com.apple.timemachine.donotpresent 26 | 27 | # Directories potentially created on remote AFP share 28 | .AppleDB 29 | .AppleDesktop 30 | Network Trash Folder 31 | Temporary Items 32 | .apdisk 33 | 34 | # Stuff from the Nova editor 35 | .nova 36 | node_modules 37 | package.json 38 | package-lock.json 39 | .eslintrc.yml 40 | .prettierrc.json 41 | 42 | # Our stuff that we want to exclude 43 | assets/configuration/configuration.xml 44 | restbot-tools/launch-scripts/systemd/restbot.service 45 | 46 | # Dependency directories (remove the comment below to include it) 47 | # vendor/ 48 | 49 | # Logging files 50 | logs/* 51 | *.log 52 | 53 | *.test 54 | *.prof 55 | 56 | # Libraries 57 | *.lib 58 | *.a 59 | *.la 60 | *.lo 61 | *.def 62 | *.exp 63 | 64 | # Shared objects (inc. Windows DLLs) 65 | *.dll 66 | #*.so 67 | #*.so.* 68 | #*.dylib 69 | # Other Microsoft Roslyn temporary files 70 | *.pdb 71 | obj/ 72 | packages/ 73 | restbot.exe-backup.config 74 | # This will be overwritten by a successful compilation anyway (gwyneth 20211129) 75 | restbot-bin/ 76 | 77 | # Executables 78 | #*.exe 79 | #*.out 80 | #*.app 81 | #*.i*86 82 | #*.x86_64 83 | #*.hex 84 | 85 | # From Visual Studio 86 | .vs 87 | 88 | # NuGet packages 89 | *.nupkg 90 | *.snupkg 91 | -------------------------------------------------------------------------------- /Microsoft.Build.xsd: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true 5 | }, 6 | "profiles": { 7 | "RESTbot": { 8 | "commandName": "Project", 9 | "launchBrowser": true, 10 | "applicationUrl": "http://localhost:62945", 11 | "environmentVariables": { 12 | "ASPNETCORE_ENVIRONMENT": "Development" 13 | } 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /RESTbot.csproj: -------------------------------------------------------------------------------- 1 |  2 | 9 | 10 | net6.0;net7.0;net8.0 11 | enable 12 | enable 13 | RESTbot 14 | restbot-bin\ 15 | Exe 16 | true 17 | true 18 | snupkg 19 | 20 | 21 | $(Version) 22 | assets\ 23 | $(AssetsFolder)images\RESTbot.ico 24 | RESTbot 25 | Gwyneth Llewelyn, Pleiades, others 26 | Copyright © Pleiades 2007. Copyright © Gwyneth Llewelyn 2010,2021,2023. Some rights reserved 27 | RESTbot-logo.png 28 | README.md 29 | AGPL-3.0-or-later 30 | https://github.com/GwynethLlewelyn/restbot 31 | Gwyneth Llewelyn 32 | LMV OMV OpenMetaverse OpenSim OpenSimulator Halcyon OpenMetaverseFoundation VirtualWorld Radegast SecondLife 33 | RESTBot is a C# webserver that uses RESTful transactions to interact with a bot in Second Life or OpenSimulator. It relies on LibreMetaverse. 34 | https://github.com/GwynethLlewelyn/restbot 35 | git 36 | RESTbot 37 | RESTBot is a C# webserver that uses RESTful transactions to interact with a bot in Second Life or OpenSimulator. It relies on LibreMetaverse. 38 | RESTBot is a C# webserver that uses RESTful transactions to interact with a bot in Second Life or OpenSimulator. It relies on LibreMetaverse. 39 | {F6E2EED5-AE02-45D9-A129-7E759F326D4C} 40 | true 41 | 42 | true 43 | true 44 | true 45 | 46 | 47 | 48 | Windows 49 | 50 | 51 | OSX 52 | 53 | 54 | Linux 55 | 56 | 57 | Debug 58 | AnyCPU 59 | 60 | 61 | true 62 | full 63 | false 64 | 65 | DEBUG;TRACE;STARTUP_DEBUG;VERBOSE_MESSAGES 66 | prompt 67 | 4 68 | 69 | 70 | 71 | pdbonly 72 | true 73 | TRACE 74 | prompt 75 | 4 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | assets\ 122 | $(AssetsFolder)configuration 123 | openmetaverse_data\ 124 | $(AssetsFolder)$(OpenMetaverseData) 125 | 126 | 127 | 128 | 129 | 131 | 132 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /RESTbot.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | RESTbot 5 | $version$ 6 | RESTBot is a C# webserver that uses RESTful transactions to interact with a bot in Second Life or OpenSimulator. It relies on LibreMetaverse. 7 | Pleiades,Gwyneth Llewelyn,others 8 | https://github.com/GwynethLlewelyn/restbot 9 | AGPL-3.0-or-later 10 | assets\images\RESTbot-logo.png 11 | README.md 12 | false 13 | Copyright 2007,2010,2021,2023 14 | LMV OMV OpenMetaverse OpenSim OpenSimulator Halcyon OpenMetaverseFoundation VirtualWorld Radegast SecondLife 15 | 16 | RESTbot 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /assets/configuration/configuration.xml.sample: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 127.0.0.1 6 | 9080 7 | 8 | https://login.agni.lindenlab.com/cgi-bin/login.cgi 9 | 10 | 11 | false 12 | 13 | pass 14 | 15 | 16 | 17 | One Region 18 | 127 19 | 127 20 | 22 21 | 22 | 23 | 24 | true 25 | true 26 | 27 | 28 | 29 | 30 | true 31 | 10000 32 | 33 | 34 | -------------------------------------------------------------------------------- /assets/configuration/log4net.config: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 27 | 28 | 29 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /assets/images/RESTbot-512x420.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/images/RESTbot-512x420.png -------------------------------------------------------------------------------- /assets/images/RESTbot-logo-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/images/RESTbot-logo-256x256.png -------------------------------------------------------------------------------- /assets/images/RESTbot-logo-github-card-1280x640.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/images/RESTbot-logo-github-card-1280x640.png -------------------------------------------------------------------------------- /assets/images/RESTbot-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/images/RESTbot-logo.png -------------------------------------------------------------------------------- /assets/images/RESTbot-logo.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/images/RESTbot-logo.psd -------------------------------------------------------------------------------- /assets/images/RESTbot.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/images/RESTbot.ico -------------------------------------------------------------------------------- /assets/openmetaverse_data/blush_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/blush_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/body_skingrain.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/body_skingrain.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/bodyfreckles_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/bodyfreckles_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/bump_face_wrinkles.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/bump_face_wrinkles.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/bump_head_base.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/bump_head_base.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/bump_lowerbody_base.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/bump_lowerbody_base.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/bump_pants_wrinkles.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/bump_pants_wrinkles.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/bump_shirt_wrinkles.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/bump_shirt_wrinkles.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/bump_upperbody_base.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/bump_upperbody_base.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/eyebrows_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/eyebrows_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/eyeliner_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/eyeliner_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/eyeshadow_inner_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/eyeshadow_inner_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/eyeshadow_outer_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/eyeshadow_outer_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/eyewhite.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/eyewhite.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/facehair_chincurtains_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/facehair_chincurtains_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/facehair_moustache_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/facehair_moustache_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/facehair_sideburns_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/facehair_sideburns_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/facehair_soulpatch_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/facehair_soulpatch_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/freckles_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/freckles_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/glove_length_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/glove_length_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/gloves_fingers_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/gloves_fingers_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/head_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/head_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/head_color.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/head_color.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/head_hair.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/head_hair.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/head_highlights_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/head_highlights_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/head_shading_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/head_shading_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/head_skingrain.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/head_skingrain.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/jacket_length_lower_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/jacket_length_lower_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/jacket_length_upper_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/jacket_length_upper_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/jacket_open_lower_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/jacket_open_lower_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/jacket_open_upper_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/jacket_open_upper_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/lipgloss_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/lipgloss_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/lips_mask.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/lips_mask.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/lipstick_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/lipstick_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/lowerbody_color.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/lowerbody_color.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/lowerbody_highlights_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/lowerbody_highlights_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/lowerbody_shading_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/lowerbody_shading_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/nailpolish_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/nailpolish_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/pants_length_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/pants_length_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/pants_waist_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/pants_waist_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/rosyface_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/rosyface_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/rouge_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/rouge_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/shirt_bottom_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/shirt_bottom_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/shirt_collar_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/shirt_collar_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/shirt_collar_back_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/shirt_collar_back_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/shirt_sleeve_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/shirt_sleeve_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/shoe_height_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/shoe_height_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/skirt_length_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/skirt_length_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/skirt_slit_back_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/skirt_slit_back_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/skirt_slit_front_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/skirt_slit_front_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/skirt_slit_left_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/skirt_slit_left_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/skirt_slit_right_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/skirt_slit_right_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/underpants_trial_female.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/underpants_trial_female.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/underpants_trial_male.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/underpants_trial_male.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/undershirt_trial_female.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/undershirt_trial_female.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/upperbody_color.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/upperbody_color.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/upperbody_highlights_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/upperbody_highlights_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/upperbody_shading_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/upperbody_shading_alpha.tga -------------------------------------------------------------------------------- /assets/openmetaverse_data/upperbodyfreckles_alpha.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/restbot/9c255e16fcf9875f5d147067d9777e180742c4a1/assets/openmetaverse_data/upperbodyfreckles_alpha.tga -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "8.0.6", 4 | "rollForward": "latestMajor", 5 | "allowPrerelease": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /restbot-plugins/ChatPlugin.cs: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------------------- 2 | FILE INFORMATION: 3 | Name: ChatPlugin.cs [./restbot-plugins/ChatPlugin.cs] 4 | Description: Handles outgoing messages (chat, public chat, shout/say/whisper) 5 | as well as instant messaging. 6 | 7 | LICENSE: 8 | This file is part of the RESTBot Project. 9 | 10 | Copyright (C) 2007-2008 PLEIADES CONSULTING, INC and others 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Affero General Public License as 14 | published by the Free Software Foundation, either version 3 of the 15 | License, or (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Affero General Public License for more details. 21 | 22 | You should have received a copy of the GNU Affero General Public License 23 | along with this program. If not, see . 24 | 25 | Author: Brian Krisler 26 | Contributing author: Gwyneth Llewelyn 27 | --------------------------------------------------------------------------------*/ 28 | using System; 29 | using System.Collections.Generic; 30 | using System.Linq; 31 | using System.Text; 32 | using OpenMetaverse; 33 | using OpenMetaverse.Utilities; 34 | 35 | namespace RESTBot 36 | { 37 | /// 38 | /// Class to send messages to a channel in chat 39 | /// 40 | public class SayPlugin : StatefulPlugin 41 | { 42 | private UUID session; 43 | 44 | private RestBot? me; // potentially null 45 | 46 | /// 47 | /// Sets the plugin name for the router. 48 | /// 49 | public SayPlugin() 50 | { 51 | MethodName = "say"; 52 | } 53 | 54 | /// 55 | /// Initialises the plugin. 56 | /// 57 | /// A currently active RestBot 58 | public override void Initialize(RestBot bot) 59 | { 60 | session = bot.sessionid; 61 | me = bot; 62 | DebugUtilities.WriteDebug($"{session} {MethodName} startup"); 63 | 64 | base.Initialize(bot); 65 | } 66 | 67 | /// 68 | /// Handler event for this plugin. 69 | /// 70 | /// A currently active RestBot 71 | /// A dictionary containing the channel, the message, possibly the chat type, and if realistic chat should be used or not (and if so, how many characters per second to type 72 | /// channel defaults to 0 (public channel), while chattype defaults to normal chat. 73 | public override string 74 | Process(RestBot b, Dictionary Parameters) 75 | { 76 | int channel = 0; 77 | bool check = true; 78 | string message = String.Empty; 79 | ChatType chattype = ChatType.Normal; 80 | bool realism = false; // allows chat to be more realistic, i.e. with typing animation etc. 81 | int charspersecond = 3; // a human types 3 characters per second on average 82 | 83 | if (Parameters.ContainsKey("channel")) 84 | { 85 | check &= int.TryParse(Parameters["channel"], out channel); 86 | } 87 | 88 | if (Parameters.ContainsKey("message")) 89 | { 90 | //message = Parameters["message"].ToString().Replace("+", " "); 91 | message = Parameters["message"]; 92 | } 93 | else 94 | check = false; // *must* have a message! 95 | 96 | // if chattype is not specified, we use normal chat by default. 97 | if (Parameters.ContainsKey("chattype")) 98 | { 99 | switch (Parameters["chattype"]) 100 | { 101 | case "shout": 102 | chattype = ChatType.Shout; 103 | break; 104 | case "whisper": 105 | chattype = ChatType.Whisper; 106 | break; 107 | default: 108 | chattype = ChatType.Normal; 109 | break; 110 | } 111 | } 112 | 113 | // optional parameters, don't affect the check flag (gwyneth 20220318) 114 | if (Parameters.ContainsKey("realism")) 115 | { 116 | bool.TryParse(Parameters["realism"], out realism); 117 | } 118 | 119 | if (Parameters.ContainsKey("charspersecond")) 120 | { 121 | // default is 3 122 | int.TryParse(Parameters["charspersecond"], out charspersecond); 123 | } 124 | 125 | if (!check) 126 | { 127 | return $"{MethodName}: missing required parameters"; 128 | } 129 | 130 | // Make sure we are not in autopilot. 131 | // Note: Why not? (gwyneth 20220121) 132 | b.Client.Self.AutoPilotCancel(); 133 | 134 | // Note: when channel is zero, we'll attempt to use Realism.Chat instead, because it looks cooler! (gwyneth 20220121) 135 | /// Realism is a class in Openmetaverse.Utilities. 136 | if (channel != 0 || !realism) 137 | { 138 | b.Client.Self.Chat(message, channel, chattype); 139 | } 140 | else if (realism) 141 | { 142 | Realism.Chat(b.Client, message, chattype, charspersecond); // 3 chars per second will be default 143 | } 144 | 145 | return $"<{MethodName}>{channel.ToString()}{message}{chattype.ToString()}"; 146 | } // end Process 147 | } // end SayPlugin 148 | 149 | /// 150 | /// Class to send instant messages to an avatar (name or UUID). 151 | /// 152 | /// 153 | /// Heavily inspired by LibreMetaverse's TestClient! (gwyneth 20220212) 154 | /// It's much cleaner that way; getting the avatar key needed to send the IM is pushed 155 | /// to the Utilities class. 156 | /// 157 | /// 158 | /// Gwyneth Llewelyn 159 | /// 160 | public class InstantMessagePlugin : StatefulPlugin 161 | { 162 | private UUID session; 163 | 164 | private RestBot? me; // potentially null 165 | 166 | /// 167 | /// Sets the plugin name for the router. 168 | /// 169 | public InstantMessagePlugin() 170 | { 171 | MethodName = "instant_message"; 172 | } 173 | 174 | /// 175 | /// Initialises the plugin. 176 | /// 177 | /// A currently active RestBot 178 | public override void Initialize(RestBot bot) 179 | { 180 | session = bot.sessionid; // why is this saved? It's never used... (gwyneth 20220213) 181 | me = bot; 182 | DebugUtilities.WriteDebug($"{session} {MethodName} startup"); 183 | 184 | base.Initialize(bot); // wtf is this for? (gwyneth 20220212) 185 | } 186 | 187 | /// 188 | /// Handler event for this plugin. 189 | /// 190 | /// A currently active RestBot 191 | /// A dictionary containing the message, avatar first and last name, or UUID 192 | public override string 193 | Process(RestBot b, Dictionary Parameters) 194 | { 195 | UUID avatarKey = UUID.Zero; 196 | bool check = true; 197 | string message = String.Empty; 198 | string avatarFirstName = String.Empty; 199 | string avatarLastName = String.Empty; 200 | 201 | if (Parameters.ContainsKey("key")) 202 | { 203 | check = 204 | UUID 205 | .TryParse(Parameters["key"].ToString().Replace("_", " "), 206 | out avatarKey); 207 | } 208 | else 209 | { 210 | if (Parameters.ContainsKey("last")) 211 | { 212 | avatarLastName = Parameters["last"]; 213 | } 214 | 215 | if (Parameters.ContainsKey("first")) 216 | { 217 | avatarFirstName = Parameters["first"]; 218 | check = true; 219 | } 220 | else 221 | check = false; 222 | 223 | // Massage the data we got; we can get away with an empty string for the last name (gwyneth 20220122). 224 | if (avatarLastName == String.Empty) 225 | { 226 | avatarLastName = "Resident"; 227 | check = true; 228 | } 229 | 230 | // InstantMessage *always* needs an avatar UUID! 231 | // We need to look it up; fortunately, there are plenty of options available to get those. 232 | String avatarFullName = 233 | avatarFirstName.ToString() + " " + avatarLastName.ToString(); 234 | 235 | avatarKey = Utilities.getKeySimple(b, avatarFullName); // handles conversion to lowercase. 236 | 237 | if (avatarKey == UUID.Zero) 238 | { 239 | DebugUtilities.WriteWarning($"Key not found for unknown avatar '{avatarFullName}'"); 240 | check = false; 241 | } 242 | else 243 | { 244 | DebugUtilities.WriteDebug($"Avatar '{avatarFullName}' has key '{avatarKey}'"); 245 | } 246 | } 247 | 248 | if (Parameters.ContainsKey("message")) 249 | { 250 | message = Parameters["message"]; 251 | if (message == String.Empty) 252 | { 253 | check = false; 254 | } 255 | } 256 | else 257 | check = false; 258 | 259 | if (!check) 260 | { 261 | return $"{MethodName}: wrong parameters passed; IM not sent"; 262 | } 263 | 264 | // make sure message is not too big (gwyneth 20220212) 265 | message = message.TrimEnd(); 266 | if (message.Length > 1023) /// 267 | { 268 | message = message.Remove(1023); 269 | } 270 | b.Client.Self.InstantMessage(avatarKey, message); 271 | return $"<{MethodName}>{avatarKey.ToString()}{message}"; 272 | } // end Process 273 | } // end InstantMessagePlugin 274 | } // end namespace 275 | -------------------------------------------------------------------------------- /restbot-plugins/ListenPlugin.cs: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------------------- 2 | FILE INFORMATION: 3 | Name: ListenPlugin.cs [./restbot-plugins/ListenPlugin.cs] 4 | Description: Listens to chat, and, if matched, calls URL for callback (gwyneth 20220213). 5 | 6 | LICENSE: 7 | This file is part of the RESTBot Project. 8 | 9 | Copyright (C) 2007-2008 PLEIADES CONSULTING, INC; (C) 2021,2022 Gwyneth Llewelyn 10 | 11 | This program is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU Affero General Public License as 13 | published by the Free Software Foundation, either version 3 of the 14 | License, or (at your option) any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU Affero General Public License for more details. 20 | 21 | You should have received a copy of the GNU Affero General Public License 22 | along with this program. If not, see . 23 | 24 | ---------------------------------------------------------------------------- 25 | 26 | Author: Gwyneth Llewelyn 27 | --------------------------------------------------------------------------------*/ 28 | using System; 29 | using System.Collections.Generic; 30 | using System.Linq; 31 | using System.Text; 32 | using OpenMetaverse; 33 | using OpenMetaverse.Utilities; 34 | 35 | namespace RESTBot 36 | { 37 | /// 38 | /// Watches for one line of chat, and, if found, returns that line. 39 | /// 40 | /// It's too hard to do it otherwise! 41 | /// Since: 8.1.5 42 | /// 43 | public class ListenPlugin : StatefulPlugin 44 | { 45 | /// System-wide registry for backend chat callbacks 46 | /// We'll probably not use it 47 | // static private Dictionary ListenCallbacks; 48 | 49 | private UUID session; 50 | 51 | /// manual reset event for listen 52 | ManualResetEvent ListenEvent = new ManualResetEvent(false); 53 | 54 | /// Chat line to be returned, with associated metadata 55 | ChatEventArgs? chatMetaData; 56 | 57 | /// Name of avatar or object that is chatting in-world 58 | private volatile string listenAgentName = String.Empty; 59 | /// UUID of avatar or object that is chatting in-world 60 | /// Needs to be a string, or you can't lock it (gwyneth 20220213) 61 | private volatile string listenAgentKey = UUID.Zero.ToString(); 62 | 63 | /// 64 | /// Sets the plugin name for the router. 65 | /// 66 | public ListenPlugin() 67 | { 68 | MethodName = "listen"; 69 | } 70 | 71 | /// 72 | /// Initialises the plugin. 73 | /// 74 | /// A currently active RestBot 75 | public override void Initialize(RestBot bot) 76 | { 77 | // ListenCallbacks = new Dictionary(); 78 | session = bot.sessionid; 79 | DebugUtilities.WriteDebug($"{session} {MethodName} startup"); 80 | 81 | base.Initialize(bot); 82 | } 83 | 84 | /// 85 | /// Handler event for this plugin. 86 | /// 87 | /// A currently active RestBot 88 | /// A dictionary containing an avatar or object name, or key (UUID) 89 | /// 90 | /// If the avatar/object name AND the key parameter are empty, 91 | /// this will match *any* avatar/object name (!) 92 | /// To-do: allow regexps in the name field 93 | /// To-do: allow selectively listening to objects/avatars in the same group as the bot 94 | /// 95 | public override string 96 | Process(RestBot b, Dictionary Parameters) 97 | { 98 | bool check = false; 99 | 100 | /// temporary, so we don't need to lock the name while accessing it 101 | string tempName = String.Empty; 102 | 103 | /// temporary, so we don't need to lock the key while the UUID is being parsed 104 | UUID tempKey = UUID.Zero; 105 | 106 | // Name can be either an avatar name, or an object name, we can listen to both (gwyneth 20220213) 107 | // Note that either one is optional, but if *both* are empty/invalid, then this will listen to anything! 108 | if (Parameters.ContainsKey("name")) 109 | { 110 | tempName = Parameters["name"].ToString().Replace("+", " "); 111 | 112 | if (tempName == String.Empty) 113 | { 114 | check = false; 115 | } 116 | else 117 | { 118 | lock (listenAgentName) // make it thread-safe! 119 | { 120 | listenAgentName = tempName; 121 | } 122 | check = true; 123 | } 124 | 125 | // very likely, this will fail if the name isn't an avatar, but an object, but we'll see, 126 | // it's possible that we can still do something useful upstream (gwyneth 20220213) 127 | tempKey = Utilities.getKeySimple(b, tempName); 128 | 129 | if (tempKey == UUID.Zero) 130 | { 131 | check = false; 132 | } 133 | else 134 | { 135 | lock (listenAgentKey) 136 | { 137 | listenAgentKey = tempKey.ToString(); 138 | } 139 | } 140 | 141 | check = true; 142 | } 143 | else if (Parameters.ContainsKey("key")) 144 | { 145 | check = UUID.TryParse(Parameters["key"].ToString().Replace("_", " "), out tempKey); 146 | 147 | if (tempKey == UUID.Zero) { 148 | check = false; 149 | } 150 | else 151 | { 152 | lock (listenAgentKey) 153 | { 154 | listenAgentKey = tempKey.ToString(); 155 | } 156 | check = true; 157 | } 158 | } 159 | else check = false; // neither contains name, nor key; we listen to everything instead! 160 | 161 | if (check == false) 162 | { 163 | DebugUtilities.WriteWarning("Listen called without valid name/UUID, we're listening to anything"); 164 | } 165 | else 166 | { 167 | DebugUtilities.WriteDebug($"Listen called, after parsing we're going to check for '{tempName}' and/or '{tempKey}'"); 168 | } 169 | 170 | // add the callback, and start listening 171 | b.Client.Self.ChatFromSimulator += Self_ChatFromSimulator; 172 | 173 | // start listening! Note that this should not be blocking on a timer, but for the sake 174 | // of expediency, we're pretending that all of this is synchronised and single-threaded... (gwyneth 20220213) 175 | ListenEvent.WaitOne(30000, false); 176 | 177 | /// Eventually, someone will type something, and that means our chatMetaData will be non-null. 178 | /// (gwyneth 20220214) 179 | if (chatMetaData != null) 180 | { 181 | if (chatMetaData != (ChatEventArgs) EventArgs.Empty) 182 | { 183 | string ret = $@"<{MethodName}> 184 | {chatMetaData.Simulator.ToString()} 185 | {chatMetaData.Message} 186 | {chatMetaData.AudibleLevel.ToString()} 187 | {chatMetaData.Type.ToString()} 188 | {chatMetaData.SourceType.ToString()} 189 | {chatMetaData.FromName} 190 | {chatMetaData.SourceID.ToString()} 191 | {chatMetaData.OwnerID.ToString()} 192 | {chatMetaData.Position.ToString()} 193 | "; 194 | 195 | DebugUtilities.WriteDebug($"Captured message XML: {ret}"); 196 | return ret; 197 | } 198 | else 199 | { 200 | DebugUtilities.WriteError($"Error retrieving chatMetaData, got: '{chatMetaData.ToString()}'"); 201 | return "Listen returned error or empty message"; 202 | } 203 | } 204 | else 205 | { 206 | // shouldn't happen... 207 | DebugUtilities.WriteError("Error retrieving chatMetaData, was null"); 208 | return "null"; 209 | } 210 | } 211 | 212 | /* Note: this is the definition of a ChatEventArgs from LibreMetaverse/AgentManager.cs, just copied here for reference: (gwyneth 20220213) 213 | /// Get the simulator sending the message 214 | public Simulator Simulator { get; } 215 | 216 | /// Get the message sent 217 | public string Message { get; } 218 | 219 | /// Get the audible level of the message 220 | public ChatAudibleLevel AudibleLevel { get; } 221 | 222 | /// Get the type of message sent: whisper, shout, etc 223 | public ChatType Type { get; } 224 | 225 | /// Get the source type of the message sender 226 | public ChatSourceType SourceType { get; } 227 | 228 | /// Get the name of the agent or object sending the message 229 | public string FromName { get; } 230 | 231 | /// Get the ID of the agent or object sending the message 232 | public UUID SourceID { get; } 233 | 234 | /// Get the ID of the object owner, or the agent ID sending the message 235 | public UUID OwnerID { get; } 236 | 237 | /// Get the position of the agent or object sending the message 238 | public Vector3 Position { get; } 239 | */ 240 | 241 | /// Callback that returns something in chat 242 | void Self_ChatFromSimulator(object? sender, ChatEventArgs e) 243 | { 244 | if (e.Message.Length > 0 && e.AudibleLevel == ChatAudibleLevel.Fully && e.Type != ChatType.StartTyping && e.Type != ChatType.StopTyping) 245 | { 246 | // Check if we have valid key and name 247 | 248 | // lock only if it is set! 249 | if (chatMetaData != null) 250 | { 251 | lock (chatMetaData) 252 | { 253 | chatMetaData = e; 254 | } 255 | } 256 | else 257 | { 258 | chatMetaData = e; 259 | } 260 | } 261 | } // end Self_ChatFromSimulator 262 | } // end class 263 | } //end namespace -------------------------------------------------------------------------------- /restbot-plugins/PrimsPlugin.cs: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------------------- 2 | LICENSE: 3 | This file is part of the RESTBot Project. 4 | 5 | Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU Affero General Public License as 9 | published by the Free Software Foundation, either version 3 of the 10 | License, or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Affero General Public License for more details. 16 | 17 | You should have received a copy of the GNU Affero General Public License 18 | along with this program. If not, see . 19 | 20 | Author: Brian Krisler bkrisler@gmail.com 21 | --------------------------------------------------------------------------------*/ 22 | using System; 23 | using System.Collections.Generic; 24 | using System.Text; 25 | using OpenMetaverse; 26 | using System.Threading; 27 | 28 | namespace RESTBot 29 | { 30 | public class NearbyPrimsPlugin : StatefulPlugin 31 | { 32 | private UUID session; 33 | private RestBot? me; // may be null... 34 | 35 | Dictionary PrimsWaiting = new Dictionary(); 36 | AutoResetEvent AllPropertiesReceived = new AutoResetEvent(false); 37 | 38 | public NearbyPrimsPlugin() 39 | { 40 | MethodName = "nearby_prims"; 41 | } 42 | 43 | public override void Initialize(RestBot bot) 44 | { 45 | session = bot.sessionid; 46 | me = bot; 47 | DebugUtilities.WriteDebug($"{session} {MethodName} startup"); 48 | 49 | base.Initialize(bot); 50 | } 51 | 52 | public override string Process(RestBot b, Dictionary Parameters) 53 | { 54 | try 55 | { 56 | string type = String.Empty; 57 | bool check = true; 58 | float radius = 0.0f; 59 | 60 | if (Parameters.ContainsKey("type")) 61 | { 62 | type = Parameters["type"].ToString().Replace("+", " "); 63 | } 64 | else check = false; 65 | 66 | if (Parameters.ContainsKey("radius")) 67 | { 68 | check &= float.TryParse(Parameters["radius"], out radius); 69 | } 70 | else check = false; 71 | 72 | if (!check) 73 | { 74 | return "parameters have to be type, radius"; 75 | } 76 | 77 | // *** get current location *** 78 | Vector3 location = b.Client.Self.SimPosition; 79 | 80 | // *** find all objects in radius *** 81 | List prims = b.Client.Network.CurrentSim.ObjectsPrimitives.FindAll( 82 | delegate(Primitive prim) 83 | { 84 | Vector3 pos = prim.Position; 85 | return (prim.ParentID == 0) && (pos != Vector3.Zero) && (Vector3.Distance(pos, location) < radius); 86 | } 87 | ); 88 | 89 | // *** request properties of these objects *** 90 | bool complete = RequestObjectProperties(prims, 0); 91 | 92 | String resultSet = String.Empty; 93 | 94 | foreach (Primitive p in prims) 95 | { 96 | string? name = p.Properties != null ? p.Properties.Name : null; 97 | if (String.IsNullOrEmpty(type) || ((name != null) && (name.Contains(type)))) 98 | { 99 | resultSet += $"{name}{p.Position.X},{p.Position.Y},{p.Position.Z}{p.ID}"; 100 | } 101 | } 102 | return "" + resultSet + ""; 103 | } 104 | catch (Exception e) 105 | { 106 | DebugUtilities.WriteError(e.Message); 107 | return $"{e.Message}"; 108 | } 109 | } 110 | 111 | private bool RequestObjectProperties(List objects, int msPerRequest) 112 | { 113 | // Create an array of the local IDs of all the prims we are requesting properties for 114 | uint[] localids = new uint[objects.Count]; 115 | 116 | lock (PrimsWaiting) 117 | { 118 | PrimsWaiting.Clear(); 119 | 120 | for (int i = 0; i < objects.Count; ++i) 121 | { 122 | localids[i] = objects[i].LocalID; 123 | PrimsWaiting.Add(objects[i].ID, objects[i]); 124 | } 125 | } 126 | if (me == null) // it _can_ be null these days, so we return false (gwyneth 20220126) 127 | return false; 128 | 129 | me.Client.Objects.SelectObjects(me.Client.Network.CurrentSim, localids); 130 | 131 | return AllPropertiesReceived.WaitOne(2000 + msPerRequest * objects.Count, false); 132 | } 133 | } 134 | 135 | public class NearbyPrimPlugin : StatefulPlugin 136 | { 137 | private UUID session; 138 | private RestBot? me; 139 | 140 | Dictionary PrimsWaiting = new Dictionary(); 141 | AutoResetEvent AllPropertiesReceived = new AutoResetEvent(false); 142 | 143 | public NearbyPrimPlugin() 144 | { 145 | MethodName = "nearby_prim"; 146 | } 147 | 148 | public override void Initialize(RestBot bot) 149 | { 150 | session = bot.sessionid; 151 | me = bot; 152 | DebugUtilities.WriteDebug($"{session} {MethodName} startup"); 153 | 154 | base.Initialize(bot); 155 | } 156 | 157 | public override string Process(RestBot b, Dictionary Parameters) 158 | { 159 | try 160 | { 161 | string type = String.Empty; 162 | bool check = true; 163 | float radius = 0.0f; 164 | 165 | if (Parameters.ContainsKey("type")) 166 | { 167 | type = Parameters["type"].ToString().Replace("+", " "); 168 | } 169 | else check = false; 170 | 171 | if (Parameters.ContainsKey("radius")) 172 | { 173 | check &= float.TryParse(Parameters["radius"], out radius); 174 | } 175 | else check = false; 176 | 177 | if (!check) 178 | { 179 | return "parameters have to be type, radius"; 180 | } 181 | 182 | // *** get current location *** 183 | Vector3 location = b.Client.Self.SimPosition; 184 | 185 | Primitive found = b.Client.Network.CurrentSim.ObjectsPrimitives.Find( 186 | delegate(Primitive prim) { 187 | return prim.Properties.Name == type; 188 | }); 189 | 190 | 191 | return $"{found.Position.X},{found.Position.Y},{found.Position.Z}"; 192 | } 193 | catch (Exception e) 194 | { 195 | DebugUtilities.WriteError(e.Message); 196 | return $"{MethodName}: {e.Message}"; 197 | } 198 | } 199 | 200 | private bool RequestObjectProperties(List objects, int msPerRequest) 201 | { 202 | // Create an array of the local IDs of all the prims we are requesting properties for 203 | uint[] localids = new uint[objects.Count]; 204 | 205 | lock (PrimsWaiting) 206 | { 207 | PrimsWaiting.Clear(); 208 | 209 | for (int i = 0; i < objects.Count; ++i) 210 | { 211 | localids[i] = objects[i].LocalID; 212 | PrimsWaiting.Add(objects[i].ID, objects[i]); 213 | } 214 | } 215 | if (me == null) // it _can_ be null these days, so we return false (gwyneth 20220213) 216 | return false; 217 | 218 | me.Client.Objects.SelectObjects(me.Client.Network.CurrentSim, localids); 219 | 220 | return AllPropertiesReceived.WaitOne(2000 + msPerRequest * objects.Count, false); 221 | } 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /restbot-plugins/ReaperPlugin.cs: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------------------- 2 | LICENSE: 3 | This file is part of the RESTBot Project. 4 | 5 | Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU Affero General Public License as 9 | published by the Free Software Foundation, either version 3 of the 10 | License, or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Affero General Public License for more details. 16 | 17 | You should have received a copy of the GNU Affero General Public License 18 | along with this program. If not, see . 19 | --------------------------------------------------------------------------------*/ 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Text; 23 | using OpenMetaverse; 24 | using OpenMetaverse.Packets; 25 | using System.Net; 26 | using System.Threading; 27 | using System.Timers; 28 | 29 | // avatar info functions 30 | namespace RESTBot 31 | { 32 | /// 33 | /// This SEEMS to clean up stalled sessions, i.e. bots that haven't logged out properly 34 | /// and are now in 'zombie' state (gwyneth 20220109) 35 | /// 36 | public static class Reaper 37 | { 38 | /// 39 | /// Session timeout timespan; default is one hour 40 | /// 41 | static readonly TimeSpan SESSION_TIMEOUT = Program.config != null ? Program.config.plugin.reaperSessionTimeout : TimeSpan.Zero; 42 | /// 43 | /// interval between reaper sweeps in ms; default is 10 seconds 44 | /// 45 | static readonly double REAPER_INTERVAL = Program.config != null ? Program.config.plugin.reaperSweepInterval : 10000; 46 | 47 | private static bool hasAlreadyStarted = false; 48 | 49 | /// Running timer for killing bot sessions 50 | public static System.Timers.Timer? ReaperTimer; // weirdly, this can be null?... 51 | 52 | /// 53 | /// Reaper Plugin Initialisation. 54 | /// 55 | public static void Init() 56 | { 57 | if (!hasAlreadyStarted && Program.config != null && Program.config.plugin.reaper != false) 58 | { 59 | hasAlreadyStarted = true; 60 | ReaperTimer = new System.Timers.Timer(); 61 | ReaperTimer.Interval = REAPER_INTERVAL; 62 | ReaperTimer.Elapsed += new ElapsedEventHandler(Reaper_Elapsed); 63 | ReaperTimer.Start(); 64 | } 65 | } 66 | 67 | static void Reaper_Elapsed(object? sender, System.Timers.ElapsedEventArgs e) 68 | { 69 | if (Program.Sessions == null) 70 | { 71 | // No sessions to worry about, we can return safely. 72 | return; 73 | } 74 | 75 | // If the configuration says we shouldn't run the Reaper, return. (gwyneth 20220412) 76 | if (Program.config != null && Program.config.plugin.reaper != true) 77 | { 78 | return; 79 | } 80 | 81 | List kc = new List(); 82 | foreach (UUID key in Program.Sessions.Keys) //why not just lock() ? :P 83 | { 84 | kc.Add(key); 85 | } 86 | //Do reaping 87 | foreach (UUID key in kc) 88 | { 89 | if (Program.Sessions.ContainsKey(key)) 90 | { 91 | DateTime t = DateTime.Now; 92 | TimeSpan ts = t.Subtract(Program.Sessions[key].LastAccessed); 93 | if (ts > SESSION_TIMEOUT) 94 | { 95 | DebugUtilities.WriteWarning("Session expiring, " + key.ToString() + ", timespan=" + ts.ToString()); 96 | Program.DisposeSession(key); 97 | } 98 | } 99 | } 100 | } 101 | } 102 | 103 | /// Settimg up main class as a Stateful Plugin 104 | public class ReaperPlugin : StatefulPlugin 105 | { 106 | private UUID session; 107 | 108 | /// Constructor 109 | public ReaperPlugin() 110 | { 111 | MethodName = "reaper_info"; 112 | } 113 | 114 | /// Initialisation 115 | public override void Initialize(RestBot bot) 116 | { 117 | session = bot.sessionid; 118 | // double-checking this, because I really, really want to force a configuration override to turn this off! 119 | // (gwyneth 20220412) 120 | if (Program.config != null && Program.config.plugin.reaper == true) 121 | { 122 | DebugUtilities.WriteDebug($"{session} {MethodName} startup"); 123 | Reaper.Init(); //start up the reaper if we havent already (the check to see if we have is in this function) 124 | } 125 | else 126 | { 127 | DebugUtilities.WriteDebug(session + " REAPER not starting due to configuration override"); 128 | } 129 | } 130 | 131 | /// Whatever needs to get processed... apparently. nothing 132 | public override string Process(RestBot b, Dictionary Parameters) 133 | { 134 | return "notprocessed"; 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /restbot-plugins/StatsPlugin.cs: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------------------- 2 | LICENSE: 3 | This file is part of the RESTBot Project. 4 | 5 | Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU Affero General Public License as 9 | published by the Free Software Foundation, either version 3 of the 10 | License, or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Affero General Public License for more details. 16 | 17 | You should have received a copy of the GNU Affero General Public License 18 | along with this program. If not, see . 19 | --------------------------------------------------------------------------------*/ 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Text; 23 | using OpenMetaverse; 24 | using System.Net; 25 | using System.Threading; 26 | 27 | namespace RESTBot 28 | { 29 | /// 30 | /// Class to return the current simulator dilation (a measure of lag). 31 | /// 32 | public class DilationPlugin : RestPlugin 33 | { 34 | /// 35 | /// Sets the plugin name for the router. 36 | /// 37 | public DilationPlugin() 38 | { 39 | MethodName = "dilation"; 40 | } 41 | 42 | /// 43 | /// Handler event for this plugin. 44 | /// 45 | /// A currently active RestBot 46 | /// not used 47 | public override string Process(RestBot b, Dictionary Parameters) 48 | { 49 | b.Client.Settings.ALWAYS_DECODE_OBJECTS = true; 50 | 51 | string dilation = b.Client.Network.CurrentSim.Stats.Dilation.ToString(); 52 | b.Client.Settings.ALWAYS_DECODE_OBJECTS = false; 53 | return $"<{MethodName}>{dilation}"; 54 | } 55 | } 56 | 57 | /// 58 | /// Class to return full statistics of the simulator the 'bot is in. 59 | /// 60 | public class SimStatPlugin : RestPlugin 61 | { 62 | /// 63 | /// Sets the plugin name for the router. 64 | /// 65 | public SimStatPlugin() 66 | { 67 | MethodName = "sim_stat"; 68 | } 69 | 70 | /// 71 | /// Handler event for this plugin. 72 | /// 73 | /// A currently active RestBot 74 | /// not used 75 | /// This will list statistics only for the simulator where the 'bot currently is. 76 | public override string Process(RestBot b, Dictionary Parameters) 77 | { 78 | bool check = false; 79 | while ( !check ) { 80 | if ( b.Client.Network.CurrentSim.Stats.FPS != 0 ) { 81 | check = true; 82 | } 83 | } 84 | string response = $@"<{MethodName}> 85 | {b.Client.Network.CurrentSim.Stats.Dilation.ToString()} 86 | {b.Client.Network.CurrentSim.Stats.IncomingBPS.ToString()} 87 | {b.Client.Network.CurrentSim.Stats.OutgoingBPS.ToString()} 88 | {b.Client.Network.CurrentSim.Stats.ResentPackets.ToString()} 89 | {b.Client.Network.CurrentSim.Stats.ReceivedResends.ToString()} 90 | {b.Client.Network.InboxCount.ToString()} 91 | {b.Client.Network.CurrentSim.Stats.FPS.ToString()} 92 | {b.Client.Network.CurrentSim.Stats.PhysicsFPS.ToString()} 93 | {b.Client.Network.CurrentSim.Stats.AgentUpdates.ToString()} 94 | {b.Client.Network.CurrentSim.Stats.Objects.ToString()} 95 | {b.Client.Network.CurrentSim.Stats.ScriptedObjects.ToString()} 96 | {b.Client.Network.CurrentSim.Stats.Agents.ToString()} 97 | {b.Client.Network.CurrentSim.Stats.ChildAgents.ToString()} 98 | {b.Client.Network.CurrentSim.Stats.ActiveScripts.ToString()} 99 | {b.Client.Network.CurrentSim.Stats.LSLIPS.ToString()} 100 | {b.Client.Network.CurrentSim.Stats.INPPS.ToString()} 101 | {b.Client.Network.CurrentSim.Stats.OUTPPS.ToString()} 102 | {b.Client.Network.CurrentSim.Stats.PendingDownloads.ToString()} 103 | {b.Client.Network.CurrentSim.Stats.PendingUploads.ToString()} 104 | {b.Client.Network.CurrentSim.Stats.VirtualSize.ToString()} 105 | {b.Client.Network.CurrentSim.Stats.ResidentSize.ToString()} 106 | {b.Client.Network.CurrentSim.Stats.PendingLocalUploads.ToString()} 107 | {b.Client.Network.CurrentSim.Stats.UnackedBytes.ToString()} 108 | 115 | "; 116 | return response; 117 | } 118 | } 119 | 120 | /// 121 | /// Class to return all currently valid sessions and associated avatar key. 122 | /// 123 | /// I need this to check upstream which RESTbots have valid sessions. 124 | /// (gwyneth 20220424) 125 | /// 126 | public class SessionListPlugin : RestPlugin 127 | { 128 | /// 129 | /// Sets the plugin name for the router. 130 | /// 131 | public SessionListPlugin() 132 | { 133 | MethodName = "session_list"; 134 | } 135 | 136 | /// 137 | /// Handler event for this plugin. 138 | /// 139 | /// A currently active RestBot 140 | /// not used 141 | /// This will list all currently known sessions. 142 | /// Also note that there is a way to retrieve all sessions (same method name) 143 | /// without requiring a valid bot session, just for my own purposes; 144 | /// 145 | public override string Process(RestBot b, Dictionary Parameters) 146 | { 147 | bool check = false; 148 | if (Program.Sessions.Count != 0) // no sessions? that's fine, no need to abort 149 | { 150 | check = true; 151 | } 152 | 153 | string response = $"<{MethodName}>"; 154 | if (check) // optimisation: if empty, no need to run the foreach (gwyneth 20220424) 155 | { 156 | foreach(KeyValuePair kvp in Program.Sessions) 157 | { 158 | if (kvp.Value.Bot != null && kvp.Value.Bot.Client != null && kvp.Value.Bot.Client.Self != null && kvp.Value.Bot.Client.Network != null) 159 | { 160 | response += $@" 161 | 162 | {kvp.Key.ToString()} 163 | {kvp.Value.Bot.Client.Self.AgentID.ToString()} 164 | {kvp.Value.Bot.Client.Self.FirstName} {kvp.Value.Bot.Client.Self.LastName} 165 | {kvp.Value.Bot.Client.Self.FirstName} 166 | {kvp.Value.Bot.Client.Self.LastName} 167 | {kvp.Value.Bot.myStatus.ToString()} 168 | {kvp.Value.Bot.getUptimeISO8601()} 169 | {kvp.Value.Bot.Start} 170 | {kvp.Value.Bot.Client.Network.CurrentSim.ToString()} 171 | {kvp.Value.Bot.Client.Self.SimPosition.X},{kvp.Value.Bot.Client.Self.SimPosition.Y},{kvp.Value.Bot.Client.Self.SimPosition.Z} 172 | {kvp.Value.Bot.Client.Self.SimRotation.X},{kvp.Value.Bot.Client.Self.SimRotation.Y},{kvp.Value.Bot.Client.Self.SimRotation.Z},{kvp.Value.Bot.Client.Self.SimRotation.W} 173 | "; 174 | } 175 | else 176 | { 177 | // Somehow, we have a session ID that has no bot assigned; 178 | // this should never be the case, but... (gwyneth 20220426) 179 | response += $"{kvp.Key.ToString()}{UUID.Zero.ToString()}"; 180 | } 181 | } 182 | } 183 | else 184 | { 185 | response += "no sessions"; 186 | } 187 | response += $""; 188 | return response; 189 | } // end Process 190 | } // end SessionListPlugin 191 | } // end namespace 192 | -------------------------------------------------------------------------------- /restbot-src/Configuration.cs: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------------------- 2 | FILE INFORMATION: 3 | Name: Configuration.cs [./restbot-src/Configuration.cs] 4 | Description: This file contains classes used by the .net's internal xml parser 5 | to define configuration options as seen in configuration.xml. 6 | 7 | LICENSE: 8 | This file is part of the RESTBot Project. 9 | 10 | Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Affero General Public License as 14 | published by the Free Software Foundation, either version 3 of the 15 | License, or (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Affero General Public License for more details. 21 | 22 | You should have received a copy of the GNU Affero General Public License 23 | along with this program. If not, see . 24 | 25 | Additional (sub)classes by Gwyneth Llewelyn in 2022 26 | --------------------------------------------------------------------------------*/ 27 | using System; 28 | using System.Collections; 29 | using System.Collections.Generic; 30 | using System.IO; 31 | using System.Text; 32 | using System.Xml; 33 | using System.Xml.Serialization; 34 | 35 | namespace RESTBot.XMLConfig 36 | { 37 | /// 38 | /// Configuration class designed for the `bots array found in the xml config file 39 | /// 40 | /// To find a copy of this class, see the Configuration class 41 | [XmlRoot("restbot")] 42 | public class Configuration 43 | { 44 | [XmlElement("networking")] 45 | public NetworkConfig networking = new NetworkConfig(); 46 | 47 | [XmlElement("debug")] 48 | public DebugConfig debug = new DebugConfig(); 49 | 50 | [XmlElement("location")] 51 | public StartLocationConfig location = new StartLocationConfig(); 52 | 53 | [XmlElement("security")] 54 | public SecurityConfig security = new SecurityConfig(); 55 | 56 | [XmlElement("plugin")] 57 | public PluginConfig plugin = new PluginConfig(); 58 | 59 | /// The default URI to connect to the Linden Lab grid 60 | public static string 61 | defaultLoginURI = "https://login.agni.lindenlab.com/cgi-bin/login.cgi"; 62 | 63 | /// 64 | /// Load the configuration file (if it exists). 65 | /// 66 | /// path to the configuration file 67 | public static Configuration? LoadConfiguration(string configuration_file) 68 | { 69 | XmlSerializer? serializer = new XmlSerializer(typeof(Configuration)); 70 | FileStream? fileStream = null; 71 | try 72 | { 73 | fileStream = new FileStream(configuration_file, FileMode.Open); 74 | } 75 | catch (Exception e) 76 | { 77 | DebugUtilities.WriteError("Could not open configuration file; error was: " + e.Message); 78 | Environment.Exit(1); 79 | } 80 | try 81 | { 82 | // fileStream/serializer are now nullable; return null if that's the case. (gwyneth 20220127) 83 | if (fileStream != null && serializer != null) 84 | { 85 | fileStream.Seek(0, SeekOrigin.Begin); 86 | return (Configuration?) serializer.Deserialize(fileStream); 87 | } 88 | } 89 | catch (Exception e) 90 | { 91 | DebugUtilities.WriteError("Could not parse XML file - error was: " + e.Message); 92 | Environment.Exit(1); // this is overkill... we might be able to deal with most errors using reasonable defaults... (gwyneth 20220127) 93 | } 94 | return null; 95 | } // end constructor 96 | } // end class Configuration 97 | } // end namespace RESTBot.XMLConfig, but, weirdly enough, it continues below... 98 | 99 | namespace RESTBot.XMLConfig 100 | { 101 | /// Class to define the network configuration 102 | /// It sets a few reasonable defaults 103 | public class NetworkConfig 104 | { 105 | [XmlElement("ip")] 106 | /// IP address ought to be set to 127.0.0.1 for localhost connections only; 107 | /// use 0.0.0.0 to have it bound to _all_ interfaces and be accessible from the Internet 108 | public string ip = "0.0.0.0"; 109 | 110 | [XmlElement("port")] 111 | public int port = 9080; 112 | 113 | [XmlElement("loginuri")] 114 | /// for special login url. You gotta have a compatible libsl version though!! 115 | public string loginuri = Configuration.defaultLoginURI; 116 | 117 | [XmlElement("throttle")] 118 | public float throttle = 1572864.0f; 119 | 120 | [XmlElement("webapi-url")] 121 | /// What _is_ this!? It's not included anywhere... (gwyneth 20220109) 122 | public string backendURL = "https://localhost/actorbot/pipe.php"; 123 | } 124 | 125 | /// Class to configure the start location 126 | public class StartLocationConfig 127 | { 128 | //TODO: Make x,y,z floats but round them off when using them (this is so the parser can read a decimal instead of errroring out) 129 | [XmlElement("sim")] 130 | /// Name of the region for the RESTbot to start, by default 131 | public string startSim = "strace island"; // 'Ahern' ought to be a better default... (gwyneth 20220109) 132 | 133 | [XmlElement("x")] 134 | public int x = 128; 135 | 136 | [XmlElement("y")] 137 | public int y = 128; 138 | 139 | [XmlElement("z")] 140 | public int z = 128; /// 20 or 30 ought to be more reasonable starting points, since that's the level that water is set (gwyneth 20220109) 141 | } 142 | 143 | /// Class to deal with debugging 144 | /// 145 | /// [Original comment:] itty bitty file - can be expanded onto later 146 | /// Note that the DebugUtilities class checks if the restbotDebug variable is set, falling back to hard-coded #defines if not (gwyneth 20220109) 147 | /// Also note that you can have both settings simultaneously configured 148 | /// Note that if Log4Net is wrongly configured (using restbot.exe.config), 149 | /// everything will get logged to the console instead (duplicate messages possible) 150 | /// 151 | public class DebugConfig 152 | { 153 | [XmlElement("restbot")] 154 | /// Log debugging specific to RESTbot 155 | public bool restbotDebug = false; 156 | 157 | [XmlElement("libsl")] 158 | /// Log debugging specific to the underlying LibreMetaverse layer 159 | /// probably ignored (gwyneth 20220427) 160 | public bool slDebug = true; 161 | } 162 | 163 | /// Class to deal with security configurations 164 | /// Password MUST be changed when in production! (gwyneth 20220109) 165 | public class SecurityConfig 166 | { 167 | [XmlElement("hostnamelock")] 168 | /// I have no idea what this is for... 169 | public bool hostnameLock = false; 170 | 171 | [XmlElement("serverpassword")] 172 | /// Main server password, used in the API; please change it! 173 | /// Should be a URL-safe password, so beware of very strange unencoded characters.. (gwyneth 20220427) 174 | public string serverPass = "pass"; // Change me! 175 | } 176 | 177 | /// 178 | /// Class to deal with specific plugin configurations 179 | /// 180 | /// Since 8.1.5 181 | /// Here we will have a few special debug flags for plugins that have zero configuration 182 | /// and were never meant to be configured manually. 183 | /// Currently only used for the Reaper plugin, but more may be added in the future! 184 | /// 185 | public class PluginConfig 186 | { 187 | [XmlElement("reaper")] 188 | /// The Reaper plugin seems to have no possible configuration to turn on/off, so we set it here 189 | public bool reaper = true; 190 | 191 | [XmlElement("reaper-session-timeout")] 192 | /// Session timeout timespan 193 | public TimeSpan reaperSessionTimeout = new TimeSpan(1, 0, 0); // default: one hour (h, m, s) 194 | 195 | [XmlElement("reaper-sweep-interval")] 196 | /// interval between reaper sweeps in ms 197 | public double reaperSweepInterval = 10000; // default: 10 seconds 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /restbot-src/RestPlugin.cs: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------------------- 2 | FILE INFORMATION: 3 | Name: RestPlugin.cs [./restbot-src/RestPlugin.cs] 4 | Description: This file defines the prototypes used in any restbot plugin 5 | 6 | LICENSE: 7 | This file is part of the RESTBot Project. 8 | 9 | Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 10 | 11 | This program is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU Affero General Public License as 13 | published by the Free Software Foundation, either version 3 of the 14 | License, or (at your option) any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU Affero General Public License for more details. 20 | 21 | You should have received a copy of the GNU Affero General Public License 22 | along with this program. If not, see . 23 | --------------------------------------------------------------------------------*/ 24 | using System; 25 | using System.Collections.Generic; 26 | using System.Net; 27 | using System.Text; 28 | 29 | namespace RESTBot 30 | { 31 | /// 32 | /// A base class for REST plugins 33 | /// 34 | public abstract class RestPlugin 35 | { 36 | /// 37 | /// The name of the method. Should be set in the constructor. 38 | /// 39 | public string MethodName = "unknown"; // cannot be null! (gwyneth 20220126) 40 | 41 | /// 42 | /// Process the request through this method. 43 | /// 44 | /// The RestBot that is doing the processing 45 | /// QueryString and POST parameters 46 | /// XML output 47 | public abstract string Process(RestBot b, Dictionary Parameters); 48 | } 49 | 50 | /// 51 | /// A base class for stateful plugins, ie those requiring actions on events from a specific 52 | /// instance of LibreMetaverse or RestBot 53 | /// 54 | /// Shouldn't be this a derived class from RestPlugin? 🤔 (gwyneth 20220424) 55 | public abstract class StatefulPlugin : RestPlugin 56 | { 57 | /// 58 | /// The name of the method. Should be set in the constructor. 59 | /// 60 | // public string MethodName = "unknown"; // making sure it's never null. (gwyneth 20220126) 61 | 62 | /// 63 | /// An optionally overridable method for setting up events and callbacks from a RestBot 64 | /// 65 | /// 66 | public virtual void Initialize(RestBot bot) 67 | { 68 | } 69 | 70 | /// 71 | /// Process the request through this method 72 | /// 73 | /// The RestBot that is doing the processing 74 | /// QueryString and POST parameters 75 | /// XML output 76 | // public abstract string Process(RestBot b, Dictionary Parameters); 77 | 78 | /// Indicates that the current plugin is actively running. 79 | public bool Active; 80 | 81 | /// Implement to perform actions that require updates over time. 82 | public virtual void Think() 83 | { 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /restbot-src/Server/HeaderConstructor.cs: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------------------- 2 | FILE INFORMATION: 3 | Name: HeaderConstructor.cs [./restbot-src/Server/HeaderConstructor.cs] 4 | Description: Contains methods used to create headers for an HTTP response 5 | 6 | LICENSE: 7 | This file is part of the RESTBot Project. 8 | 9 | Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 10 | 11 | This program is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU Affero General Public License as 13 | published by the Free Software Foundation, either version 3 of the 14 | License, or (at your option) any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU Affero General Public License for more details. 20 | 21 | You should have received a copy of the GNU Affero General Public License 22 | along with this program. If not, see . 23 | --------------------------------------------------------------------------------*/ 24 | using System; 25 | using System.Collections.Generic; 26 | using System.Text; 27 | 28 | namespace RESTBot.Server 29 | { 30 | /// 31 | /// Generates a response header line with HTTP status code and given reason for that status. 32 | /// 33 | /// I believe this will only cover the most basic HTTP codes, as some require bodies as well (gwyneth 20220425) 34 | public class ResponseStatus 35 | { 36 | /// A valid HTTP status code, e.g. 100, 200, 404, 503, etc. 37 | public int StatusCode; 38 | 39 | /// Reason for given status code. 40 | /// Traditionally, these are (semi-)standard and could be a lookup table (gwyneth 20220425) 41 | public string StatusReason; 42 | 43 | /// Constructor 44 | /// A valid HTTP code, e.g. 100, 200, 404, 503, etc. 45 | /// Reason given for the above status code 46 | /// So-called "reason" is almost standard these days and should not be overriden... (gwyneth 20220425) 47 | public ResponseStatus(int code, string reason) 48 | { 49 | StatusCode = code; 50 | StatusReason = reason; 51 | } 52 | 53 | /// Converts internal representation of a ResponseStatus to a string. 54 | /// The converted string, which will at least be a single, empty space character... 55 | public override string ToString() 56 | { 57 | return $"{StatusCode} {StatusReason}"; 58 | } 59 | } 60 | 61 | /// 62 | /// Class to generate the properly-formatted response header, including status code. 63 | /// 64 | public class HeaderResponseLine 65 | { 66 | private ResponseStatus _status = new ResponseStatus(200, "OK"); 67 | 68 | private string _http_version = ""; //Something that might be usefull, eg. HTTP/1.1 69 | 70 | /// Returns the status of the request, which is a ResponseStatus object 71 | public ResponseStatus Status 72 | { 73 | get 74 | { 75 | return _status; 76 | } 77 | } 78 | 79 | /// Returns the HTTP version 80 | /// I believe that only 1.0 or 1.1 will make sense here... (gwyneth 20220425) 81 | public string HttpVersion 82 | { 83 | get 84 | { 85 | return _http_version; 86 | } 87 | } 88 | 89 | private void CreateHeaderResponseLine( 90 | string http_version, 91 | ResponseStatus status 92 | ) 93 | { 94 | _http_version = http_version; 95 | _status = status; 96 | } 97 | 98 | /// 99 | /// Creates a header response line, from the status code and a previously created ResponseStatus object. 100 | /// 101 | public HeaderResponseLine(string http_version, ResponseStatus status) 102 | { 103 | CreateHeaderResponseLine(http_version, status); 104 | } 105 | 106 | /// 107 | /// Overloaded version including a string with a reason for the status, which will be 108 | /// used to (internally) create a ResponseStatus object. 109 | /// 110 | public HeaderResponseLine( 111 | string http_version, 112 | int status_code, 113 | string status_reason 114 | ) 115 | { 116 | ResponseStatus status = new ResponseStatus(status_code, status_reason); 117 | CreateHeaderResponseLine(http_version, status); 118 | } 119 | 120 | /// Converts the HTTP version and the current status (code + reason) to a string 121 | /// Converted string (at least one space character will be returned) 122 | public override string ToString() 123 | { 124 | return $"{_http_version} {_status.ToString()}"; 125 | } 126 | } 127 | 128 | /// Class to generate properly-formatted response headers 129 | /// Assumes that the response will be XML; note that we might have JSON 130 | /// as an option in the future, which will require a few overloaded methods here 131 | /// (gwyneth 20220425) 132 | public class ResponseHeaders 133 | { 134 | /// The following _may_ be null... 135 | public HeaderResponseLine? ResponseLine; 136 | 137 | public List? HeaderLines; 138 | 139 | private void CreateResponseHeaders( 140 | int status, 141 | string status_response, 142 | string content_type 143 | ) 144 | { 145 | ResponseLine = 146 | new HeaderResponseLine("HTTP/1.1", 147 | new ResponseStatus(status, status_response)); //some defaults 148 | HeaderLines = new List(); 149 | 150 | HeaderLines 151 | .Add(new HeaderLine("Date", 152 | DateTime.Now.ToUniversalTime().ToLongDateString())); 153 | HeaderLines.Add(new HeaderLine("Server", "RestBotRV/" + Program.Version)); 154 | HeaderLines.Add(new HeaderLine("Content-type", content_type)); 155 | } 156 | 157 | private ResponseHeaders( 158 | int status, 159 | string status_response, 160 | string content_type 161 | ) 162 | { 163 | CreateResponseHeaders(status, status_response, content_type); 164 | } 165 | 166 | /// Creates the full reponse headers for a XML reply 167 | public ResponseHeaders(int status, string status_response) 168 | { 169 | CreateResponseHeaders(status, status_response, "text/xml"); 170 | } 171 | 172 | /// Converts a response/header line to a string representation 173 | /// Converted string, or just a line break if reponse/headers missing 174 | public override string ToString() 175 | { 176 | // Do we have any headers at all? (gwyneth 20220213) 177 | if (ResponseLine != null && HeaderLines != null) 178 | { 179 | string headers = ResponseLine.ToString() + "\r\n"; //initial header response line 180 | foreach (HeaderLine line in HeaderLines) 181 | { 182 | headers += line.ToString() + "\r\n"; 183 | } 184 | headers += "\r\n"; //finish up the headers.. a \r\n\r\n signifies a change between headers and the body 185 | return headers; 186 | } 187 | return "\r\n"; 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /restbot-src/Server/HeaderLines.cs: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------------------- 2 | FILE INFORMATION: 3 | Name: HeaderLines.cs [./restbot-src/Server/HeaderLines.cs] 4 | Description: Contains a class that allows easy parsing (or creation) 5 | of individual header lines in a HTTP request/response. 6 | 7 | LICENSE: 8 | This file is part of the RESTBot Project. 9 | 10 | Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Affero General Public License as 14 | published by the Free Software Foundation, either version 3 of the 15 | License, or (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Affero General Public License for more details. 21 | 22 | You should have received a copy of the GNU Affero General Public License 23 | along with this program. If not, see . 24 | --------------------------------------------------------------------------------*/ 25 | using System; 26 | using System.Collections.Generic; 27 | using System.Text; 28 | 29 | namespace RESTBot.Server 30 | { 31 | /// Key/Value storage class for headers extracted from a request. 32 | public class HeaderLine 33 | { 34 | private string _key = ""; 35 | 36 | private string _value = ""; 37 | 38 | 39 | #region Get/Set Code 40 | public string Key 41 | { 42 | get 43 | { 44 | return _key; 45 | } 46 | } 47 | 48 | public string Value 49 | { 50 | get 51 | { 52 | return _value; 53 | } 54 | } 55 | #endregion 56 | 57 | /// Converts the internal key/value to a string 58 | /// A valid string, even if it's just a colon followed by a single space character 59 | public override string ToString() 60 | { 61 | // return "${Key}: {Value}"; // duh... if *I* wrote this, I must have been insane! 62 | return $"{_key}: {_value}"; 63 | } 64 | 65 | /// Constructors! 66 | public HeaderLine(string key, string value) 67 | { 68 | _key = key; 69 | _value = value; 70 | } 71 | 72 | /// Constructors, overloaded! 73 | /// This is the one doing all the work of actually parsing the line 74 | /// into its key/value components... (gwyneth 20220425) 75 | public HeaderLine(string entire_line) 76 | { 77 | entire_line = entire_line.Trim(); 78 | string[] split = entire_line.Split(':'); 79 | if (split.Length > 2) 80 | { 81 | string second_part = ""; 82 | for (int i = 1; i < split.Length; ++i) 83 | { 84 | second_part += split[i]; 85 | } 86 | string[] new_split = new string[2]; 87 | new_split[0] = split[0]; 88 | new_split[1] = second_part; 89 | split = new_split; 90 | } 91 | else if (split.Length < 2) 92 | { 93 | DebugUtilities 94 | .WriteWarning($"Could not parse header line! ({entire_line})"); 95 | 96 | //no exception needed, just a warning 97 | return; 98 | } 99 | 100 | //DebugUtilities.WriteDebug($"key=[{split[0]}] value=[{split[1]}]"); 101 | _key = split[0].Trim(); 102 | _value = split[1].Trim(); 103 | //DebugUtilities.WriteDebug($"[{_value}]"); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /restbot-src/Server/HeaderParser.cs: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------------------- 2 | FILE INFORMATION: 3 | Name: HeaderParser.cs [./restbot-src/Server/HeaderParser.cs] 4 | Description: Handles entire header sections of a HTTP request for processing 5 | into individual HeaderLines 6 | 7 | LICENSE: 8 | This file is part of the RESTBot Project. 9 | 10 | Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Affero General Public License as 14 | published by the Free Software Foundation, either version 3 of the 15 | License, or (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Affero General Public License for more details. 21 | 22 | You should have received a copy of the GNU Affero General Public License 23 | along with this program. If not, see . 24 | --------------------------------------------------------------------------------*/ 25 | using System; 26 | using System.Collections; 27 | using System.Collections.Generic; 28 | using System.Net; 29 | using System.Net.Sockets; 30 | using System.Text; 31 | using System.Web; 32 | using RESTBot; 33 | 34 | namespace RESTBot.Server 35 | { 36 | /// Extract the actual request and all the other headers from a HTTP request 37 | /// Who was insane enough to reinvent the wheel?! Microsoft already 38 | /// provides everything and the kitchen sink, and is (probably) future-proof 39 | /// (gwyneth 20220425) 40 | public class RequestHeaders 41 | { 42 | public HeaderRequestLine RequestLine; 43 | 44 | public List HeaderLines; 45 | 46 | /// FQDN host name 47 | public string Hostname = ""; 48 | 49 | /// Constructor 50 | /// All lines from the HTTP stream captured so far 51 | /// FQDN host name, extracted from the socket stream and reverse-DNSified 52 | public RequestHeaders(string headers_section, string host_name) 53 | { 54 | Hostname = host_name; 55 | headers_section.Trim(); 56 | 57 | string[] split_up = 58 | headers_section 59 | .Split(new string[] { "\r\n" }, 60 | StringSplitOptions.RemoveEmptyEntries); 61 | 62 | //first line is the request line 63 | if (split_up.Length < 1) 64 | throw new Exception("Uhm, Theres supposed to be something in the headers"); 65 | 66 | string request_line = split_up[0]; 67 | RequestLine = new HeaderRequestLine(request_line); 68 | 69 | int length = split_up.Length; 70 | HeaderLines = new List(); 71 | for (int i = 1; i < length; ++i) 72 | { 73 | HeaderLines.Add(new HeaderLine(split_up[i])); 74 | } 75 | DebugUtilities 76 | .WriteDebug($"HTTP request has {HeaderLines.Count} headers"); 77 | } 78 | } 79 | 80 | /// Represents one valid header, received from the request. 81 | public class HeaderRequestLine 82 | { 83 | private string _method = ""; //GET/POST/etc 84 | 85 | private string _path = ""; //For parsing REST commands 86 | 87 | private string _http_version = ""; //Something that might be usefull, eg. HTTP/1.1 88 | 89 | /// Returns GET/PUT/POST/DELETE... etc. 90 | public string Method 91 | { 92 | get 93 | { 94 | return _method; 95 | } 96 | } 97 | 98 | /// Path part of the URL 99 | public string Path 100 | { 101 | get 102 | { 103 | return _path; 104 | } 105 | } 106 | 107 | /// HTTP Version of this request 108 | /// Very likely, just HTTP/1.0 or HTTP/1.1 are supported... 109 | public string HttpVersion 110 | { 111 | get 112 | { 113 | return _http_version; 114 | } 115 | } 116 | 117 | /// Constructor (parsed line) 118 | public HeaderRequestLine(string method, string path, string http_version) 119 | { 120 | _method = method; 121 | _path = path; 122 | _http_version = http_version; 123 | } 124 | 125 | /// Constructor (overloaded, for a single raw line) 126 | public HeaderRequestLine(string entire_line) 127 | { 128 | string[] split = entire_line.Trim().Split(' '); 129 | if (split.Length != 3) 130 | { 131 | //this is more serious than a header line, this is the request line batch! 132 | DebugUtilities.WriteError("Could not parse request line"); 133 | throw new Exception("Could not parse request line", 134 | new Exception($"Line has {(split.Length - 1)} spaces instead of 2 [requestline]")); 135 | } 136 | 137 | //ok, we got three entries 138 | _method = split[0].ToUpper().Trim(); 139 | _path = split[1]; 140 | _http_version = split[2].ToUpper().Trim(); 141 | 142 | DebugUtilities 143 | .WriteDebug($"Request Line Parsed: method={_method}; path={_path}; version={_http_version}"); 144 | } 145 | } 146 | } // namespace RESTBot.Server 147 | -------------------------------------------------------------------------------- /restbot-src/Server/Router.cs: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------------------- 2 | FILE INFORMATION: 3 | Name: Router.cs [./restbot-src/Server/Router.cs] 4 | Description: The class in this file handles all http requests and passes them to 5 | an indivual server (defined in Server.cs) 6 | 7 | LICENSE: 8 | This file is part of the RESTBot Project. 9 | 10 | Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Affero General Public License as 14 | published by the Free Software Foundation, either version 3 of the 15 | License, or (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Affero General Public License for more details. 21 | 22 | You should have received a copy of the GNU Affero General Public License 23 | along with this program. If not, see . 24 | --------------------------------------------------------------------------------*/ 25 | using System; 26 | using System.Collections; 27 | using System.Collections.Generic; 28 | using System.Net; 29 | using System.Net.Sockets; 30 | using System.Text; 31 | using System.Threading; 32 | 33 | namespace RESTBot.Server 34 | { 35 | /// 36 | /// HTTP router for incoming REST requests. 37 | /// 38 | /// Processes each request on a separate thread, and includes a basic (but working) 39 | /// mechanism to start/stop the thread. 40 | /// 41 | public partial class Router 42 | { 43 | private IPAddress _bounded_ip; 44 | 45 | private int _port; 46 | 47 | private TcpListener _listener; 48 | 49 | private Thread _router_thread; 50 | 51 | private ManualResetEvent 52 | _processed_connection = new ManualResetEvent(false); 53 | 54 | /// Checks/sets this router thread to running/stopping 55 | /// How this works is a mystery to me, but it seems to work rather well! (gwyneth 20220425) 56 | public bool StillRunning; 57 | 58 | /// Constructor 59 | /// IP address to bind to 60 | /// A valid port number 61 | public Router(IPAddress IP, int Port) 62 | { 63 | _bounded_ip = IP; 64 | _port = Port; 65 | 66 | try 67 | { 68 | DebugUtilities.WriteInfo($"Starting HTTP server on {IP}:{Port}..."); 69 | 70 | _listener = new TcpListener(_bounded_ip, _port); 71 | _listener.Start(); 72 | } 73 | catch (Exception e) 74 | { 75 | throw new Exception($"Could not bind to the specified IP address ({IP}:{Port})", e); 76 | } 77 | 78 | DebugUtilities 79 | .WriteDebug($"Router was able to bind to specified ip/port combination ({IP}:{Port})... starting thread"); 80 | 81 | ManualResetEvent waitingForStart = new ManualResetEvent(false); 82 | try 83 | { 84 | _router_thread = new Thread(new ParameterizedThreadStart(RunListener)); 85 | _router_thread.Start(waitingForStart); 86 | DebugUtilities.WriteDebug("Waiting for thread to initialize"); 87 | if (!waitingForStart.WaitOne(15000, true)) 88 | { 89 | throw new Exception("Timeout exceeded on the router thread start (15s)"); 90 | } 91 | else 92 | { 93 | DebugUtilities 94 | .WriteDebug("Router thread started without a problem, so far"); 95 | } 96 | } 97 | catch (Exception e) 98 | { 99 | throw new Exception("Could not start the server routing thread!", e); 100 | } 101 | DebugUtilities 102 | .WriteDebug("If you see this message, all was good when initializing the router"); 103 | } 104 | 105 | private void RunListener(object? ResetTrigger) 106 | { 107 | if (ResetTrigger == null) 108 | { 109 | DebugUtilities 110 | .WriteWarning("RunListener was passed a null ResetTrigger"); 111 | return; 112 | } 113 | DebugUtilities.WriteDebug("Router thread started successfully"); 114 | 115 | ManualResetEvent trigger = (ManualResetEvent)ResetTrigger; 116 | StillRunning = true; 117 | trigger.Set(); 118 | do 119 | { 120 | _processed_connection.Reset(); 121 | try 122 | { 123 | _listener 124 | .BeginAcceptTcpClient(new AsyncCallback(AcceptClientThread), 125 | _listener); // in server_thread.cs 126 | } 127 | catch (Exception e) 128 | { 129 | DebugUtilities 130 | .WriteError($"Failed to listen to client thread: {e.Message}"); 131 | } 132 | _processed_connection.WaitOne(); 133 | } 134 | while (StillRunning); 135 | _listener.Stop(); 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /restbot-src/Server/Server.cs: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------------------- 2 | FILE INFORMATION: 3 | Name: Server.cs [./restbot-src/Server/Server.cs] 4 | Description: This class handles an individual http request, passes it on to a restbot 5 | (if applicable) and responds with a response in xml form. 6 | 7 | LICENSE: 8 | This file is part of the RESTBot Project. 9 | 10 | Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Affero General Public License as 14 | published by the Free Software Foundation, either version 3 of the 15 | License, or (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Affero General Public License for more details. 21 | 22 | You should have received a copy of the GNU Affero General Public License 23 | along with this program. If not, see . 24 | --------------------------------------------------------------------------------*/ 25 | using System; 26 | using System.Collections.Generic; 27 | using System.Net; 28 | using System.Net.Sockets; 29 | using System.Text; 30 | 31 | namespace RESTBot.Server 32 | { 33 | /// Lower-level connections to special scenarios 34 | public partial class Router 35 | { 36 | /// deals with methods of the router class 37 | private void AcceptClientThread(IAsyncResult result) 38 | { 39 | TcpClient client = _listener.EndAcceptTcpClient(result); 40 | _processed_connection.Set(); 41 | 42 | EndPoint? endpoint = client.Client.RemoteEndPoint; // we put it right here to make things easier later on (gwyneth 20220107) 43 | 44 | string ip = String.Empty; 45 | 46 | // more stupid checks to deal with the many, many ways this can become null... (gwyneth 20220214) 47 | if (endpoint != null) 48 | { 49 | string? endpointToString = endpoint.ToString(); 50 | if (endpointToString != null) 51 | { 52 | ip = endpointToString.Split(':')[0]; 53 | DebugUtilities 54 | .WriteInfo($"Processing Connection from {IPAddress.Parse(((IPEndPoint) endpoint).Address.ToString())} (ip: {ip})!"); // new syntax, since this is now nullable (gwyneth 20220207) 55 | } 56 | else 57 | { 58 | DebugUtilities.WriteError("No IP address received (?) or couldn't parse IP address for connection"); 59 | } 60 | } 61 | 62 | NetworkStream stream = client.GetStream(); 63 | 64 | DebugUtilities.WriteSpecial("Reading Stream"); 65 | string request = ""; 66 | byte[] buffer = new byte[512]; 67 | int i = 0; 68 | do 69 | { 70 | i = stream.Read(buffer, 0, buffer.Length); //add the next set of data into the buffer.. 71 | DebugUtilities.WriteSpecial("Read chunk from the stream"); 72 | request += Encoding.UTF8.GetString(buffer, 0, i); //append it to the overall request 73 | } 74 | while (stream.DataAvailable); //and repeat :) 75 | 76 | DebugUtilities 77 | .WriteInfo($"Got request, totalling {request.Length} characters"); 78 | string[] split = 79 | request 80 | .Split(new string[] { "\r\n\r\n" }, 81 | StringSplitOptions.RemoveEmptyEntries); 82 | 83 | string hostname = "unknown"; // if we can't resolve IP address to a hostname... 84 | try 85 | { 86 | DebugUtilities.WriteDebug("ip: " + ip ?? "nothing"); // may be an empty string (gwyneth 20220214) 87 | if (ip != null) 88 | { 89 | IPHostEntry host = Dns.GetHostEntry(IPAddress.Parse(ip)); 90 | hostname = host.HostName; 91 | } 92 | DebugUtilities.WriteDebug($"ENDPOINT HOSTNAME: {hostname}"); 93 | } 94 | catch 95 | { 96 | DebugUtilities 97 | .WriteWarning("Could not parse ip address to get the hostname (ipv6?) - hostname is set as 'unknown'"); 98 | } 99 | 100 | /// get request headers into the appropriate class 101 | RequestHeaders _request_headers = new RequestHeaders(split[0], hostname); 102 | 103 | string body = ""; 104 | 105 | /// 106 | /// For some reason, the RESTbot HTTP server takes pleasure in waiting for 100-continue, 107 | /// so we set a flag here. 108 | /// 109 | bool foundExpectContinue = false; 110 | foreach (HeaderLine line in _request_headers.HeaderLines) 111 | { 112 | if (line.ToString() == "Expect: 100-continue") 113 | { 114 | foundExpectContinue = true; 115 | DebugUtilities.WriteSpecial("Found 100 continue!"); 116 | } 117 | } 118 | 119 | if (foundExpectContinue) 120 | { 121 | try 122 | { 123 | ResponseHeaders continue_response = 124 | new ResponseHeaders(100, "Continue"); 125 | byte[] byte_continue_response = 126 | System.Text.Encoding.UTF8.GetBytes(continue_response.ToString()); 127 | 128 | //send the 100 continue message and then go back to the above. 129 | DebugUtilities.WriteSpecial("Writing 100 continue response"); 130 | stream.Write(byte_continue_response, 0, byte_continue_response.Length); 131 | DebugUtilities.WriteSpecial($"Finished writing - {byte_continue_response.Length} bytes total sent"); 132 | 133 | request = ""; 134 | buffer = new byte[512]; 135 | /// stream chunk counter 136 | i = 0; 137 | if (stream.DataAvailable) 138 | { 139 | DebugUtilities.WriteSpecial("DATA AVALIABLE!!"); 140 | } 141 | else 142 | { 143 | DebugUtilities.WriteWarning("NO DATA AVALIABLE? Hurr"); 144 | } 145 | do 146 | { 147 | i = stream.Read(buffer, 0, buffer.Length); //add the next set of data into the buffer.. 148 | DebugUtilities.WriteSpecial("Read continued chunk from the stream"); 149 | request += Encoding.UTF8.GetString(buffer, 0, i); //append it to the overall request 150 | } 151 | while (stream.DataAvailable); //and repeat :) 152 | 153 | DebugUtilities.WriteInfo($"Got continued request, totalling {request.Length} characters"); 154 | DebugUtilities.WriteDebug($"Here's what I got: {request}"); 155 | body = request; 156 | } 157 | catch (Exception e) 158 | { 159 | DebugUtilities.WriteError("An error occured while trying to talk to the client (100 expectation response): " + e.Message); 160 | } 161 | } 162 | else 163 | { 164 | if (split.Length > 1) 165 | { 166 | body = split[1]; 167 | } 168 | } 169 | /// Status message to return to the client that made the request 170 | /// Likely XML-formatted (there are very few exceptions) 171 | string to_return = Program.DoProcessing(_request_headers, body); 172 | // The next line is DELIBERATELY not using interpolated strings, because there might have 173 | // been some issues with those. (gwyneth 20220426) 174 | to_return = "" + to_return + ""; 175 | // commented out until I figure out how to write a DebugUtilities.WriteTrace() method. (gwyneth 20220426) 176 | // DebugUtilities.WriteDebug($"What I should return to the client: {to_return}"); 177 | 178 | ResponseHeaders response_headers = new ResponseHeaders(200, "OK"); 179 | string response = response_headers.ToString() + to_return; 180 | 181 | try 182 | { 183 | /// stream of bytes to send over the HTTP stream as response 184 | /// TODO(gwyneth): This comes as XML, but we might wish to convert it first to JSON or 185 | /// something else. Note: this would require changing the headers, too 186 | byte[] the_buffer = System.Text.Encoding.UTF8.GetBytes(response); 187 | response = ""; //unset for the hell of it 188 | stream.Write(the_buffer, 0, the_buffer.Length); 189 | } 190 | catch (Exception e) 191 | { 192 | DebugUtilities.WriteError("Could not write to the network stream, error was: " + e.Message); 193 | //see below 194 | } 195 | 196 | try 197 | { 198 | stream.Close(); 199 | client.Close(); 200 | } 201 | catch 202 | { 203 | DebugUtilities.WriteWarning("An error occured while closing the stream"); 204 | // ignore, sometimes the connection was closed by the client 205 | // if it's to be ignored, I've downgraded it to a warning. (gwyneth 20220426) 206 | } 207 | } 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /restbot-tools/launch-scripts/systemd/README - for systemd.md: -------------------------------------------------------------------------------- 1 | # Automating the launch in systemd 2 | 3 | This should get RESTbot up and running under Debian/Ubuntu Linux and its derivatives (e.g. RaspberryOS). 4 | 5 | For other systems, please adjust the paths below accordingly. 6 | 7 | ## Requirements 8 | 9 | - `screen` (which can be installed with `apt-get install screen`) 10 | 11 | ## Instructions 12 | 13 | - copy `restbot.service.sample` to `restbot.service` 14 | - fill in the missing data, namely: 15 | * User (the account that this script will run under; avoid `root` at all costs!) 16 | * Group 17 | * adjust the paths for the installation, paying attention that the working directory should be the actual 18 | directory where the binary resides 19 | - let systemd be aware of the existence of the file, running (as root) `/usr/bin/systemctl link /path/to/your/restbot/directory/restbot-tools/launch-scripts/systemd/restbot.service` 20 | - enable the service: `/usr/bin/systemctl enable /path/to/your/restbot/directory/restbot-tools/launch-scripts/systemd/restbot.service` 21 | - from now on, you can safely start and stop the service using `systemctl start restbot` and `systemctl stop restbot` 22 | 23 | If, by any chance, you need to change this script, don't forget to run `systemctl daemon-reload` after saving, so that systemd is made aware of the changes. -------------------------------------------------------------------------------- /restbot-tools/launch-scripts/systemd/restbot.service.sample: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=RESTbot 3 | After=syslog.target 4 | After=network.target 5 | 6 | [Service] 7 | Type=forking 8 | User= 9 | Group= 10 | Environment="DOTNET=/usr/lib/dotnet" 11 | WorkingDirectory=/full/path/to/bin/directory 12 | ExecStart=/usr/bin/screen -dmS "RESTbot" /full/path/to/bin/RESTbot 13 | ExecStop=/usr/bin/screen -p 0 -S "RESTbot" -X kill 14 | KillSignal=SIGCONT 15 | Restart=always 16 | RestartSec=30s 17 | RemainAfterExit=false 18 | SuccessExitStatus=1 19 | 20 | [Install] 21 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /restbot-tools/php-restbot-api/avatars.php: -------------------------------------------------------------------------------- 1 | . 20 | --------------------------------------------------------------------------------*/ 21 | require_once "include/funktions.php"; 22 | require_once "include/config.php"; 23 | 24 | require_once "include/avatars.php"; 25 | require_once "include/util.php"; 26 | 27 | global $ownername; 28 | global $authuser; 29 | if ( 30 | $_SERVER["HTTP_X_SECONDLIFE_OWNER_NAME"] == $ownername || 31 | $_REQUEST["psk"] == $authuser 32 | ) { 33 | $authorized = true; 34 | } 35 | 36 | $command = $_REQUEST["command"]; 37 | 38 | if ($command == "profilepic") { 39 | if (!$authorized) { 40 | genPipeError("auth"); 41 | } 42 | if (!isset($_REQUEST["key"])) { 43 | genPipeError("param"); 44 | } 45 | $key = avatarProfilePic($_REQUEST["key"]); 46 | if ($key == null) { 47 | genPipeError("lookup"); 48 | } else { 49 | genPipeResponse(friendlyUUID($key)); 50 | } 51 | } elseif ($command == "grouplist") { 52 | if (!$authorized) { 53 | genPipeError("auth"); 54 | } 55 | if (!isset($_REQUEST["key"])) { 56 | genPipeError("param"); 57 | } 58 | $list = avatarGroupList($_REQUEST["key"]); 59 | genPipeResponse($list); 60 | } else { 61 | genPipeError("param"); 62 | } 63 | -------------------------------------------------------------------------------- /restbot-tools/php-restbot-api/groups.php: -------------------------------------------------------------------------------- 1 | . 20 | --------------------------------------------------------------------------------*/ 21 | require_once "include/funktions.php"; 22 | require_once "include/config.php"; 23 | 24 | require_once "include/groups.php"; 25 | require_once "include/util.php"; 26 | 27 | global $ownername; 28 | global $authuser; 29 | if ( 30 | $_SERVER["HTTP_X_SECONDLIFE_OWNER_NAME"] == $ownername || 31 | $_REQUEST["psk"] == $authuser 32 | ) { 33 | $authorized = true; 34 | } 35 | $command = $_REQUEST["command"]; 36 | 37 | if ($command == "groupinfo") { 38 | if (!$authorized) { 39 | genPipeError("auth"); 40 | } 41 | if (!isset($_REQUEST["group_key"])) { 42 | genPipeError("param"); 43 | } 44 | $result = groupInfo($_REQUEST["group_key"]); 45 | if ($result == null) { 46 | genPipeError("unknown"); 47 | } else { 48 | genPipeResponse($result); 49 | } 50 | /*} else if ( $command == "getgroups" ) { 51 | if ( !$authorized ) { 52 | genPipeError('auth'); 53 | } 54 | if ( ! isset($_REQUEST['av_key']) ) { 55 | genPipeError('param'); 56 | } 57 | $result = groupList($_REQUEST['av_key']); 58 | if ( $result == null ) { 59 | genPipeError('unknown'); 60 | } else { 61 | genPipeResponse($result); 62 | }*/ 63 | } else { 64 | genPipeError("param"); 65 | } 66 | -------------------------------------------------------------------------------- /restbot-tools/php-restbot-api/include/avatars.php: -------------------------------------------------------------------------------- 1 | . 20 | --------------------------------------------------------------------------------*/ 21 | require_once "db.php"; 22 | require_once "funktions.php"; 23 | require_once "util.php"; 24 | 25 | function avatarName($key) 26 | { 27 | // global $debug; 28 | $cached = getFromCache("key2name", $key); 29 | if (!empty($cached["value"])) { 30 | logMessage( 31 | "rest", 32 | 3, 33 | "Returning cache entry (" . (time() - $cached["timestamp"]) . ")" 34 | ); 35 | return $cached["value"]; 36 | } else { 37 | $avatarname = getAvatarName($key); 38 | if (empty($avatarname)) { 39 | logMessage("rest", 3, "Response not received."); 40 | // $cached = getForceFromCache("regionhandle", $sim); // typo? 41 | $cached = getForceFromCache("regionhandle", $key); 42 | if (!empty($cached)) { 43 | logMessage( 44 | "db", 45 | 1, 46 | "Returning old cache entry (" . (time() - $cached["timestamp"]) . ")" 47 | ); 48 | return $cached["value"]; 49 | } else { 50 | logMessage("rest", 1, "Failed to lookup avatar name for " . $key); 51 | return null; 52 | } 53 | } elseif ($avatarname == "0") { 54 | logMessage("rest", 3, "Avatar name not found"); 55 | return 0; 56 | } else { 57 | if (existsInCache("key2name", $key)) { 58 | updateInCache("key2name", $key, $avatarname); 59 | } else { 60 | putInCache("key2name", $key, $avatarname); 61 | } 62 | return $avatarname; 63 | } 64 | } 65 | } 66 | 67 | function avatarKey($name) 68 | { 69 | // global $debug; // if it's not used, why declare it? (gwyneth 20220422) 70 | $cached = getFromCache("name2key", $name); 71 | if (!empty($cached["value"])) { 72 | return $cached["value"]; 73 | } else { 74 | $avatarkey = getAvatarKey($name); 75 | if (!empty($avatarkey)) { 76 | if (existsInCache("name2key", $name)) { 77 | updateInCache("name2key", $name, $avatarkey); 78 | } else { 79 | putInCache("name2key", $name, $avatarkey); 80 | } 81 | return $avatarkey; 82 | } else { 83 | $cached = getForceFromCache("name2key", $name); 84 | if (empty($cached["value"])) { 85 | logMessage("rest", 3, "Response not received."); 86 | return null; 87 | } elseif ($cached["value"] == 0) { 88 | logMessage("db", 1, "Failed to lookup avatar name for " . $name); 89 | return null; 90 | } else { 91 | logMessage( 92 | "db", 93 | 1, 94 | "Returning old cache entry (" . (time() - $cached["timestamp"]) . ")" 95 | ); 96 | return $cached["value"]; 97 | } 98 | } 99 | } 100 | } 101 | function avatarProfilePic($key) 102 | { 103 | $imagekey = getAvatarProfilePic($key); 104 | return $imagekey; 105 | } 106 | 107 | function avatarGroupList($key) 108 | { 109 | return getAvatarGroupList($key); 110 | } 111 | 112 | function getAvatarName($avkey) 113 | { 114 | $result = rest("avatar_name", "key=$avkey"); 115 | if ($result == null) { 116 | logMessage("sl", 0, "Error looking up Avatar Name for $avkey", null, null); 117 | return null; 118 | } 119 | $xml = new SimpleXMLElement($result); 120 | return $xml->name; 121 | } 122 | 123 | function getAvatarKey($avatarname) 124 | { 125 | $result = rest("avatar_key", "name=$avatarname"); 126 | if ($result == null) { 127 | logMessage( 128 | "sl", 129 | 0, 130 | "Error looking up Avatar Key for $avatarname", 131 | null, 132 | null 133 | ); 134 | return null; 135 | } 136 | $xml = new SimpleXMLElement($result); 137 | if ($xml->key != "00000000000000000000000000000000") { 138 | return $xml->key; 139 | } else { 140 | logMessage("sl", 1, "$avatarname does not exist", null, null); 141 | return "0"; 142 | } 143 | } 144 | 145 | function getAvatarProfilePic($key) 146 | { 147 | $result = rest("avatar_profile", "key=$key"); 148 | if ($result == null) { 149 | logMessage("sl", 0, "Error looking up profile for $key", null, null); 150 | return null; 151 | } 152 | $xml = new SimpleXMLElement($result); 153 | return $xml->profile->profileimage; 154 | } 155 | 156 | function getAvatarGroupList($key) 157 | { 158 | $result = rest("avatar_groups", "key=$key"); 159 | if ($result == null) { 160 | logMessage("sl", 0, "Error looking up profile for $key", null, null); 161 | return null; 162 | } 163 | $xml = new SimpleXMLElement($result); 164 | $return = ""; 165 | foreach ($xml->groups->group as $group) { 166 | $return = $return . $group->name . "," . friendlyUUID($group->key) . ","; 167 | } 168 | return $return; 169 | } 170 | function getAvatarGroupListDetailed($key) 171 | { 172 | $result = rest("avatar_groups", "key=$key"); 173 | if ($result == null) { 174 | logMessage("sl", 0, "Error looking up profile for $key", null, null); 175 | return null; 176 | } 177 | $xml = new SimpleXMLElement($result); 178 | $return = ""; 179 | foreach ($xml->groups->group as $group) { 180 | $return = 181 | $return . 182 | $group->key . 183 | "," . 184 | $group->name . 185 | "," . 186 | $group->title . 187 | "," . 188 | $group->notices . 189 | "," . 190 | $group->powers . 191 | "," . 192 | friendlyUUID($group->insignia) . 193 | ","; 194 | } 195 | return $return; 196 | } 197 | ?> 198 | -------------------------------------------------------------------------------- /restbot-tools/php-restbot-api/include/config.php: -------------------------------------------------------------------------------- 1 | . 20 | --------------------------------------------------------------------------------*/ 21 | # Don't forget to change all the below data! 22 | 23 | $debugdb = false; 24 | $debug = false; 25 | $dburi = "mysql://root:yqeiduyi@localhost:3305/restbot"; 26 | 27 | $ownername = "otakup0pe Neumann"; 28 | $authuser = "lolwhut"; 29 | 30 | $cache_expore = 300; 31 | 32 | $use_syslog = false; 33 | 34 | $restbots = [ 35 | ["first" => "", "last" => "", "pass" => "", "host" => "", "key" => ""], 36 | ]; 37 | 38 | ?> 39 | -------------------------------------------------------------------------------- /restbot-tools/php-restbot-api/include/db.php: -------------------------------------------------------------------------------- 1 | . 20 | --------------------------------------------------------------------------------*/ 21 | 22 | // Note: You can get DB.php using `pear install DB` 23 | // However, this PEAR package is deprecated in favour of MDB2; caveat utilitor 24 | require_once "/usr/local/share/pear/DB.php"; 25 | 26 | function getConn() 27 | { 28 | global $dburi; 29 | $conn = &DB::connect($dburi); 30 | if (DB::isError($conn)) { 31 | logMessage("db", 0, $conn->getMessage(), null, null); 32 | genPipeError("db"); 33 | } else { 34 | return $conn; 35 | } 36 | } 37 | 38 | function getSingle($sql) 39 | { 40 | global $debugdb; 41 | if ($debugdb) { 42 | logMessage("db", 3, "SQL - " . $sql); 43 | } 44 | $return = 0; 45 | $conn = getConn(); 46 | $result = $conn->query($sql); 47 | if (DB::isError($result)) { 48 | logMessage("db", 0, "Query Error " . $result->getMessage(), null, null); 49 | genPipeError("db"); 50 | } 51 | if ($result->numRows() > 1) { 52 | return "MULTIPLE"; 53 | } 54 | $row = $result->fetchRow(); 55 | if (count($row) == 1) { 56 | $return = $row[0]; 57 | } 58 | return $return; 59 | } 60 | 61 | function doQuery($sql) 62 | { 63 | global $debugdb; 64 | if ($debugdb) { 65 | logMessage("db", 3, "SQL - " . $sql); 66 | } 67 | $conn = getConn(); 68 | $result = $conn->query($sql); 69 | if (DB::isError($result)) { 70 | logMessage("db", 0, "Query Error " . $result->getMessage(), null, null); 71 | genPipeError("db"); 72 | } 73 | return $result; 74 | } 75 | 76 | function doUpdate($sql) 77 | { 78 | global $debugdb; 79 | if ($debugdb) { 80 | logMessage("db", 3, "SQL - " . $sql); 81 | } 82 | $conn = getConn(); 83 | $result = $conn->query($sql); 84 | if (DB::isError($result)) { 85 | logMessage("db", 0, "Query Error " . $result->getMessage(), null, null); 86 | genPipeError("db"); 87 | } 88 | return $conn->affectedrows(); 89 | } 90 | -------------------------------------------------------------------------------- /restbot-tools/php-restbot-api/include/funktions.php: -------------------------------------------------------------------------------- 1 | . 20 | --------------------------------------------------------------------------------*/ 21 | require_once "sql.php"; 22 | #require_once 'config.php'; 23 | 24 | global $debug; 25 | 26 | function genPipeError($error) 27 | { 28 | if ($error == "param") { 29 | print "PARAMETER_ERROR" . PHP_EOL; 30 | } elseif ($error == "auth") { 31 | print "AUTHENTICATION" . PHP_EOL; 32 | logMessage( 33 | "auth", 34 | 1, 35 | "Authentication issue from " . 36 | $_SERVER["REMOTE_ADDR"] ?: "(unknown remote address)" . 37 | " on " . 38 | $_SERVER["REQUEST_URI"] ?: "(unknown URI request)" 39 | ); 40 | } elseif ($error == "db") { 41 | print "DB" . PHP_EOL; 42 | } elseif ($error == "found") { 43 | print "NOTFOUND" . PHP_EOL; 44 | } elseif ($error == "lookup") { 45 | print "LOOKUPERROR" . PHP_EOL; 46 | } else { 47 | print "UNKNOWN ERROR" . PHP_EOL; 48 | } 49 | die(); 50 | } 51 | function genPipeResponse($resp) 52 | { 53 | print "OK" . $resp . PHP_EOL; 54 | die(); 55 | } 56 | 57 | #0 Error 1 Warning 2 Info 3 Debug 58 | function logMessage($type, $level, $message) 59 | { 60 | global $debug; 61 | global $use_syslog; 62 | if ($use_syslog) { 63 | // define_syslog_variables(); // deprecated and not needed any longer (gwyneth 20220422) 64 | if ($debug) { 65 | } 66 | if ($level == 0) { 67 | $s_level = LOG_ERR; 68 | } elseif ($level == 1) { 69 | $s_level = LOG_WARNING; 70 | } elseif ($level == 2) { 71 | $s_level = LOG_INFO; 72 | } elseif ($level == 3) { 73 | $s_level = LOG_DEBUG; 74 | } else { 75 | $s_level = LOG_ERR; 76 | } 77 | $s_message = $type . " " . $message; 78 | openlog("restbot", LOG_PID, LOG_DAEMON); 79 | syslog($s_level, $s_message); 80 | closelog(); 81 | } 82 | } 83 | 84 | function doRest($method, $arguments, $hostname, $session) 85 | { 86 | global $debug; 87 | $url = "http://" . $hostname . "/" . $method . "/" . $session . "/"; 88 | if ($debug) { 89 | logMessage("rest", 3, "Contacting URL - " . $url); 90 | } 91 | $ch = curl_init($url); 92 | curl_setopt($ch, CURLOPT_POST, true); 93 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 94 | curl_setopt($ch, CURLOPT_POSTFIELDS, $arguments); 95 | curl_setopt($ch, CURLOPT_TIMEOUT, 60); 96 | $response = curl_exec($ch); 97 | curl_close($ch); 98 | return $response; 99 | } 100 | 101 | function rest($method, $arguments) 102 | { 103 | global $restbots; 104 | $tries = count($restbots) + 3; 105 | $lastid = 0; 106 | while ($tries > 0) { 107 | if ($tries == count($restbots) + 3 - count($restbots)) { 108 | logMessage("rest", 3, "Checked every bot"); 109 | } 110 | $restbot = restbotFromDB(); 111 | if ($restbot == null && $restbot["id"] != $lastid) { 112 | $restbot = newRestBot(); 113 | if ($restbot["hostname"] == null || $restbot["session"] == null) { 114 | logMessage("rest", 0, "Error creating new restbot"); 115 | $tries--; 116 | continue; 117 | } 118 | } else { 119 | if ($lastid == $restbot["id"]) { 120 | logMessage("rest", 3, "already tried this bot..."); 121 | $restbot = newRestBot(); 122 | } 123 | } 124 | $lastid = $restbot["id"]; 125 | if (!lockBot($restbot["session"])) { 126 | logMessage("rest", 1, "Unable to lock bot"); 127 | $tries--; 128 | continue; 129 | } 130 | $response = doRest( 131 | $method, 132 | $arguments, 133 | $restbot["hostname"], 134 | $restbot["session"] 135 | ); 136 | if (empty($response)) { 137 | logMessage("http", 0, "Empty response from restbot"); 138 | restbotRemoveByID($restbot["id"]); 139 | $tries--; 140 | continue; 141 | } else { 142 | logMessage("rest", 3, "Response received" . $response); 143 | } 144 | $xml = new SimpleXMLElement($response); 145 | if ($xml->error == "invalidsession") { 146 | logMessage("rest", 1, "Removing invalid session"); 147 | restbotRemoveByID($restbot["id"]); 148 | $tries--; 149 | continue; 150 | } elseif ( 151 | $xml->error == "Offline" || 152 | $xml->error == "Reconnecting" || 153 | $xml->error == "LoggingIn" 154 | ) { 155 | logMessage("rest", 3, "Awaiting connection to SL"); 156 | releaseBot($restbot["session"]); 157 | sleep(5); 158 | $tries--; 159 | continue; 160 | } elseif (isset($xml->error)) { 161 | logMessage("rest", 0, "Unhandled restbot error - " . $xml->error); 162 | releaseBot($restbot["session"]); 163 | $tries--; 164 | continue; 165 | } 166 | releaseBot($restbot["session"]); 167 | return $response; 168 | } 169 | logMessage("rest", 3, "Unable to do REST magic"); 170 | } 171 | 172 | function restbotConnect($first, $last, $pass, $host, $hostpass) 173 | { 174 | global $debug; 175 | $url = "http://" . $host . "/establish_session/" . $hostpass . "/"; 176 | if ($debug) { 177 | logMessage("newrest", 3, "Attempting to establish new bot at " . $url); 178 | } 179 | $ch = curl_init($url); 180 | $arguments = "first=" . $first . "&last=" . $last . "&pass=" . md5($pass); 181 | curl_setopt($ch, CURLOPT_POST, true); 182 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 183 | curl_setopt($ch, CURLOPT_POSTFIELDS, $arguments); 184 | curl_setopt($ch, CURLOPT_TIMEOUT, 10); 185 | $response = curl_exec($ch); 186 | curl_close($ch); 187 | if (empty($response)) { 188 | if ($debug) { 189 | logMessage("newrest", 3, "Empty response from supposed server"); 190 | } 191 | return null; 192 | } 193 | $xml = new SimpleXMLElement($response); 194 | if (isset($xml->error)) { 195 | return ["error" => $xml->error]; 196 | } else { 197 | return [ 198 | "existing" => $xml->existing_session, 199 | "session" => $xml->session_id, 200 | ]; 201 | } 202 | } 203 | 204 | function newRestBot() 205 | { 206 | global $restbots; 207 | 208 | $thisbot = $restbots[rand(0, count($restbots) - 1)]; 209 | $bot = restbotConnect( 210 | $thisbot["first"], 211 | $thisbot["last"], 212 | $thisbot["pass"], 213 | $thisbot["host"], 214 | $thisbot["key"] 215 | ); 216 | if (!isset($bot["error"])) { 217 | $restbot = ["hostname" => $thisbot["host"], "session" => $bot["session"]]; 218 | if ($bot["existing"] == "true") { 219 | if (restbotIsLocked($restbot["session"])) { 220 | logMessage("newrest", 2, "Not using locked bot"); 221 | return null; 222 | } 223 | } 224 | if ( 225 | // $xml->existing_session != "true" || // this is weird, where does it come from? (gwyneth 20220422) 226 | !sessionAlreadyExists($restbot["session"]) 227 | ) { 228 | restbotRemoveBySession($restbot["session"]); 229 | $restbot["id"] = restbotAddToDB( 230 | $restbot["session"], 231 | $restbot["hostname"] 232 | ); 233 | } 234 | return $restbot; 235 | } 236 | } 237 | 238 | function friendlyUUID($key) 239 | { 240 | return substr($key, 0, 8) . 241 | "-" . 242 | substr($key, 8, 4) . 243 | "-" . 244 | substr($key, 12, 4) . 245 | "-" . 246 | substr($key, 16, 4) . 247 | "-" . 248 | substr($key, 20, 12); 249 | } 250 | ?> 251 | -------------------------------------------------------------------------------- /restbot-tools/php-restbot-api/include/groups.php: -------------------------------------------------------------------------------- 1 | . 20 | --------------------------------------------------------------------------------*/ 21 | require_once "db.php"; 22 | require_once "funktions.php"; 23 | /* 24 | function groupList($key) { 25 | global $debug; 26 | $result = rest("get_groups", ""); 27 | if ( $result == null ) { 28 | logMessage('sl', 0, "Error retrieving group list for", null, null); 29 | return null; 30 | } 31 | $xml = new SimpleXMLElement($result); 32 | $return = ""; 33 | foreach ($xml->groups->group as $group) { 34 | $return += $group->key . "," . $group->name . ","; 35 | } 36 | return $return; 37 | }*/ 38 | 39 | function groupInfo($key) 40 | { 41 | // global $debug; // not used, so not included. 42 | $result = rest("get_group_profile", "group=$key"); 43 | if ($result == null) { 44 | logMessage("sl", 0, "Error retrieving group profile for $key", null, null); 45 | return null; 46 | } 47 | $xml = new SimpleXMLElement($result); 48 | return $xml->groupprofile->name . 49 | "," . 50 | $xml->groupprofile->insignia . 51 | "," . 52 | $xml->groupprofile->maturepublish . 53 | "," . 54 | $xml->groupprofile->charter; 55 | } 56 | 57 | ?> 58 | -------------------------------------------------------------------------------- /restbot-tools/php-restbot-api/include/sl.php: -------------------------------------------------------------------------------- 1 | . 20 | --------------------------------------------------------------------------------*/ 21 | require_once "db.php"; 22 | require_once "funktions.php"; 23 | 24 | function getGridStatus() 25 | { 26 | $url = "http://www.secondlife.com/status"; 27 | if (!@$web = file($url)) { 28 | logMessage("sl", 0, "Error looking up grid status", null, null); 29 | return "Unknown"; 30 | } 31 | if (!$web) { 32 | logMessage("sl", 0, "Error looking up grid status", null, null); 33 | return "Unknown"; 34 | } 35 | $data = implode("", $web); 36 | $findme = "Open"; 37 | preg_match_all("/

([^`]*?)<\/h3>/", $data, $matches); 38 | $result = $matches[0][0]; 39 | //Force a fake "SL Grid is closed result for testing 40 | //$result = "Second life is offline"; 41 | $pos = strpos($result, $findme); 42 | if ($pos == false) { 43 | return "Closed"; 44 | } else { 45 | return "Open"; 46 | } 47 | } 48 | function gridStatus() 49 | { 50 | global $gridStatus; 51 | $result = doQuery( 52 | "SELECT UNIX_TIMESTAMP(state.time) AS timestamp, value, id FROM state WHERE state.key = 'gridStatus'" 53 | ); 54 | if ($result->numRows() == 1) { 55 | $state = $result->fetchRow(DB_FETCHMODE_ASSOC); 56 | if (time() - $state["timestamp"] > 300) { 57 | $gridStatus = getGridStatus(); 58 | # print "Update " . $gridStatus; 59 | if ($gridStatus != $state["value"] && $gridStatus != null) { 60 | doQuery( 61 | "UPDATE state SET time=null, value = '" . 62 | $gridStatus . 63 | "' WHERE id = " . 64 | $state["id"] 65 | ); 66 | } 67 | } else { 68 | # print "Cached " . $state['value']; 69 | $gridStatus = $state["value"]; 70 | } 71 | } else { 72 | $gridStatus = getGridStatus(); 73 | if ($gridStatus != null) { 74 | # print "New " . $gridStatus; 75 | doQuery("DELETE FROM state WHERE state.key = 'gridStatus'"); 76 | doQuery( 77 | "INSERT INTO state VALUES(null, null, null, 'gridStatus', '$gridStatus')" 78 | ); 79 | } 80 | } 81 | return $gridStatus; 82 | } 83 | ?> 84 | -------------------------------------------------------------------------------- /restbot-tools/php-restbot-api/include/sql.php: -------------------------------------------------------------------------------- 1 | . 20 | --------------------------------------------------------------------------------*/ 21 | require_once "db.php"; 22 | 23 | function restbotFromDB() 24 | { 25 | $request = doQuery( 26 | "SELECT restbots.id, restbots.hostname, restbots.session FROM restbots WHERE restbots.lock = 0 ORDER BY RAND() DESC LIMIT 1" 27 | ); 28 | if ($request->numRows() != 1) { 29 | return null; 30 | } else { 31 | $session = $request->fetchRow(DB_FETCHMODE_ASSOC); 32 | return [ 33 | "session" => $session["session"], 34 | "hostname" => $session["hostname"], 35 | "id" => $session["id"], 36 | ]; 37 | } 38 | } 39 | function restbotRemoveByID($botid) 40 | { 41 | doQuery("DELETE FROM restbots WHERE restbots.id = $botid"); 42 | } 43 | function restbotRemoveBySession($session) 44 | { 45 | doQuery("DELETE FROM restbots WHERE restbots.session = '$session'"); 46 | } 47 | function restbotAddToDB($session, $hostname) 48 | { 49 | doQuery("INSERT INTO restbots VALUES(null, '$session','$hostname', 0, null)"); 50 | return getSingle( 51 | "SELECT restbots.id FROM restbots WHERE restbots.session = '$session'" 52 | ); 53 | } 54 | function sessionAlreadyExists($session) 55 | { 56 | $bots = doQuery( 57 | "SELECT restbots.id FROM restbots WHERE restbots.session = '$session'" 58 | ); 59 | if ($bots->numRows() == 1) { 60 | return true; 61 | } else { 62 | return false; 63 | } 64 | } 65 | function lockBot($session) 66 | { 67 | global $debug; 68 | if ( 69 | getSingle( 70 | "SELECT restbots.lock FROM restbots WHERE restbots.session = '$session'" 71 | ) == 1 72 | ) { 73 | return false; 74 | } 75 | if ($debug) { 76 | logMessage("rest", 3, "Locking session $session"); 77 | } 78 | if ( 79 | doUpdate( 80 | "UPDATE restbots SET restbots.lock = 1, restbots.timestamp = null WHERE restbots.session = '$session'" 81 | ) == 1 82 | ) { 83 | return true; 84 | } else { 85 | return false; 86 | } 87 | } 88 | function releaseBot($session) 89 | { 90 | global $debug; 91 | if ($debug) { 92 | logMessage("rest", 3, "Unlocking session $session"); 93 | } 94 | doQuery( 95 | "UPDATE restbots SET restbots.lock = 0 WHERE restbots.session = '$session'" 96 | ); 97 | } 98 | function restbotIsLocked($session) 99 | { 100 | $locked = getSingle( 101 | "SELECT restbots.lock FROM restbots WHERE restbots.session = '$session'" 102 | ); 103 | if ($locked == 1) { 104 | return true; 105 | } else { 106 | return false; 107 | } 108 | } 109 | 110 | ////// 111 | function getFromCache($type, $key) 112 | { 113 | global $cache_expire; 114 | $cache = getForceFromCache($type, $key); 115 | if (time() - $cache["timestamp"] > $cache_expire || $cache == null) { 116 | return null; 117 | } 118 | return ["value" => $cache["value"]]; 119 | } 120 | function getForceFromCache($type, $key) 121 | { 122 | $result = doQuery( 123 | "SELECT UNIX_TIMESTAMP(cache.time) AS timestamp, value, id FROM cache WHERE cache.key = '$key' AND cache.type = '$type'" 124 | ); 125 | if ($result->numRows() == 0) { 126 | return null; 127 | } 128 | $cache = $result->fetchRow(DB_FETCHMODE_ASSOC); 129 | return ["value" => $cache["value"], "timestamp" => $cache["timestamp"]]; 130 | } 131 | function removeFromCache($type, $key) 132 | { 133 | global $debug; 134 | 135 | if ($debug) { 136 | logMessage("db", 3, "Removing $key from $type cache"); 137 | } 138 | doQuery( 139 | "DELETE FROM cache WHERE cache.type = '$type' AND cache.key = '$key'" 140 | ); 141 | } 142 | function updateInCache($type, $key, $value) 143 | { 144 | global $debug; 145 | 146 | if ($debug) { 147 | logMessage("db", 3, "Updating $key in $type cache with $value"); 148 | } 149 | doQuery( 150 | "UPDATE cache SET cache.value = '$value', cache.time = null WHERE cache.type = '$type' AND cache.key = '$key'" 151 | ); 152 | } 153 | function putInCache($type, $key, $value) 154 | { 155 | global $debug; 156 | 157 | if ($debug) { 158 | logMessagE("db", 3, "Inserting $key into $type cache with $value"); 159 | } 160 | doQuery("INSERT INTO cache VALUES(null, null, '$type', '$key', '$value')"); 161 | } 162 | function existsInCache($type, $key) 163 | { 164 | $q = getSingle( 165 | "SELECT cache.id FROM cache WHERE cache.type = '$type' AND cache.key = '$key'" 166 | ); 167 | if ($q == null) { 168 | return false; 169 | } else { 170 | return true; 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /restbot-tools/php-restbot-api/include/util.php: -------------------------------------------------------------------------------- 1 | . 20 | --------------------------------------------------------------------------------*/ 21 | require_once "db.php"; 22 | require_once "funktions.php"; 23 | 24 | function regionHandle($sim) 25 | { 26 | // global $debug; // if not used, don't declare it! (gwyneth 20220422) 27 | // $cached = getFromCache("regionhandle", $key); // this was on the original code; typo? (gwyneth 20220422) 28 | $cached = getFromCache("regionhandle", $sim); 29 | if ($cached["value"] != null) { 30 | return $cached["value"]; 31 | } else { 32 | $handle = getRegionHandle($sim); 33 | if ($handle == null) { 34 | logMessage("rest", 3, "Response not received."); 35 | $cached = getForceFromCache("regionhandle", $sim); 36 | if ($cached != null) { 37 | logMessage( 38 | "db", 39 | 1, 40 | "Returning old cache entry (" . (time() - $cached["timestamp"]) . ")" 41 | ); 42 | return $cached["value"]; 43 | } else { 44 | return null; 45 | } 46 | } elseif ($handle == 0) { 47 | return "0"; 48 | } else { 49 | if (existsInCache("regionhandle", $sim)) { 50 | updateInCache("regionhandle", $sim, $handle); 51 | } else { 52 | putInCache("regionhandle", $sim, $handle); 53 | } 54 | return $handle; 55 | } 56 | } 57 | } 58 | 59 | function getRegionHandle($sim) 60 | { 61 | $result = rest("region_handle", "region=$sim"); 62 | if ($result == null) { 63 | logMessage("sl", 0, "Error looking up region handle for $sim", null, null); 64 | return null; 65 | } 66 | $xml = new SimpleXMLElement($result); 67 | return $xml->handle; 68 | } 69 | function regionMap($sim) 70 | { 71 | // global $debug; // if not used, don't include it (gwyneth 20220422) 72 | // $cached = getFromCache("regionmap", $key); // probably a typo? (gwyneth 20220422) 73 | $cached = getFromCache("regionmap", $sim); 74 | if ($cached["value"] != null) { 75 | return $cached["value"]; 76 | } else { 77 | $handle = getRegionMap($sim); 78 | if ($handle == null) { 79 | logMessage("rest", 3, "Response not received."); 80 | $cached = getForceFromCache("regionmap", $sim); 81 | if ($cached != null) { 82 | logMessage( 83 | "db", 84 | 1, 85 | "Returning old cache entry (" . (time() - $cached["timestamp"]) . ")" 86 | ); 87 | return $cached["value"]; 88 | } else { 89 | return null; 90 | } 91 | } else { 92 | if (existsInCache("regionmap", $sim)) { 93 | updateInCache("regionmap", $sim, $handle); 94 | } else { 95 | putInCache("regionmap", $sim, $handle); 96 | } 97 | return $handle; 98 | } 99 | } 100 | } 101 | 102 | function getRegionMap($sim) 103 | { 104 | $result = rest("region_image", "region=" . urlencode($sim)); 105 | if ($result == null) { 106 | logMessage("sl", 0, "Error looking up region handle for $sim", null, null); 107 | return null; 108 | } 109 | $xml = new SimpleXMLElement($result); 110 | return $xml->image; 111 | } 112 | 113 | ?> 114 | -------------------------------------------------------------------------------- /restbot-tools/php-restbot-api/util.php: -------------------------------------------------------------------------------- 1 | . 20 | --------------------------------------------------------------------------------*/ 21 | require_once "include/funktions.php"; 22 | require_once "include/config.php"; 23 | 24 | require_once "include/avatars.php"; 25 | require_once "include/util.php"; 26 | 27 | global $ownername; 28 | global $authuser; 29 | if ( 30 | $_SERVER["HTTP_X_SECONDLIFE_OWNER_NAME"] == $ownername || 31 | $_REQUEST["psk"] == $authuser 32 | ) { 33 | $authorized = true; 34 | } 35 | 36 | $command = $_REQUEST["command"]; 37 | 38 | if ($command == "getkey") { 39 | if (!$authorized) { 40 | genPipeError("auth"); 41 | } 42 | if (isset($_REQUEST["name"])) { 43 | if ($_REQUEST["base64"] == 1) { 44 | $name = base64_decode($_REQUEST["name"]); 45 | } else { 46 | $name = urldecode($_REQUEST["name"]); 47 | } 48 | } else { 49 | genPipeError("param"); 50 | } 51 | $resp = avatarKey($name); 52 | if ($resp == null) { 53 | genPipeError("lookup"); 54 | } elseif ($resp == "0") { 55 | genPipeError("found"); 56 | } else { 57 | genPipeResponse($resp); 58 | } 59 | } elseif ($command == "getname") { 60 | if (!$authorized) { 61 | genPipeError("auth"); 62 | } 63 | if (isset($_REQUEST["key"])) { 64 | if ($_REQUEST["base64"] == 1) { 65 | $key = base64_decode($_REQUEST["key"]); 66 | } else { 67 | $key = urldecode($_REQUEST["key"]); 68 | } 69 | } else { 70 | genPipeError("param"); 71 | } 72 | $resp = avatarName($key); 73 | if ($resp == null) { 74 | genPipeError("lookup"); 75 | } elseif ($resp == "0") { 76 | genPipeError("found"); 77 | } else { 78 | genPipeResponse($resp); 79 | } 80 | } elseif ($command == "gethandle") { 81 | if (!$authorized) { 82 | genPipeError("auth"); 83 | } 84 | if (isset($_REQUEST["sim"])) { 85 | if ($_REQUEST["base64"] == 1) { 86 | $sim = base64_decode($_REQUEST["sim"]); 87 | } else { 88 | $sim = urldecode($_REQUEST["sim"]); 89 | } 90 | } else { 91 | genPipeError("param"); 92 | } 93 | $resp = regionHandle($sim); 94 | if ($resp == null) { 95 | genPipeError("lookup"); 96 | } elseif ($resp == "0") { 97 | genPipeError("found"); 98 | } else { 99 | genPipeResponse($resp); 100 | } 101 | } elseif ($command == "getmap") { 102 | if (!$authorized) { 103 | genPipeError("auth"); 104 | } 105 | if (isset($_REQUEST["sim"])) { 106 | if ($_REQUEST["base64"] == 1) { 107 | $sim = base64_decode($_REQUEST["sim"]); 108 | } else { 109 | $sim = urldecode($_REQUEST["sim"]); 110 | } 111 | } else { 112 | genPipeError("param"); 113 | } 114 | $resp = regionMap($sim); 115 | if ($resp == null) { 116 | genPipeError("lookup"); 117 | } elseif ($resp == "00000000000000000000000000000000") { 118 | genPipeResponse("3ab7e2fa-9572-ef36-1a30-d855dbea4f92"); 119 | } else { 120 | genPipeResponse(friendlyUUID($resp)); 121 | } 122 | } else { 123 | genPipeError("param"); 124 | } 125 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/api/getname.lsl: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------------------------- 2 | // LICENSE: 3 | // This file is part of the RESTBot Project. 4 | // 5 | // Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 6 | // 7 | // This program is free software: you can redistribute it and/or modify 8 | // it under the terms of the GNU Affero General Public License as 9 | // published by the Free Software Foundation, either version 3 of the 10 | // License, or (at your option) any later version. 11 | // 12 | // This program is distributed in the hope that it will be useful, 13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | // GNU Affero General Public License for more details. 16 | // 17 | // You should have received a copy of the GNU Affero General Public License 18 | // along with this program. If not, see . 19 | //-------------------------------------------------------------------------------- 20 | 21 | string API = "http://localhost:9080/restbot/util.php?psk=lolwhut"; 22 | 23 | key nameLookupID = NULL_KEY; 24 | 25 | default 26 | { 27 | touch_start(integer total_number) 28 | { 29 | if ( nameLookupID == NULL_KEY ) { 30 | nameLookupID = llHTTPRequest(API + "&command=getname&key=" + (string) llDetectedKey(0), [], ""); 31 | } else { 32 | llSay(0, "In use"); 33 | } 34 | } 35 | 36 | http_response(key request_id, integer status, list metadata, string body) { 37 | //llWhisper(0, (string) status + " " + body); 38 | if ( request_id == nameLookupID ) { 39 | if ( llGetSubString(body, 0, 1) == "OK" ) { 40 | llSay(0, "Hello thar " + llGetSubString(body, 2, -1)); 41 | } 42 | nameLookupID = NULL_KEY; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/dilation-meter.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # LICENSE: 3 | # This file is part of the RESTBot Project. 4 | # 5 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU Affero General Public License as 9 | # published by the Free Software Foundation, either version 3 of the 10 | # License, or (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU Affero General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Affero General Public License 18 | # along with this program. If not, see . 19 | 20 | # To use this script, make sure you have the following dependencies installed: 21 | # - perl 22 | # - dialog (Ubuntu/Debian: 'apt install dialog'; macOS: 'brew install dialog') 23 | 24 | if [ $# -ne 3 ] ; then 25 | echo "dilation-meter.sh firstname lastname password" ; 26 | exit 1 ; 27 | fi 28 | SESSION=`perl botlogin.pl "$1" "$2" "$3"` 29 | while [ 1 ] ; do 30 | DILATION=`perl bot-dilation.pl "$SESSION"` ; 31 | LEN=`echo "$DILATION" | wc -c` ; 32 | if [ $LEN -eq 1 ] ; then 33 | DILATION=100 ; 34 | fi ; 35 | done | dialog --gauge "Time Dilation" 7 80 36 | 37 | perl botquit.pl $SESSION 38 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-dilation.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | 22 | use XML::XPath; 23 | use HTTP::Request::Common qw(POST); 24 | use LWP::UserAgent; 25 | 26 | $ua = new LWP::UserAgent; 27 | if ( ( $#ARGV + 1 ) < 2 ) { 28 | print "bad args - url session\n"; 29 | exit; 30 | } 31 | my $req = POST $ARGV[0] . "/dilation/" . $ARGV[1] . "/"; 32 | 33 | $res = $ua->request($req); 34 | if ( $res->code == 200 ) { 35 | my $xp = XML::XPath->new(xml => $res->content); 36 | print $xp->getNodeText('/restbot/dilation') . "\n"; 37 | } 38 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-getgroupprofile.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 1 ) { 27 | print "bad args - url session groupkey\n"; 28 | exit; 29 | } 30 | my $req = POST $ARGV[0] . "/get_group_profile/" . $ARGV[1] . "/", 31 | [ "group" => $ARGV[2] ]; 32 | 33 | $res = $ua->request($req); 34 | if ( $res->code == 200 ) { 35 | print $res->content . "\n"; 36 | } 37 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-getgrouproles.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # LICENSE: 3 | # This file is part of the RESTBot Project. 4 | # 5 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU Affero General Public License as 9 | # published by the Free Software Foundation, either version 3 of the 10 | # License, or (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU Affero General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Affero General Public License 18 | # along with this program. If not, see . 19 | 20 | use XML::XPath; 21 | use HTTP::Request::Common qw(POST); 22 | use LWP::UserAgent; 23 | 24 | $ua = new LWP::UserAgent; 25 | if ( ( $#ARGV + 1 ) < 2 ) { 26 | print "bad args - url session groupkey\n"; 27 | exit; 28 | } 29 | my $req = POST $ARGV[0] . "/get_roles/" . $ARGV[1] . "/", 30 | [ 'group' => $ARGV[2] ]; 31 | 32 | $res = $ua->request($req); 33 | if ( $res->code == 200 ) { 34 | print $res->content . "\n"; 35 | } 36 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-getgroups.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 1 ) { 27 | print "bad args - url session\n"; 28 | exit; 29 | } 30 | my $req = POST $ARGV[0] . "/get_groups/" . $ARGV[1] . "/"; 31 | 32 | $res = $ua->request($req); 33 | if ( $res->code == 200 ) { 34 | print $res->content . "\n"; 35 | } 36 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-getgroups2.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 1 ) { 27 | print "bad args - url session avkey\n"; 28 | exit; 29 | } 30 | my $req = POST $ARGV[0] . "/avatar_groups/" . $ARGV[1] . "/", 31 | [ "key" => $ARGV[2] ]; 32 | 33 | $res = $ua->request($req); 34 | if ( $res->code == 200 ) { 35 | print $res->content . "\n"; 36 | } 37 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-getkey.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 3 ) { 27 | print "bad args - url session firstname lastname\n"; 28 | exit; 29 | } 30 | my $req = POST $ARGV[0] . "/avatar_key/" . $ARGV[1] . "/", 31 | [ "name" => $ARGV[2] . " " . $ARGV[3] ]; 32 | $res = $ua->request($req); 33 | if ( $res->code == 200 ) { 34 | my $xp = XML::XPath->new(xml => $res->content); 35 | print $xp->getNodeText('/restbot/key') . "\n"; 36 | } 37 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-getname.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 3 ) { 27 | print "bad args - url session agent_key\n"; 28 | exit; 29 | } 30 | my $req = POST $ARGV[0] . "/avatar_name/" . $ARGV[1] . "/", 31 | [ "key" => $ARGV[2] ]; 32 | $res = $ua->request($req); 33 | if ( $res->code == 200 ) { 34 | my $xp = XML::XPath->new(xml => $res->content); 35 | print $xp->getNodeText('/restbot/name') . "\n"; 36 | } 37 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-getonline.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 3 ) { 27 | print "bad args - session url agent_key\n"; 28 | exit; 29 | } 30 | my $req = POST $ARGV[0] . "/avatar_online/" . $ARGV[1] . "/", 31 | [ "key" => $ARGV[2] ]; 32 | $res = $ua->request($req); 33 | if ( $res->code == 200 ) { 34 | my $xp = XML::XPath->new(xml => $res->content); 35 | print $xp->getNodeText('/restbot/online') . "\n"; 36 | } 37 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-getprofile.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 3 ) { 27 | print "bad args - url session agent_key\n"; 28 | exit; 29 | } 30 | my $req = POST $ARGV[0] . "/avatar_profile/" . $ARGV[1] . "/", 31 | [ "key" => $ARGV[2] ]; 32 | $res = $ua->request($req); 33 | if ( $res->code == 200 ) { 34 | # my $xp = XML::XPath->new(xml => $res->content); 35 | # print $xp->getNodeText('/restbot/name') . "\n"; 36 | print $res->content; 37 | } 38 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-givelandmark.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 3 ) { 27 | print "bad args - url session name destkey\n"; 28 | exit; 29 | } 30 | my $req = POST $ARGV[0] . "/create_landmark/" . $ARGV[1] . "/", 31 | [ "name" => $ARGV[2], "desc" => "restbot 4tw", "avatar" => $ARGV[3] ]; 32 | $res = $ua->request($req); 33 | if ( $res->code == 200 ) { 34 | my $xp = XML::XPath->new(xml => $res->content); 35 | print $xp->getNodeText('/restbot/status') . "\n"; 36 | } 37 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-groupinvitations.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use strict; 22 | 23 | use XML::XPath; 24 | use HTTP::Request::Common qw(POST); 25 | use LWP::UserAgent; 26 | 27 | my $url = $ARGV[0]; 28 | my $session = $ARGV[1]; 29 | 30 | my $ua = new LWP::UserAgent; 31 | if ( ( $#ARGV + 1 ) < 1 ) { 32 | print "bad args - url session\n"; 33 | exit; 34 | } 35 | my $req = POST $url . "invitations/" . $session . "/", 36 | [ "action" => "list_invitations" ]; 37 | 38 | my $res = $ua->request($req); 39 | if ( $res->code == 200 ) { 40 | my $xp = XML::XPath->new(xml => $res->content); 41 | if ( $xp->exists('/restbot') ) { 42 | print "Valid restjunk\n"; 43 | } else { 44 | print "Invalid restjunk\n"; 45 | die; 46 | } 47 | my $invitations = $xp->find('/restbot/invitations/invite'); 48 | print "Invites - " . $invitations->size() . "\n"; 49 | foreach my $invite ( $invitations->get_nodelist) { 50 | # print XML::XPath::XMLParser::as_string($invite) . "\n"; 51 | print "Invited to " . getGroupName($invite->find('group')) . " by " . $invite->find('inviter') ."\n"; 52 | my $answer = ''; 53 | while ( $answer ne 'y' && $answer ne 'n' ) { 54 | print "Do you wish to accept ? (y/n) "; 55 | chomp($answer = ); 56 | } 57 | if ( $answer eq 'y' ) { 58 | my $req2 = POST $url . "/invitations/" . $session . "/", 59 | [ "action" => "accept_invitation", "inviteid" => $invite->find('key') ]; 60 | my $res2 = $ua->request($req2); 61 | } elsif ( $answer eq 'n' ) { 62 | my $req2 = POST $url . "/invitations/" . $session . "/", 63 | [ "action" => "decline_invitation", "inviteid" => $invite->find('key') ]; 64 | my $res2 = $ua->request($req2); 65 | } 66 | } 67 | } 68 | 69 | sub getGroupName 70 | { 71 | my $groupkey = $_[0]; 72 | my $req = POST $url . "/get_group_profile/" . $session . "/", 73 | [ "group" => "$groupkey" ]; 74 | my $res = $ua->request($req); 75 | if ( $res->code == 200 ) { 76 | my $xp = XML::XPath->new(xml => $res->content); 77 | return $xp->getNodeText('/restbot/groupprofile/name'); 78 | } 79 | return undef; 80 | } 81 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-groupinvite.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 4 ) { 27 | print "bad args - url session group avatar\n"; 28 | exit; 29 | } 30 | my $req = POST $ARGV[0] . "/invite/" . $ARGV[1] . "/", 31 | [ "group" => $ARGV[2] , "target" => $ARGV[3] ]; 32 | $res = $ua->request($req); 33 | if ( $res->code == 200 ) { 34 | my $xp = XML::XPath->new(xml => $res->content); 35 | print $xp->getNodeText('/restbot/success') . "\n"; 36 | } 37 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-joingroup.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 3 ) { 27 | print "bad args - url session group\n"; 28 | exit; 29 | } 30 | my $req = POST $ARGV[0] . "/join_group/" . $ARGV[1] . "/", 31 | [ "groupid" => $ARGV[2] ]; 32 | $res = $ua->request($req); 33 | if ( $res->code == 200 ) { 34 | my $xp = XML::XPath->new(xml => $res->content); 35 | print $xp->getNodeText('/restbot/success') . "\n"; 36 | } 37 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-leavegroup.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 3 ) { 27 | print "bad args - url session groupkey\n"; 28 | exit; 29 | } 30 | my $req = POST $ARGV[0] . "/leave_group/" . $ARGV[1] . "/", 31 | [ "groupid" => $ARGV[2] ]; 32 | $res = $ua->request($req); 33 | if ( $res->code == 200 ) { 34 | my $xp = XML::XPath->new(xml => $res->content); 35 | print $xp->getNodeText('/restbot/success') . "\n"; 36 | } 37 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-location.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 1 ) { 27 | print "bad args - url session\n"; 28 | exit; 29 | } 30 | my $req = POST $ARGV[0] . "/location/" . $ARGV[1] . "/"; 31 | 32 | $res = $ua->request($req); 33 | if ( $res->code == 200 ) { 34 | my $xp = XML::XPath->new(xml => $res->content); 35 | print $xp->getNodeText('/restbot/sim') . "@" . $xp->getNodeText('/restbot/pos') . "\n"; 36 | } 37 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-parcel.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 2 ) { 27 | print "bad args - url session\n"; 28 | exit; 29 | } 30 | my $req = POST $ARGV[0] . "/parcel_properties/" . $ARGV[1] . "/"; 31 | 32 | $res = $ua->request($req); 33 | if ( $res->code == 200 ) { 34 | print $res->content . "\n"; 35 | # my $xp = XML::XPath->new(xml => $res->content); 36 | # print $xp->getNodeText('/restbot') . "\n"; 37 | } 38 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-parceleditname.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 3 ) { 27 | print "bad args - url session new_name\n"; 28 | exit; 29 | } 30 | my $req = POST $ARGV[0] . "/parcel_modify/" . $ARGV[1] . "/", 31 | [ "name" => $ARGV[2] ]; 32 | $res = $ua->request($req); 33 | if ( $res->code == 200 ) { 34 | # my $xp = XML::XPath->new(xml => $res->content); 35 | # print $xp->getNodeText('/restbot/name') . "\n"; 36 | print $res->content; 37 | } 38 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-regionhandle.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 2 ) { 27 | print "bad args - url region\n"; 28 | exit; 29 | } 30 | my $req = POST $ARGV[0] . "/region_handle/" . $ARGV[1] . "/", 31 | [ 'region' => $ARGV[2] ]; 32 | 33 | $res = $ua->request($req); 34 | if ( $res->code == 200 ) { 35 | my $xp = XML::XPath->new(xml => $res->content); 36 | print $xp->getNodeText('/restbot/handle') . "\n"; 37 | } 38 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-rez.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 4 ) { 27 | print "bad args - url session name x,y,z [path]\n"; 28 | exit; 29 | } 30 | my $req; 31 | if ( $ARGV[4] != "" ) { 32 | $req = POST $ARGV[0] . "/rez_from_inventory/" . $ARGV[1] . "/", 33 | [ "name" => $ARGV[2] , "pos" => $ARGV[3] , "path" => $ARGV[4] ]; 34 | } else { 35 | $req = POST $ARGV[0] . "/rez_from_inventory/" . $ARGV[1] . "/", 36 | [ "name" => $ARGV[2] , "pos" => $ARGV[3] ]; 37 | } 38 | $res = $ua->request($req); 39 | if ( $res->code == 200 ) { 40 | my $xp = XML::XPath->new(xml => $res->content); 41 | print $xp->getNodeText('/restbot/status') . "\n"; 42 | } 43 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-sit.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 3 ) { 27 | print "bad args - url session target camping\n"; 28 | exit; 29 | } 30 | my $req; 31 | $req = POST $ARGV[0] . "/sit/" . $ARGV[1] . "/", 32 | [ "seat" => $ARGV[2] , "camp" => $ARGV[3], "action" => "sit_on_target" ]; 33 | 34 | $res = $ua->request($req); 35 | if ( $res->code == 200 ) { 36 | my $xp = XML::XPath->new(xml => $res->content); 37 | print $xp->getNodeText('/restbot/success') . "\n"; 38 | } 39 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-sitground.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 2 ) { 27 | print "bad args - url session camping\n"; 28 | exit; 29 | } 30 | my $req; 31 | $req = POST $ARGV[0] . "/sit/" . $ARGV[1] . "/", 32 | [ "action" => "sit_on_ground", "camp" => $ARGV[2] ]; 33 | 34 | $res = $ua->request($req); 35 | if ( $res->code == 200 ) { 36 | my $xp = XML::XPath->new(xml => $res->content); 37 | print $xp->getNodeText('/restbot/success') . "\n"; 38 | } 39 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-stand.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 1 ) { 27 | print "bad args - url session\n"; 28 | exit; 29 | } 30 | my $req; 31 | $req = POST $ARGV[0] . "/sit/" . $ARGV[1] . "/", 32 | [ "action" => "stand_up" ]; 33 | 34 | $res = $ua->request($req); 35 | if ( $res->code == 200 ) { 36 | my $xp = XML::XPath->new(xml => $res->content); 37 | print $xp->getNodeText('/restbot/success') . "\n"; 38 | } 39 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-startanim.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 3 ) { 27 | print "bad args - url session anim-UUID\n"; 28 | exit; 29 | } 30 | my $req; 31 | $req = POST $ARGV[0] . "/startanim/" . $ARGV[1] . "/", 32 | [ "animation" => $ARGV[2] ]; 33 | 34 | $res = $ua->request($req); 35 | if ( $res->code == 200 ) { 36 | my $xp = XML::XPath->new(xml => $res->content); 37 | print $xp->getNodeText('/restbot/success') . "\n"; 38 | } 39 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-stats.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 2 ) { 27 | print "bad args - url session\n"; 28 | exit; 29 | } 30 | my $req = POST $ARGV[0] . "/sim_stat/" . $ARGV[1] . "/"; 31 | 32 | $res = $ua->request($req); 33 | if ( $res->code == 200 ) { 34 | print $res->content . "\n"; 35 | # my $xp = XML::XPath->new(xml => $res->content); 36 | # print $xp->getNodeText('/restbot') . "\n"; 37 | } 38 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-status.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 1 ) { 27 | print "bad args - url session\n"; 28 | exit; 29 | } 30 | my $req = POST $ARGV[0] . "/status/" . $ARGV[1] . "/"; 31 | 32 | $res = $ua->request($req); 33 | if ( $res->code == 200 ) { 34 | my $xp = XML::XPath->new(xml => $res->content); 35 | print $xp->getNodeText('/restbot/status') . "\n"; 36 | } 37 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-stopanim.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 3 ) { 27 | print "bad args - url session anim-UUID\n"; 28 | exit; 29 | } 30 | my $req; 31 | $req = POST $ARGV[0] . "/stopanim/" . $ARGV[1] . "/", 32 | [ "animation" => $ARGV[2] ]; 33 | 34 | $res = $ua->request($req); 35 | if ( $res->code == 200 ) { 36 | my $xp = XML::XPath->new(xml => $res->content); 37 | print $xp->getNodeText('/restbot/success') . "\n"; 38 | } 39 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/bot-teleport.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | 25 | $ua = new LWP::UserAgent; 26 | if ( ( $#ARGV + 1 ) < 4 ) { 27 | print "bad args - url session sim x,y,z\n"; 28 | exit; 29 | } 30 | my $req = POST $ARGV[0] . "/teleport/" . $ARGV[1] . "/", 31 | [ "sim" => $ARGV[2] , "pos" => $ARGV[3] ]; 32 | $res = $ua->request($req); 33 | if ( $res->code == 200 ) { 34 | my $xp = XML::XPath->new(xml => $res->content); 35 | print $xp->getNodeText('/restbot/status') . "\n"; 36 | } 37 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/botlogin.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use Data::Dumper; 23 | use HTTP::Request::Common qw(POST); 24 | use LWP::UserAgent; 25 | use Digest::MD5 qw(md5_hex); 26 | 27 | $ua = new LWP::UserAgent; 28 | if ( ( $#ARGV + 1 ) < 4 ) { 29 | print "bad args - url firstname lastname password\n"; 30 | exit; 31 | } 32 | my $req = POST $ARGV[0] . '/establish_session/pass/', 33 | [ 'first' => $ARGV[1], 'last' => $ARGV[2], 'pass' => md5_hex($ARGV[3]) ]; 34 | 35 | $res = $ua->request($req); 36 | if ( $res->code == 200 ) { 37 | my $xp = XML::XPath->new(xml => $res->content); 38 | print $xp->getNodeText('/restbot/success/session_id') . "\n"; 39 | # print $res->content . "\n"; 40 | } 41 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/botquit.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use HTTP::Request::Common qw(POST); 23 | use LWP::UserAgent; 24 | use Digest::MD5 qw(md5_hex); 25 | 26 | $ua = new LWP::UserAgent; 27 | if ( ( $#ARGV + 1 ) < 2 ) { 28 | print "bad args - url session\n"; 29 | exit; 30 | } 31 | my $req = POST $ARGV[0] . '/exit/' . $ARGV[1] . "/"; 32 | 33 | $res = $ua->request($req); 34 | if ( $res->code == 200 ) { 35 | my $xp = XML::XPath->new(xml => $res->content); 36 | print $xp->getNodeText('/restbot/disposed') . "\n"; 37 | } 38 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/perl/botshutdown.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #-------------------------------------------------------------------------------- 3 | # LICENSE: 4 | # This file is part of the RESTBot Project. 5 | # 6 | # Copyright (C) 2007-2008 PLEIADES CONSULTING, INC 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as 10 | # published by the Free Software Foundation, either version 3 of the 11 | # License, or (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | #------------------------------------------------------------------------------- 21 | use XML::XPath; 22 | use Data::Dumper; 23 | use HTTP::Request::Common qw(POST); 24 | use LWP::UserAgent; 25 | use Digest::MD5 qw(md5_hex); 26 | 27 | $ua = new LWP::UserAgent; 28 | if ( ( $#ARGV + 1 ) < 1) { 29 | print "bad args - url \n"; 30 | exit; 31 | } 32 | my $req = POST $ARGV[0] . '/server_quit/pass/'; 33 | 34 | $res = $ua->request($req); 35 | if ( $res->code == 200 ) { 36 | my $xp = XML::XPath->new(xml => $res->content); 37 | # print $xp->getNodeText('/restbot/status') . "\n"; 38 | print $res->content . "\n"; 39 | } 40 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/php/bot-dilation.php: -------------------------------------------------------------------------------- 1 | . 20 | --------------------------------------------------------------------------------*/ 21 | 22 | // Don't forget to change th $url to reflect your configuration! 23 | 24 | if ($argv[1] == null) { 25 | print "Usage bot-dilation.php session" . PHP_EOL; 26 | exit(0); 27 | } 28 | $url = "http://lumo.eghetto.ca:9080/dilation/" . $argv[1] . "/"; 29 | $ch = curl_init($url); 30 | 31 | curl_setopt($ch, CURLOPT_POST, true); 32 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 33 | $stuff = curl_exec($ch); 34 | curl_close($ch); 35 | if (empty($stuff)) { 36 | print "Nothing returned from server" . PHP_EOL; 37 | exit(1); 38 | } 39 | #print "$stuff"; 40 | $xml = new SimpleXMLElement($stuff); 41 | print $xml->dilation . PHP_EOL; 42 | -------------------------------------------------------------------------------- /restbot-tools/test-scripts/php/bot-getkey.php: -------------------------------------------------------------------------------- 1 | . 20 | --------------------------------------------------------------------------------*/ 21 | 22 | // Don't forget to change th $url to reflect your configuration! 23 | 24 | if ($argv[1] == null || $argv[2] == null || $argv[3] == null) { 25 | print "Usage " . $argv[0] . " session firstname lastname" . PHP_EOL; 26 | exit(1); 27 | } 28 | $url = "http://127.0.0.1:9080/avatar_key/" . $argv[1] . "/"; 29 | $ch = curl_init($url); 30 | 31 | curl_setopt($ch, CURLOPT_POST, true); 32 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 33 | curl_setopt($ch, CURLOPT_POSTFIELDS, "name=" . $argv[2] . " " . $argv[3]); 34 | $stuff = curl_exec($ch); 35 | curl_close($ch); 36 | if (empty($stuff)) { 37 | print "Nothing returned from server" . PHP_EOL; 38 | exit(2); 39 | } 40 | $xml = new SimpleXMLElement($stuff); 41 | print $xml->key . PHP_EOL; 42 | --------------------------------------------------------------------------------