Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions indra/newview/llfloaterimsession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,28 @@ void LLFloaterIMSession::GearDoToSelectedGroup(const LLSD& userdata)
// [/SL:KB]

// [SL:KB] - Patch: Chat-Misc | Checked: 2014-03-22 (Catznip-3.6)
void LLFloaterIMSession::onSnoozeGroupClicked(const LLUICtrl* pCtrl)
{
if (!pCtrl)
{
return;
}

const std::string value = pCtrl->getValue().asString();
if (value == "-1")
{
LLGroupActions::leaveIM(mSessionID);
}
else if (value.empty())
{
LLGroupActions::snoozeIM(mSessionID, 0);
}
else
{
LLGroupActions::snoozeIM(mSessionID, boost::lexical_cast<S32>(value) * 60);
}
}

Comment on lines +281 to +302

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the relevant files and symbols.
git ls-files | rg 'indra/newview/(llfloaterimsession.cpp|llgroupactions.*|.*im_session.xml)$'

printf '\n--- llfloaterimsession.cpp (relevant section) ---\n'
sed -n '260,330p' indra/newview/llfloaterimsession.cpp

printf '\n--- LLGroupActions definitions/usages ---\n'
rg -n "leaveIM\\(|snoozeIM\\(|close_group_im\\(" indra/newview -g '!*.o'

printf '\n--- floater_im_session.xml (relevant section) ---\n'
sed -n '320,350p' indra/newview/skins/default/xui/en/floater_im_session.xml

printf '\n--- snooze/leave behavior references ---\n'
rg -n "CLOSE_SNOOZE|CLOSE_LEAVE|snooze_duration|Next relog|snooze" indra/newview

Repository: AlchemyViewer/Alchemy

Length of output: 8096


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n--- llgroupactions.cpp close_group_im/leaveIM/snoozeIM ---\n'
sed -n '600,665p' indra/newview/llgroupactions.cpp

printf '\n--- llimview.cpp snooze/reopen path ---\n'
sed -n '3540,3795p' indra/newview/llimview.cpp

printf '\n--- llimview.h close action / snoozed sessions declarations ---\n'
sed -n '70,95p' indra/newview/llimview.h
sed -n '535,555p' indra/newview/llimview.h

Repository: AlchemyViewer/Alchemy

Length of output: 12670


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n--- restoreSnoozedSession references ---\n'
rg -n "restoreSnoozedSession\\(" indra/newview

printf '\n--- mSnoozedSessions references ---\n'
rg -n "mSnoozedSessions|checkSnoozeExpiration|isSnoozedSession" indra/newview

printf '\n--- login/session-init hooks that might restore snoozed sessions ---\n'
rg -n "login|logged in|login.*session|session.*login|restore.*snooze|Snooze" indra/newview/ll*.cpp indra/newview/ll*.h

Repository: AlchemyViewer/Alchemy

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1328,1362p' indra/newview/llimprocessing.cpp

printf '\n--- any snooze persistence/serialization hooks ---\n'
rg -n "mSnoozedSessions|snoozed_sessions|restoreSnoozedSession|checkSnoozeExpiration|isSnoozedSession|save.*snooze|load.*snooze" indra/newview/llim*.cpp indra/newview/llim*.h

Repository: AlchemyViewer/Alchemy

Length of output: 3096


