diff --git a/.github/workflows/build_viewer.yml b/.github/workflows/build_viewer.yml index 245dcb4071..4e08d2db9e 100644 --- a/.github/workflows/build_viewer.yml +++ b/.github/workflows/build_viewer.yml @@ -313,7 +313,8 @@ jobs: FS_PF_UA: ${{ secrets.FS_PF_UA }} run: | if [ -n "${FS_PF_UA}" ]; then - echo "EXTRA_ARGS=${{ env.EXTRA_ARGS }} -DFS_PS_USER_AGENT=\"${FS_PF_UA}\"" >> $GITHUB_ENV + echo "EXTRA_ARGS=${{ env.EXTRA_ARGS }} -DFS_PF_USER_AGENT=\"${FS_PF_UA}\"" >> $GITHUB_ENV + echo "Building with custom user-agent string." else echo "No custom user-agent string provided." fi @@ -378,13 +379,13 @@ jobs: - name: Install Microsoft.Trusted.Signing.Client if: runner.os == 'Windows' run: | - .\nuget.exe install Microsoft.Trusted.Signing.Client -Version 1.0.53 -OutputDirectory . + .\nuget.exe install Microsoft.Trusted.Signing.Client -Version 1.0.86 -OutputDirectory . shell: pwsh - name: Locate Azure.CodeSigning.Dlib.dll if: runner.os == 'Windows' run: | - $dllPath = (Get-ChildItem ".\Microsoft.Trusted.Signing.Client.1.0.53\bin\x64\Azure.CodeSigning.Dlib.dll" -Recurse -File | Select-Object -First 1).FullName + $dllPath = (Get-ChildItem ".\Microsoft.Trusted.Signing.Client.1.0.86\bin\x64\Azure.CodeSigning.Dlib.dll" -Recurse -File | Select-Object -First 1).FullName if (-not $dllPath) { Write-Error "Azure.CodeSigning.Dlib.dll not found." exit 1 diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 310a358b96..abc0df8095 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -75,10 +75,12 @@ endif(TESTBUILD AND TESTBUILDPERIOD) # Support for custom Primfeed UA option(FS_PF_USER_AGENT "Optional compile‐time Primfeed user‐agent string" "") -if(FS_PF_USER_AGENT) - # For a single target, say your executable is called "firestorm_viewer": +if (FS_PF_USER_AGENT) add_compile_definitions(FS_PF_USER_AGENT="${FS_PF_USER_AGENT}") -endif() + message(STATUS "Compiling with custom Primfeed user-agent: ${FS_PF_USER_AGENT}") +else (FS_PF_USER_AGENT) + message(STATUS "Compiling with standard Primfeed user-agent") +endif (FS_PF_USER_AGENT) # # [AVX Optimization] option(USE_AVX_OPTIMIZATION "AVX optimization support" OFF) diff --git a/indra/newview/fsfloaterprimfeed.cpp b/indra/newview/fsfloaterprimfeed.cpp index c665d09198..b740cecc06 100644 --- a/indra/newview/fsfloaterprimfeed.cpp +++ b/indra/newview/fsfloaterprimfeed.cpp @@ -74,9 +74,14 @@ FSPrimfeedPhotoPanel::FSPrimfeedPhotoPanel() : mDescriptionTextBox(nullptr), mLocationCheckbox(nullptr), mRatingComboBox(nullptr), + mStoresComboBox(nullptr), mPostButton(nullptr), mBtnPreview(nullptr), - mBigPreviewFloater(nullptr) + mBigPreviewFloater(nullptr), + mCancelButton(nullptr), + mCommercialCheckbox(nullptr), + mFilterComboBox(nullptr), + mPublicGalleryCheckbox(nullptr) { mCommitCallbackRegistrar.add("SocialSharing.SendPhoto", [this](LLUICtrl*, const LLSD&) { onSend(); }); mCommitCallbackRegistrar.add("SocialSharing.RefreshPhoto", [this](LLUICtrl*, const LLSD&) { onClickNewSnapshot(); }); @@ -88,6 +93,16 @@ FSPrimfeedPhotoPanel::FSPrimfeedPhotoPanel() : LL_DEBUGS("primfeed") << "Info button clicked, opening " << url << LL_ENDL; LLWeb::loadURLExternal(url); }); + FSPrimfeedAuth::sPrimfeedAuthPump->listen("FSPrimfeedPhotoPanel", + [this](const LLSD& data) + { + if (data["responseType"].asString() == "primfeed_user_info") + { + this->loadPrimfeedInfo(data); + return true; + } + return false; + }); } FSPrimfeedPhotoPanel::~FSPrimfeedPhotoPanel() @@ -97,8 +112,6 @@ FSPrimfeedPhotoPanel::~FSPrimfeedPhotoPanel() mPreviewHandle.get()->die(); } - FSPrimfeedAuth::sPrimfeedAuthPump->stopListening("FSPrimfeedAccountPanel"); - gSavedSettings.setS32("FSLastSnapshotToPrimfeedResolution", getChild("resolution_combobox")->getCurrentIndex()); gSavedSettings.setS32("FSLastSnapshotToPrimfeedWidth", getChild("custom_snapshot_width")->getValue().asInteger()); gSavedSettings.setS32("FSLastSnapshotToPrimfeedHeight", getChild("custom_snapshot_height")->getValue().asInteger()); @@ -121,6 +134,7 @@ bool FSPrimfeedPhotoPanel::postBuild() mCommercialCheckbox = getChild("primfeed_commercial_content"); mPublicGalleryCheckbox = getChild("primfeed_add_to_public_gallery"); mRatingComboBox = getChild("rating_combobox"); + mStoresComboBox = getChild("stores_combobox"); mPostButton = getChild("post_photo_btn"); mCancelButton = getChild("cancel_photo_btn"); mBigPreviewFloater = dynamic_cast(LLFloaterReg::getInstance("big_preview")); @@ -192,6 +206,8 @@ void FSPrimfeedPhotoPanel::draw() mCancelButton->setEnabled(can_post); mDescriptionTextBox->setEnabled(can_post); mRatingComboBox->setEnabled(can_post); + // If the stores combo box is present, enable it only if we have stores to select from + mStoresComboBox->setEnabled(can_post && mStoresComboBox->getItemCount() > 1); mResolutionComboBox->setEnabled(can_post); mFilterComboBox->setEnabled(can_post); mRefreshBtn->setEnabled(can_post); @@ -327,7 +343,7 @@ bool FSPrimfeedPhotoPanel::onPrimfeedConnectStateChange(const LLSD& /*data*/) { if (FSPrimfeedAuth::isAuthorized()) { - sendPhoto(); + return true; } return false; @@ -352,10 +368,10 @@ void FSPrimfeedPhotoPanel::sendPhoto() std::string description = mDescriptionTextBox->getValue().asString(); // Get the content rating - int content_rating = mRatingComboBox->getValue().asInteger(); - bool post_to_public_gallery = mPublicGalleryCheckbox->getValue().asBoolean(); - bool commercial_content = mCommercialCheckbox->getValue().asBoolean(); - + int content_rating = mRatingComboBox->getValue().asInteger(); + bool post_to_public_gallery = mPublicGalleryCheckbox->getValue().asBoolean(); + bool commercial_content = mCommercialCheckbox->getValue().asBoolean(); + std::string store_id = mStoresComboBox->getValue().asString(); // Get the image LLSnapshotLivePreview* previewp = getPreviewView(); @@ -376,6 +392,11 @@ void FSPrimfeedPhotoPanel::sendPhoto() params["location"] = slurl_string; } + if (!store_id.empty()) + { + // Add the store ID if we have one selected + params["store_id"] = store_id; + } FSPrimfeedConnect::instance().uploadPhoto(params, previewp->getFormattedImage().get(), [this](bool success, const std::string& url) @@ -529,6 +550,35 @@ void FSPrimfeedPhotoPanel::checkAspectRatio(S32 index) } } +void FSPrimfeedPhotoPanel::loadPrimfeedInfo(const LLSD& data) +{ + if (!mStoresComboBox) + return; + + // Clear any existing entries + mStoresComboBox->clearRows(); + mStoresComboBox->add(LLTrans::getString("Personal"), LLSD("")); + + // Read the saved stores array + const LLSD& stores = data["stores"]; + if (!stores.isArray() || stores.size() == 0) + { + // No stores - disable the combobox + mStoresComboBox->setEnabled(false); + return; + } + + mStoresComboBox->setEnabled(true); + for (S32 i = 0; i < stores.size(); ++i) + { + const LLSD& store = stores[i]; + std::string id = store["id"].asString(); + std::string name = store["name"].asString(); + mStoresComboBox->add(name, LLSD(id)); + } + mStoresComboBox->setCurrentByIndex(0); +} + LLUICtrl* FSPrimfeedPhotoPanel::getRefreshBtn() { return mRefreshBtn; @@ -536,13 +586,10 @@ LLUICtrl* FSPrimfeedPhotoPanel::getRefreshBtn() void FSPrimfeedPhotoPanel::onOpen(const LLSD& key) { - if (!FSPrimfeedAuth::isAuthorized()) - { - // Reauthorise if necessary. - FSPrimfeedAuth::initiateAuthRequest(); - LLSD dummy; - onPrimfeedConnectStateChange(dummy); - } + // Reauthorise if necessary. + FSPrimfeedAuth::initiateAuthRequest(); + LLSD dummy; + onPrimfeedConnectStateChange(dummy); } void FSPrimfeedPhotoPanel::uploadCallback(bool success, const LLSD& response) @@ -639,9 +686,23 @@ FSPrimfeedAccountPanel::FSPrimfeedAccountPanel() : FSPrimfeedAuth::sPrimfeedAuthPump->listen("FSPrimfeedAccountPanel", [this](const LLSD& data) { - bool success = data["success"].asBoolean(); - primfeedAuthResponse(success, data); - return true; + if (data.has("responseType")) + { + auto response_type = data["responseType"].asString(); + if (response_type == "primfeed_auth_response") + { + bool success = data["success"].asBoolean(); + primfeedAuthResponse(success, data); + return true; + } + if (response_type == "primfeed_auth_reset") + { + bool success = data["success"].asBoolean(); + primfeedAuthResponse(success, data); + return true; + } + } + return false; }); setVisibleCallback([this](LLUICtrl*, bool visible) { onVisibilityChange(visible); }); @@ -663,8 +724,8 @@ bool FSPrimfeedAccountPanel::postBuild() void FSPrimfeedAccountPanel::draw() { - FSPrimfeedConnect::EConnectionState connection_state = FSPrimfeedConnect::instance().getConnectionState(); - static FSPrimfeedConnect::EConnectionState last_state = FSPrimfeedConnect::PRIMFEED_DISCONNECTED; + FSPrimfeedConnect::EConnectionState connection_state = FSPrimfeedConnect::instance().getConnectionState(); + static FSPrimfeedConnect::EConnectionState last_state = FSPrimfeedConnect::PRIMFEED_DISCONNECTED; // Update the connection state if it has changed if (connection_state != last_state) @@ -772,14 +833,20 @@ void FSPrimfeedAccountPanel::onConnect() { FSPrimfeedAuth::initiateAuthRequest(); LLSD dummy; - onPrimfeedConnectStateChange(dummy); + onPrimfeedConnectStateChange(dummy); } void FSPrimfeedAccountPanel::onDisconnect() { FSPrimfeedAuth::resetAuthStatus(); LLSD dummy; - onPrimfeedConnectStateChange(dummy); + onPrimfeedConnectStateChange(dummy); +} + +FSPrimfeedAccountPanel::~FSPrimfeedAccountPanel() +{ + // Disconnect the primfeed auth pump + FSPrimfeedAuth::sPrimfeedAuthPump->stopListening("FSPrimfeedAccountPanel"); } //////////////////////// @@ -789,10 +856,10 @@ void FSPrimfeedAccountPanel::onDisconnect() FSFloaterPrimfeed::FSFloaterPrimfeed(const LLSD& key) : LLFloater(key), mPrimfeedPhotoPanel(nullptr), + mPrimfeedAccountPanel(nullptr), mStatusErrorText(nullptr), mStatusLoadingText(nullptr), - mStatusLoadingIndicator(nullptr), - mPrimfeedAccountPanel(nullptr) + mStatusLoadingIndicator(nullptr) { mCommitCallbackRegistrar.add("SocialSharing.Cancel", [this](LLUICtrl*, const LLSD&) { onCancel(); }); } diff --git a/indra/newview/fsfloaterprimfeed.h b/indra/newview/fsfloaterprimfeed.h index 312f06c130..e1c33a6182 100644 --- a/indra/newview/fsfloaterprimfeed.h +++ b/indra/newview/fsfloaterprimfeed.h @@ -34,6 +34,7 @@ class LLIconCtrl; class LLCheckBoxCtrl; +class LLComboBox; class LLSnapshotLivePreview; class LLFloaterBigPreview; @@ -52,6 +53,7 @@ public: bool postBuild() override; S32 notify(const LLSD& info); void draw() override; + void loadPrimfeedInfo(const LLSD& data); LLSnapshotLivePreview* getPreviewView(); void onVisibilityChange(bool new_visibility); @@ -80,28 +82,30 @@ private: LLHandle mPreviewHandle; - LLUICtrl * mResolutionComboBox; - LLUICtrl * mFilterComboBox; - LLUICtrl * mRefreshBtn; - LLUICtrl * mWorkingLabel; - LLUICtrl * mThumbnailPlaceholder; - LLUICtrl * mDescriptionTextBox; - LLUICtrl * mLocationCheckbox; + LLUICtrl* mResolutionComboBox; + LLUICtrl* mFilterComboBox; + LLUICtrl* mRefreshBtn; + LLUICtrl* mWorkingLabel; + LLUICtrl* mThumbnailPlaceholder; + LLUICtrl* mDescriptionTextBox; + LLUICtrl* mLocationCheckbox; - LLUICtrl * mCommercialCheckbox; - LLUICtrl * mPublicGalleryCheckbox; - LLUICtrl * mRatingComboBox; - LLUICtrl * mPostButton; - LLUICtrl * mCancelButton; - LLButton * mBtnPreview; + LLUICtrl* mCommercialCheckbox; + LLUICtrl* mPublicGalleryCheckbox; + LLUICtrl* mRatingComboBox; + LLUICtrl* mPostButton; + LLUICtrl* mCancelButton; + LLButton* mBtnPreview; + LLComboBox* mStoresComboBox; - LLFloaterBigPreview * mBigPreviewFloater; + LLFloaterBigPreview* mBigPreviewFloater; }; class FSPrimfeedAccountPanel : public LLPanel { public: FSPrimfeedAccountPanel(); + ~FSPrimfeedAccountPanel(); bool postBuild() override; void draw() override; diff --git a/indra/newview/fsprimfeedauth.cpp b/indra/newview/fsprimfeedauth.cpp index 2c7c66f60c..20b9b6a042 100644 --- a/indra/newview/fsprimfeedauth.cpp +++ b/indra/newview/fsprimfeedauth.cpp @@ -112,31 +112,25 @@ void FSPrimfeedAuth::initiateAuthRequest() // It should be called when the user clicks the "Authenticate" button. // Also triggered on opening the floater. // The actual implementation is in the create() method. - - if (!isAuthorized()) + + if (sPrimfeedAuth) { - if (sPrimfeedAuth) + LLNotificationsUtil::add("PrimfeedAuthorizationAlreadyInProgress"); + return; + } + // If no token stored, begin the login request; otherwise check user status. + sPrimfeedAuth = FSPrimfeedAuth::create( + [](bool success, const LLSD &response) { - LLNotificationsUtil::add("PrimfeedAuthorizationAlreadyInProgress"); - return; + LLSD event_data = response; + event_data["responseType"] = "primfeed_auth_response"; + event_data["success"] = success; + sPrimfeedAuthPump->post(event_data); + // Now that auth is complete, clear the static pointer. + sPrimfeedAuth.reset(); } - // If no token stored, begin the login request; otherwise check user status. - sPrimfeedAuth = FSPrimfeedAuth::create( - [](bool success, const LLSD &response) - { - LLSD event_data = response; - event_data["success"] = success; - sPrimfeedAuthPump->post(event_data); - // Now that auth is complete, clear the static pointer. - sPrimfeedAuth.reset(); - } - ); - FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_CONNECTING); - } - else - { - LLNotificationsUtil::add("PrimfeedAlreadyAuthorized"); - } + ); + FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_CONNECTING); } void FSPrimfeedAuth::resetAuthStatus() @@ -147,7 +141,7 @@ void FSPrimfeedAuth::resetAuthStatus() gSavedPerAccountSettings.setString("FSPrimfeedPlan", ""); gSavedPerAccountSettings.setString("FSPrimfeedUsername", ""); LLSD event_data; - event_data["status"] = "reset"; + event_data["responseType"] = "primfeed_auth_reset"; event_data["success"] = "false"; sPrimfeedAuthPump->post(event_data); FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_DISCONNECTED); @@ -201,7 +195,8 @@ std::shared_ptr FSPrimfeedAuth::create(authorized_callback_t cal FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_CONNECTING); // If no token stored, begin the login request; otherwise check user status. - if (gSavedPerAccountSettings.getString("FSPrimfeedOAuthToken").empty()) + auth->mOauthToken = gSavedPerAccountSettings.getString("FSPrimfeedOAuthToken"); + if (auth->mOauthToken.empty()) { auth->beginLoginRequest(); } @@ -432,22 +427,23 @@ void FSPrimfeedAuth::checkUserStatus() } -void FSPrimfeedAuth::gotUserStatus(bool success, const LLSD &response) +void FSPrimfeedAuth::gotUserStatus(bool success, const LLSD &response) const { LL_INFOS("Primfeed") << "User status: " << response << "(" << success << ")" << LL_ENDL; - if (success && response.has("plan")) + if (success && response.has("plan") && response.has("username") && response.has("link")) { gSavedPerAccountSettings.setString("FSPrimfeedOAuthToken", mOauthToken); gSavedPerAccountSettings.setString("FSPrimfeedPlan", response["plan"].asString()); gSavedPerAccountSettings.setString("FSPrimfeedProfileLink", response["link"].asString()); gSavedPerAccountSettings.setString("FSPrimfeedUsername", response["username"].asString()); FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_CONNECTED); + LLSD event_data = response; + event_data["responseType"] = "primfeed_user_info"; + sPrimfeedAuthPump->post(event_data); mCallback(true, response); + return; } - else - { - LLNotificationsUtil::add("PrimfeedUserStatusFailed"); - FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_DISCONNECTED); - mCallback(false, response); - } + LLNotificationsUtil::add("PrimfeedUserStatusFailed"); + FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_DISCONNECTED); + mCallback(false, response); } diff --git a/indra/newview/fsprimfeedauth.h b/indra/newview/fsprimfeedauth.h index 43fc36a937..5e3934269f 100644 --- a/indra/newview/fsprimfeedauth.h +++ b/indra/newview/fsprimfeedauth.h @@ -79,7 +79,7 @@ private: // Callback when the validate response is received. void gotValidateResponse(bool success, const LLSD &response); // Callback when the user status response is received. - void gotUserStatus(bool success, const LLSD &response); + void gotUserStatus(bool success, const LLSD &response) const; boost::signals2::connection mInstantMessageConnection; boost::signals2::connection mChatMessageConnection; diff --git a/indra/newview/fsprimfeedconnect.cpp b/indra/newview/fsprimfeedconnect.cpp index 6c6d849152..442a4789e5 100644 --- a/indra/newview/fsprimfeedconnect.cpp +++ b/indra/newview/fsprimfeedconnect.cpp @@ -89,6 +89,7 @@ void FSPrimfeedConnect::uploadPhotoCoro(const LLSD& params, LLImageFormatted* im addPart("location", params["location"].asString()); } + LL_DEBUGS("primfeed") << "Adding image file header" << LL_ENDL; body << dash << sep << "Content-Disposition: form-data; name=\"image\"; filename=\"snapshot." << fmt << "\"" << sep @@ -122,12 +123,11 @@ void FSPrimfeedConnect::uploadPhotoCoro(const LLSD& params, LLImageFormatted* im headers->append(HTTP_OUT_HEADER_USER_AGENT, FS_PF_USER_AGENT); headers->append("Authorization", "Bearer " + token); headers->append("pf-viewer-api-key", apiKey); - headers->append("Content-Type", "multipart/form-data; boundary=" + boundary); - LL_DEBUGS("primfeed") << "Dumping HTTP headers for POST:" << LL_ENDL; - for (auto it = headers->begin(); it != headers->end(); ++it) + if (params.has("store_id") && !params["store_id"].asString().empty()) { - LL_DEBUGS("primfeed") << it->first << ": " << it->second << LL_ENDL; + headers->append("kynno-selected-store", params["store_id"].asString()); } + headers->append("Content-Type", "multipart/form-data; boundary=" + boundary); LL_DEBUGS("primfeed") << "Headers set" << LL_ENDL; LL_DEBUGS("primfeed") << "Starting HTTP POST" << LL_ENDL; @@ -182,9 +182,3 @@ bool FSPrimfeedConnect::isTransactionOngoing() const mConnectionState == PRIMFEED_DISCONNECTING); } -void FSPrimfeedConnect::loadPrimfeedInfo() -{ - LL_DEBUGS("primfeed") << "loadPrimfeedInfo() called" << LL_ENDL; - // Nothing to do here for Primfeed - setConnectionState(PRIMFEED_CONNECTED); -} \ No newline at end of file diff --git a/indra/newview/llagentbenefits.cpp b/indra/newview/llagentbenefits.cpp index 01a701094d..ce14b51ce7 100644 --- a/indra/newview/llagentbenefits.cpp +++ b/indra/newview/llagentbenefits.cpp @@ -305,7 +305,10 @@ S32 LLAgentBenefits::get2KTextureUploadCost(S32 area) const { if (m_2k_texture_upload_cost.empty()) { - return m_texture_upload_cost; + // OpenSim legacy economy + //return m_texture_upload_cost; + return LLGridManager::instance().isInSecondLife() ? m_texture_upload_cost : LLGlobalEconomy::instance().getPriceUpload(); + // } return m_2k_texture_upload_cost[0]; } diff --git a/indra/newview/llheroprobemanager.cpp b/indra/newview/llheroprobemanager.cpp index 477a348c72..8633fe00cb 100644 --- a/indra/newview/llheroprobemanager.cpp +++ b/indra/newview/llheroprobemanager.cpp @@ -60,7 +60,7 @@ static void touch_default_probe(LLReflectionMap* probe) } } -LLHeroProbeManager::LLHeroProbeManager():mMirrorNormal(0,0,1) // [FIRE-35007][#3331] mirrors not working after relog. make sure the mirror normal is not zero length +LLHeroProbeManager::LLHeroProbeManager() { } diff --git a/indra/newview/skins/default/xui/de/panel_primfeed_photo.xml b/indra/newview/skins/default/xui/de/panel_primfeed_photo.xml index 1f58d06d0d..88dbb3c47f 100644 --- a/indra/newview/skins/default/xui/de/panel_primfeed_photo.xml +++ b/indra/newview/skins/default/xui/de/panel_primfeed_photo.xml @@ -15,6 +15,10 @@ + + Post as: + + + + - + +