Skip to content
Merged
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
55 changes: 55 additions & 0 deletions indra/llcommon/llsdutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,61 @@ LLSD shallow(LLSD value, LLSD filter=LLSD()) { return llsd_shallow(value, filter

} // namespace llsd

/*****************************************************************************
* toArray(), toMap()
*****************************************************************************/
namespace llsd
{

// For some T convertible to LLSD, given std::vector<T> myVec,
// toArray(myVec) returns an LLSD array whose entries correspond to the
// items in myVec.
// For some U convertible to LLSD, given function U xform(const T&),
// toArray(myVec, xform) returns an LLSD array whose every entry is
// xform(item) of the corresponding item in myVec.
// toArray() actually works with any container<C> usable with range
// 'for', not just std::vector.
// (Once we get C++20 we can use std::identity instead of this default lambda.)
template<typename C, typename FUNC>
LLSD toArray(const C& container, FUNC&& func = [](const auto& arg) { return arg; })
{
LLSD array;
for (const auto& item : container)
{
array.append(std::forward<FUNC>(func)(item));
}
return array;
}

// For some T convertible to LLSD, given std::map<std::string, T> myMap,
// toMap(myMap) returns an LLSD map whose entries correspond to the
// (key, value) pairs in myMap.
// For some U convertible to LLSD, given function
// std::pair<std::string, U> xform(const std::pair<std::string, T>&),
// toMap(myMap, xform) returns an LLSD map whose every entry is
// xform(pair) of the corresponding (key, value) pair in myMap.
// toMap() actually works with any container usable with range 'for', not
// just std::map. It need not even be an associative container, as long as
// you pass an xform function that returns std::pair<std::string, U>.
// (Once we get C++20 we can use std::identity instead of this default lambda.)
template<typename C, typename FUNC>
LLSD toMap(const C& container, FUNC&& func = [](const auto& arg) { return arg; })
{
LLSD map;
for (const auto& pair : container)
{
const auto& [key, value] = std::forward<FUNC>(func)(pair);
map[key] = value;
}
return map;
}

} // namespace llsd

/*****************************************************************************
* boost::hash<LLSD>
*****************************************************************************/

// Specialization for generating a hash value from an LLSD block.
namespace boost
{
Expand Down
2 changes: 2 additions & 0 deletions indra/newview/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ set(viewer_SOURCE_FILES
llagentwearables.cpp
llanimstatelabels.cpp
llappcorehttp.cpp
llappearancelistener.cpp
llappearancemgr.cpp
llappviewer.cpp
llappviewerlistener.cpp
Expand Down Expand Up @@ -761,6 +762,7 @@ set(viewer_HEADER_FILES
llanimstatelabels.h
llappcorehttp.h
llappearance.h
llappearancelistener.h
llappearancemgr.h
llappviewer.h
llappviewerlistener.h
Expand Down
84 changes: 55 additions & 29 deletions indra/newview/groupchatlistener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
* @file groupchatlistener.cpp
* @author Nat Goodspeed
* @date 2011-04-11
* @brief Implementation for groupchatlistener.
* @brief Implementation for LLGroupChatListener.
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, Linden Research, Inc.
* Copyright (C) 2024, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
Expand Down Expand Up @@ -34,43 +34,69 @@
// std headers
// external library headers
// other Linden headers
#include "llchat.h"
#include "llgroupactions.h"
#include "llimview.h"

LLGroupChatListener::LLGroupChatListener():
LLEventAPI("GroupChat",
"API to enter, leave, send and intercept group chat messages")
{
add("startGroupChat",
"Enter a group chat in group with UUID [\"group_id\"]\n"
"Assumes the logged-in agent is already a member of this group.",
&LLGroupChatListener::startGroupChat,
llsd::map("group_id", LLSD()));
add("leaveGroupChat",
"Leave a group chat in group with UUID [\"group_id\"]\n"
"Assumes a prior successful startIM request.",
&LLGroupChatListener::leaveGroupChat,
llsd::map("group_id", LLSD()));
add("sendGroupIM",
"send a [\"message\"] to group with UUID [\"group_id\"]",
&LLGroupChatListener::sendGroupIM,
llsd::map("message", LLSD(), "group_id", LLSD()));
}

namespace {
void startIm_wrapper(LLSD const & event)
bool is_in_group(LLEventAPI::Response &response, const LLSD &data)
{
if (!LLGroupActions::isInGroup(data["group_id"]))
{
LLUUID session_id = LLGroupActions::startIM(event["id"].asUUID());
sendReply(LLSDMap("session_id", LLSD(session_id)), event);
response.error(stringize("You are not the member of the group:", std::quoted(data["group_id"].asString())));
return false;
}
return true;
}

void send_message_wrapper(const std::string& text, const LLUUID& session_id, const LLUUID& group_id)
void LLGroupChatListener::startGroupChat(LLSD const &data)
{
Response response(LLSD(), data);
if (!is_in_group(response, data))
{
return;
}
if (LLGroupActions::startIM(data["group_id"]).isNull())
{
LLIMModel::sendMessage(text, session_id, group_id, IM_SESSION_GROUP_START);
return response.error(stringize("Failed to start group chat session ", std::quoted(data["group_id"].asString())));
}
}

void LLGroupChatListener::leaveGroupChat(LLSD const &data)
{
Response response(LLSD(), data);
if (is_in_group(response, data))
{
LLGroupActions::endIM(data["group_id"].asUUID());
}
}

GroupChatListener::GroupChatListener():
LLEventAPI("GroupChat",
"API to enter, leave, send and intercept group chat messages")
void LLGroupChatListener::sendGroupIM(LLSD const &data)
{
add("startIM",
"Enter a group chat in group with UUID [\"id\"]\n"
"Assumes the logged-in agent is already a member of this group.",
&startIm_wrapper);
add("endIM",
"Leave a group chat in group with UUID [\"id\"]\n"
"Assumes a prior successful startIM request.",
&LLGroupActions::endIM,
llsd::array("id"));
add("sendIM",
"send a groupchat IM",
&send_message_wrapper,
llsd::array("text", "session_id", "group_id"));
Response response(LLSD(), data);
if (!is_in_group(response, data))
{
return;
}
LLUUID group_id(data["group_id"]);
LLIMModel::sendMessage(data["message"], gIMMgr->computeSessionID(IM_SESSION_GROUP_START, group_id), group_id, IM_SESSION_SEND);
}
/*
static void sendMessage(const std::string& utf8_text, const LLUUID& im_session_id,
const LLUUID& other_participant_id, EInstantMessage dialog);
*/
15 changes: 10 additions & 5 deletions indra/newview/groupchatlistener.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,20 @@
* $/LicenseInfo$
*/

#if ! defined(LL_GROUPCHATLISTENER_H)
#define LL_GROUPCHATLISTENER_H
#if ! defined(LL_LLGROUPCHATLISTENER_H)
#define LL_LLGROUPCHATLISTENER_H

#include "lleventapi.h"

class GroupChatListener: public LLEventAPI
class LLGroupChatListener: public LLEventAPI
{
public:
GroupChatListener();
LLGroupChatListener();

private:
void startGroupChat(LLSD const &data);
void leaveGroupChat(LLSD const &data);
void sendGroupIM(LLSD const &data);
};

#endif /* ! defined(LL_GROUPCHATLISTENER_H) */
#endif /* ! defined(LL_LLGROUPCHATLISTENER_H) */
Loading