Next relog needs persistent snooze handling. value="-1" still calls leaveIM, while snooze state is only kept in mSnoozedSessions in memory. If this option is meant to mute the group until the next login, it needs a persistent restore path; otherwise the label is misleading.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@indra/newview/llfloaterimsession.cpp` around lines 281 - 302, The
LLFloaterIMSession::onSnoozeGroupClicked handler treats the “Next relog” option
as leaveIM and only stores snooze state in mSnoozedSessions, so update the
snooze flow to persist a true “mute until next login” state instead of using a
transient in-memory flag. Add a restore path for that persistent state when
sessions are recreated, and keep the existing snooze durations for the other
value cases while ensuring the value="-1" branch maps to the new persistent
snooze behavior rather than leaving the IM session.

void LLFloaterIMSession::onTeleportClicked(const LLUICtrl* pCtrl)
{
if (pCtrl)
Expand Down Expand Up @@ -478,6 +500,7 @@ bool LLFloaterIMSession::postBuild()
mExtendedButtonPanel->getChild<LLUICtrl>("profile_btn")->setCommitCallback(boost::bind(&LLFloaterIMSession::GearDoToSelectedGroup, this, "view_profile"));
mExtendedButtonPanel->getChild<LLUICtrl>("chat_history_btn")->setCommitCallback(boost::bind(&LLFloaterIMSession::GearDoToSelectedGroup, this, "chat_history"));
mExtendedButtonPanel->getChild<LLUICtrl>("view_notices_btn")->setCommitCallback(boost::bind(&LLFloaterIMSession::GearDoToSelectedGroup, this, "view_notices"));
mExtendedButtonPanel->getChild<LLUICtrl>("snooze_groupt_btn")->setCommitCallback(boost::bind(&LLFloaterIMSession::onSnoozeGroupClicked, this, _1));
}
// [/SL:KB]

Expand Down
1 change: 1 addition & 0 deletions indra/newview/llfloaterimsession.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ class LLFloaterIMSession
bool checkGearMenuItem(const LLSD& userdata);
// [SL:KB] - Patch: Chat-Misc | Checked: 2014-03-22 (Catznip-3.6)
void onTeleportClicked(const LLUICtrl* pCtrl);
void onSnoozeGroupClicked(const LLUICtrl* pCtrl);
// [/SL:KB]
// [SL:KB] - Patch: Chat-BaseGearBtn | Checked: 2014-04-10 (Catznip-3.6)
void GearDoToSelectedGroup(const LLSD& userdata);
Expand Down
33 changes: 33 additions & 0 deletions indra/newview/llgroupactions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,27 @@ LLUUID LLGroupActions::startIM(const LLUUID& group_id)
}
}

static void close_group_im(const LLUUID& group_id, LLIMModel::LLIMSession::SCloseAction close_action, S32 snooze_duration = -1)
{
if (group_id.isNull())
{
return;
}

LLUUID session_id = gIMMgr->computeSessionID(IM_SESSION_GROUP_START, group_id);
if (session_id.notNull())
{
LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id);
if (session)
{
session->mCloseAction = close_action;
session->mSnoozeDuration = snooze_duration;
}

gIMMgr->leaveSession(session_id);
}
}

// static
void LLGroupActions::endIM(const LLUUID& group_id)
{
Expand All @@ -618,6 +639,18 @@ void LLGroupActions::endIM(const LLUUID& group_id)
}
}

// static
void LLGroupActions::leaveIM(const LLUUID& group_id)
{
close_group_im(group_id, LLIMModel::LLIMSession::SCloseAction::CLOSE_LEAVE);
}

// static
void LLGroupActions::snoozeIM(const LLUUID& group_id, S32 snooze_duration)
{
close_group_im(group_id, LLIMModel::LLIMSession::SCloseAction::CLOSE_SNOOZE, snooze_duration);
}

// static
bool LLGroupActions::isInGroup(const LLUUID& group_id)
{
Expand Down
2 changes: 2 additions & 0 deletions indra/newview/llgroupactions.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ class LLGroupActions
* End group instant messaging session.
*/
static void endIM(const LLUUID& group_id);
static void leaveIM(const LLUUID& group_id);
static void snoozeIM(const LLUUID& group_id, S32 snooze_duration = -1);

/// Returns if the current user is a member of the group
static bool isInGroup(const LLUUID& group_id);
Expand Down
7 changes: 6 additions & 1 deletion indra/newview/llimprocessing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1345,7 +1345,12 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
// should happen after you get an "invitation"
if (!gIMMgr->hasSession(session_id))
{
return;
if (!gAgent.isInGroup(session_id) ||
!gIMMgr->checkSnoozeExpiration(session_id) ||
!gIMMgr->restoreSnoozedSession(session_id))
{
return;
}
}

else if (offline == IM_ONLINE && is_do_not_disturb)
Comment on lines 1346 to 1356

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Process the message after restoring the snoozed session.

When restoreSnoozedSession() succeeds, execution leaves the if (!hasSession) block and skips the attached else if / else, so the message that woke the session is dropped.

🐛 Proposed fix
             if (!gIMMgr->hasSession(session_id))
             {
                 if (!gAgent.isInGroup(session_id) ||
                     !gIMMgr->checkSnoozeExpiration(session_id) ||
                     !gIMMgr->restoreSnoozedSession(session_id))
                 {
                     return;
                 }
             }
 
-            else if (offline == IM_ONLINE && is_do_not_disturb)
+            if (offline == IM_ONLINE && is_do_not_disturb)
             {

Also applies to: 1389-1415

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@indra/newview/llimprocessing.cpp` around lines 1346 - 1356, The message
handling in the block using hasSession, checkSnoozeExpiration, and
restoreSnoozedSession drops the incoming message after a snoozed session is
successfully restored because control flow exits the hasSession branch before
the later offline/is_do_not_disturb handling. Update this logic so a successful
restore continues into the normal message-processing path instead of returning
or skipping the rest of the function, and make the same change in the duplicated
code path referenced by the other affected section.

Expand Down
52 changes: 50 additions & 2 deletions indra/newview/llimview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3556,7 +3556,17 @@ bool LLIMMgr::leaveSession(const LLUUID& session_id)
LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id);
if (!im_session) return false;

LLIMModel::getInstance()->sendLeaveSession(session_id, im_session->mOtherParticipantID);
if (im_session->isGroupSessionType() && im_session->mCloseAction == LLIMModel::LLIMSession::SCloseAction::CLOSE_SNOOZE)
{
const F64 duration = llmax(0, im_session->mSnoozeDuration);
mSnoozedSessions[session_id] = LLTimer::getTotalSeconds() + duration;
Comment on lines +3561 to +3562

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Preserve the “next relog” sentinel instead of expiring it immediately.

mSnoozeDuration == -1 is the only visible sentinel for “next relog”, but llmax(0, ...) stores it as an immediately-expired snooze, so the next group message restores the chat instead of keeping it snoozed until logout.

🐛 Proposed fix
-        const F64 duration = llmax(0, im_session->mSnoozeDuration);
-        mSnoozedSessions[session_id] = LLTimer::getTotalSeconds() + duration;
+        const S32 duration = im_session->mSnoozeDuration;
+        mSnoozedSessions[session_id] = duration < 0
+            ? -1.0 // in-memory only: snoozed until next relog
+            : LLTimer::getTotalSeconds() + duration;
-    return it != mSnoozedSessions.end() && it->second <= LLTimer::getTotalSeconds();
+    return it != mSnoozedSessions.end()
+        && it->second >= 0.0
+        && it->second <= LLTimer::getTotalSeconds();

Also applies to: 3760-3763

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@indra/newview/llimview.cpp` around lines 3561 - 3562, The snooze handling in
llimview.cpp is collapsing the “next relog” sentinel because llmax(0,
im_session->mSnoozeDuration) turns mSnoozeDuration == -1 into an immediately
expired timer. Update the snooze calculation in the code paths that assign
mSnoozedSessions for both the session state in llimview.cpp so that the sentinel
value is preserved and treated as “snoozed until logout,” while only finite
snooze durations are converted into a timestamp-based expiry. Use the existing
im_session and mSnoozedSessions logic as the anchor points when applying the
fix.

}
else
{
LLIMModel::getInstance()->sendLeaveSession(session_id, im_session->mOtherParticipantID);
mSnoozedSessions.erase(session_id);
}

gIMMgr->removeSession(session_id);
return true;
}
Expand Down Expand Up @@ -3747,6 +3757,45 @@ bool LLIMMgr::hasSession(const LLUUID& session_id)
return LLIMModel::getInstance()->findIMSession(session_id) != NULL;
}

bool LLIMMgr::checkSnoozeExpiration(const LLUUID& session_id) const
{
snoozed_sessions_t::const_iterator it = mSnoozedSessions.find(session_id);
return it != mSnoozedSessions.end() && it->second <= LLTimer::getTotalSeconds();
}

bool LLIMMgr::isSnoozedSession(const LLUUID& session_id) const
{
return mSnoozedSessions.find(session_id) != mSnoozedSessions.end();
}

bool LLIMMgr::restoreSnoozedSession(const LLUUID& session_id)
{
snoozed_sessions_t::iterator it = mSnoozedSessions.find(session_id);
if (it == mSnoozedSessions.end())
{
return false;
}

mSnoozedSessions.erase(it);

LLGroupData group_data;
if (!gAgent.getGroupData(session_id, group_data))
{
return false;
}
Comment on lines +3779 to +3785

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Don’t consume snooze state before restoration can succeed.

If getGroupData() fails, this returns false after erasing the snooze entry, so future messages can no longer restore the snoozed session.

🐛 Proposed fix
-    mSnoozedSessions.erase(it);
-
     LLGroupData group_data;
     if (!gAgent.getGroupData(session_id, group_data))
     {
         return false;
     }
+
+    mSnoozedSessions.erase(it);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
mSnoozedSessions.erase(it);
LLGroupData group_data;
if (!gAgent.getGroupData(session_id, group_data))
{
return false;
}
LLGroupData group_data;
if (!gAgent.getGroupData(session_id, group_data))
{
return false;
}
mSnoozedSessions.erase(it);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@indra/newview/llimview.cpp` around lines 3779 - 3785, The snooze entry is
being removed before restoration is confirmed, so a failed getGroupData() call
leaves the session permanently unsnoozed. Update the snoozed-session restoration
flow in the logic that uses mSnoozedSessions and gAgent.getGroupData() so the
erase only happens after group data has been successfully retrieved and the
session can actually be restored. Keep the existing false return path, but
preserve the snooze state when restoration cannot proceed.


gIMMgr->addSession(group_data.mName, IM_SESSION_GROUP_START, session_id);

uuid_vec_t ids;
LLIMModel::sendStartSession(session_id, session_id, ids, IM_SESSION_GROUP_START, false);

if (!gAgent.isDoNotDisturb())
{
make_ui_sound("UISndStartIM");
}
return true;
}

void LLIMMgr::clearPendingInvitation(const LLUUID& session_id)
{
if ( mPendingInvitations.has(session_id.asString()) )
Expand Down Expand Up @@ -4441,4 +4490,3 @@ LLHTTPRegistration<LLViewerChatterBoxSessionUpdate>
LLHTTPRegistration<LLViewerChatterBoxInvitation>
gHTTPRegistrationMessageChatterBoxInvitation(
"/message/ChatterBoxInvitation");

15 changes: 15 additions & 0 deletions indra/newview/llimview.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ class LLIMModel : public LLSingleton<LLIMModel>
NONE_SESSION,
} SType;

enum class SCloseAction
{
CLOSE_DEFAULT,
CLOSE_LEAVE,
CLOSE_SNOOZE
};

LLIMSession(const LLUUID& session_id, const std::string& name,
const EInstantMessage& type, const LLUUID& other_participant_id, const LLSD& voiceChannelInfo, const uuid_vec_t& ids, bool has_offline_msg);
virtual ~LLIMSession();
Expand Down Expand Up @@ -122,6 +129,8 @@ class LLIMModel : public LLSingleton<LLIMModel>
std::string mName;
EInstantMessage mType;
SType mSessionType;
SCloseAction mCloseAction = SCloseAction::CLOSE_DEFAULT;
S32 mSnoozeDuration = -1;
LLUUID mOtherParticipantID;
uuid_vec_t mInitialTargetIDs;
std::string mHistoryFileName;
Expand Down Expand Up @@ -444,6 +453,9 @@ class LLIMMgr : public LLSingleton<LLIMMgr>
void disconnectAllSessions();

bool hasSession(const LLUUID& session_id);
bool checkSnoozeExpiration(const LLUUID& session_id) const;
bool isSnoozedSession(const LLUUID& session_id) const;
bool restoreSnoozedSession(const LLUUID& session_id);

static LLUUID computeSessionID(EInstantMessage dialog, const LLUUID& other_participant_id);

Expand Down Expand Up @@ -529,6 +541,9 @@ class LLIMMgr : public LLSingleton<LLIMMgr>

LLSD mPendingInvitations;
LLSD mPendingAgentListUpdates;

typedef std::map<LLUUID, F64> snoozed_sessions_t;
snoozed_sessions_t mSnoozedSessions;
};

class LLCallDialogManager : public LLSingleton<LLCallDialogManager>
Expand Down
50 changes: 50 additions & 0 deletions indra/newview/skins/default/xui/en/floater_im_session.xml
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,56 @@
tool_tip="View group notices"
top="1"
width="31" />
<flyout_button
arrow_button_width="18"
follows="top|left"
height="25"
halign="left"
label=""
layout="topleft"
left_pad="2"
name="snooze_groupt_btn"
tool_tip="Snooze group chat"
top="1"
width="44">
<flyout_button.item
label="Next message"
value="0" />
<flyout_button.item
label="5 minutes"
value="5" />
<flyout_button.item
label="15 minutes"
value="15" />
<flyout_button.item
label="30 minutes"
value="30" />
<flyout_button.item
label="45 minutes"
value="45" />
<flyout_button.item
label="1 hour"
value="60" />
<flyout_button.item
label="Next relog"
value="-1" />
<flyout_button.action_button
image_bottom_pad="1"
image_hover_unselected="Toolbar_Middle_Over"
image_overlay="Conv_toolbar_snooze"
image_overlay_alignment="left"
image_selected="Toolbar_Middle_Selected"
image_unselected="transparent.j2c"
imgoverlay_label_space="0" />
<flyout_button.drop_down_button
image_hover_unselected="Toolbar_Middle_Over"
image_overlay="Arrow_Small_Down"
image_overlay_alignment="right"
image_pressed="none"
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
pad_right="-2" />
</flyout_button>
</panel>
<button
follows="right|top"
Expand Down
Loading