aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/rlvhelper.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/newview/rlvhelper.cpp674
1 files changed, 674 insertions, 0 deletions
diff --git a/linden/indra/newview/rlvhelper.cpp b/linden/indra/newview/rlvhelper.cpp
new file mode 100644
index 0000000..6b2a1a0
--- /dev/null
+++ b/linden/indra/newview/rlvhelper.cpp
@@ -0,0 +1,674 @@
1#include "llviewerprecompiledheaders.h"
2#include "llagent.h"
3#include "llviewerobject.h"
4#include "llviewerstats.h"
5#include "llviewerwindow.h"
6#include "llvoavatar.h"
7#include "llwlparammanager.h"
8
9#include "rlvhelper.h"
10#include "rlvevent.h"
11#include "rlvhandler.h"
12
13// ============================================================================
14// Static variable initialization
15//
16
17RlvMultiStringSearch RlvCommand::m_BhvrLookup;
18
19// ============================================================================
20
21// Checked:
22RlvCommand::RlvCommand(const std::string& strCommand)
23 : m_eBehaviour(RLV_BHVR_UNKNOWN), m_eParamType(RLV_TYPE_UNKNOWN)
24{
25 if ((m_fValid = parseCommand(strCommand, m_strBehaviour, m_strOption, m_strParam)))
26 {
27 if ( ("n" == m_strParam) || ("add" == m_strParam) )
28 m_eParamType = RLV_TYPE_ADD;
29 else if ( ("y" == m_strParam) || ("rem" == m_strParam) )
30 m_eParamType = RLV_TYPE_REMOVE;
31 else if ("force" == m_strParam)
32 m_eParamType = RLV_TYPE_FORCE;
33 else
34 {
35 m_eParamType = RLV_TYPE_REPLY; // Assume it's a reply command until we encounter a non-digit
36
37 if ( (m_strParam.empty()) || (-1 != m_strParam.find_first_not_of("0123456789")) )
38 {
39 m_eParamType = RLV_TYPE_UNKNOWN;
40 m_fValid = ("clear" == m_strBehaviour);
41 }
42 }
43 }
44
45 if (!m_fValid)
46 {
47 m_strBehaviour = m_strOption = m_strParam = "";
48 return;
49 }
50
51 U16 nBehaviour;
52 if (m_BhvrLookup.getExactMatchParam(m_strBehaviour, nBehaviour))
53 {
54 m_eBehaviour = (ERlvBehaviour)nBehaviour;
55 }
56}
57
58RlvCommand::RlvCommand(const RlvCommand& rlvCmd)
59 : m_fValid(rlvCmd.m_fValid),
60 m_strBehaviour(rlvCmd.m_strBehaviour), m_eBehaviour(rlvCmd.m_eBehaviour),
61 m_strOption(rlvCmd.m_strOption),
62 m_strParam(rlvCmd.m_strParam), m_eParamType(rlvCmd.m_eParamType)
63{
64}
65
66// ============================================================================
67
68/*
69 * ------------------------------
70 * Command | RLV | RLVa
71 * ------------------------------
72 * : | F | F (missing behaviour)
73 * :option | F | F (missing behaviour)
74 * := | T | F (missing behaviour)
75 * :option= | T | F (missing behaviour)
76 * :option=param | T | F (missing behaviour)
77 * = | T | F (missing behaviour)
78 * =param | T | F (missing behaviour)
79 * cmd | F | F (missing param) [T if <behaviour> == "clear"]
80 * cmd: | F | F (missing param)
81 * cmd:option | F | F (missing param)
82 * cmd:= | T | F (missing param) [1]
83 * cmd:option= | T | F (missing param) [1]
84 * cmd= | T | F (missing param) [1]
85 * cmd:option=param | T | T
86 * cmd=param | T | T
87 * cmd:=param | T | T
88 *
89 * [1] 'clear:=', 'clear:option=' and 'clear=' are "valid" variations of 'clear'
90 */
91
92BOOL RlvCommand::parseCommand(/*[in]*/ const std::string& strCommand,
93 /*[out]*/ std::string& strBehaviour, /*[out]*/ std::string& strOption, /*[out]*/ std::string& strParam)
94{
95 // Format: <behaviour>[:<option>]=<param>
96 int idxParam = strCommand.find('=');
97 int idxOption = (idxParam > 0) ? strCommand.find(':') : -1;
98 if (idxOption > idxParam - 1)
99 idxOption = -1;
100
101 // If <behaviour> is missing it's always an improperly formatted command
102 if ( (0 == idxOption) || (0 == idxParam) )
103 return FALSE;
104
105 strBehaviour = strCommand.substr(0, (-1 != idxOption) ? idxOption : idxParam);
106 strOption = strParam = "";
107
108 // If <param> is missing it's an improperly formatted command
109 if ( (-1 == idxParam) || ((int)strCommand.length() - 1 == idxParam) )
110 {
111 // Unless "<behaviour> == "clear" AND (idxOption == 0)"
112 // OR <behaviour> == "clear" AND (idxParam != 0) [see table above]
113 if ( ("clear" == strBehaviour) && ( (!idxOption) || (idxParam) ) )
114 return TRUE;
115 return FALSE;
116 }
117
118 if ( (-1 != idxOption) && (idxOption + 1 != idxParam) )
119 strOption = strCommand.substr(idxOption + 1, idxParam - idxOption - 1);
120 strParam = strCommand.substr(idxParam + 1);
121
122 return TRUE;
123}
124
125void RlvCommand::initLookupTable()
126{
127 static bool fInitialized = false;
128 if (!fInitialized)
129 {
130 // NOTE: keep this match with the enumeration at all times
131 std::string arBehaviours[RLV_BHVR_COUNT] =
132 {
133 "version", "detach", "redirchat", "rediremote", "sendim", "recvchat", "recvemote", "recvim", "tploc", "tplure",
134 "sittp", "edit", "rez", "addoutfit", "remoutfit", "getoutfit", "getattach", "showinv", "unsit", "sit",
135 "getstatus", "getstatusall", "getinv", "getinvworn", "findfolder", "findfolders", "attach", "attachall", "detachall",
136 "getpath", "attachthis", "attachallthis", "detachthis", "detachallthis", "fartouch", "showworldmap", "showminimap",
137 "showloc", "tpto", "accepttp", "shownames", "fly", "getsitid", "setdebug", "setenv", "detachme",
138 "showhovertextall", "showhovertextworld", "showhovertexthud", "showhovertext", "notify"
139 };
140
141 for (int idxBvhr = 0; idxBvhr < RLV_BHVR_COUNT; idxBvhr++)
142 m_BhvrLookup.addKeyword(arBehaviours[idxBvhr], idxBvhr);
143
144 fInitialized = true;
145 }
146}
147
148// Checked: 2009-06-07 (RLVa-0.2.1c)
149std::string RlvCommand::asString() const
150{
151 return (!m_strOption.empty()) ? (std::string(m_strBehaviour)).append(":").append(m_strOption) : (std::string(m_strBehaviour));
152}
153
154// =========================================================================
155
156BOOL RlvObject::addCommand(const RlvCommand& rlvCmd)
157{
158 // Sanity checking
159 if (RLV_TYPE_ADD != rlvCmd.getParamType())
160 return FALSE;
161
162 // Don't add duplicate commands for this object (ie @detach=n followed by another @detach=n later on)
163 BOOL fDuplicate =
164 (RLV_BHVR_UNKNOWN != rlvCmd.getBehaviourType())
165 ? hasBehaviour(rlvCmd.getBehaviourType(), rlvCmd.getOption())
166 : hasBehaviour(rlvCmd.getBehaviour(), rlvCmd.getOption());
167 if (fDuplicate)
168 return FALSE;
169
170 // Now that we know it's not a duplicate, add it to the end of the list
171 m_Commands.push_back(rlvCmd);
172
173 return TRUE;
174}
175
176BOOL RlvObject::removeCommand(const RlvCommand& rlvCmd)
177{
178 // Sanity checking
179 if (RLV_TYPE_REMOVE != rlvCmd.getParamType())
180 return FALSE;
181
182 for (rlv_command_list_t::iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd)
183 {
184 //if (*itCmd == rlvCmd) <- commands will never be equal since one is an add and the other is a remove *rolls eyes*
185 if ( (itCmd->getBehaviour() == rlvCmd.getBehaviour()) && (itCmd->getOption() == rlvCmd.getOption()) )
186 {
187 m_Commands.erase(itCmd);
188 return TRUE;
189 }
190 }
191 return FALSE; // Command was never added so nothing to remove now
192}
193
194BOOL RlvObject::hasBehaviour(ERlvBehaviour eBehaviour) const
195{
196 for (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd)
197 if ( (itCmd->getBehaviourType() == eBehaviour) && (itCmd->getOption().empty()) )
198 return TRUE;
199 return FALSE;
200}
201
202BOOL RlvObject::hasBehaviour(const std::string& strBehaviour) const
203{
204 for (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd)
205 if ( (itCmd->getBehaviour() == strBehaviour) && (itCmd->getOption().empty()) )
206 return TRUE;
207 return FALSE;
208}
209
210BOOL RlvObject::hasBehaviour(ERlvBehaviour eBehaviour, const std::string& strOption) const
211{
212 for (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd)
213 if ( (itCmd->getBehaviourType() == eBehaviour) && (itCmd->getOption() == strOption) )
214 return TRUE;
215 return FALSE;
216}
217
218BOOL RlvObject::hasBehaviour(const std::string& strBehaviour, const std::string& strOption) const
219{
220 for (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd)
221 if ( (itCmd->getBehaviour() == strBehaviour) && (itCmd->getOption() == strOption) )
222 return TRUE;
223 return FALSE;
224}
225
226// Checked: 2009-06-07 (RLVa-0.2.1c)
227std::string RlvObject::getStatusString(const std::string& strMatch) const
228{
229 std::string strStatus, strCmd;
230
231 for (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd)
232 {
233 strCmd = itCmd->asString();
234 if ( (strMatch.empty()) || (std::string::npos != strCmd.find(strMatch)) )
235 {
236 if (!strStatus.empty())
237 strStatus.push_back('/');
238 strStatus += strCmd;
239 }
240 }
241
242 return strStatus;
243}
244
245// =========================================================================
246/*
247 * Various helper classes/timers/functors
248 *
249 */
250
251// Checked: 2009-05-26 (RLVa-0.2.0d) | Modified: RLVa-0.2.0d
252S32 rlvGetDirectDescendentsCount(const LLInventoryCategory* pFolder, LLAssetType::EType type)
253{
254 S32 cntType = 0;
255 if (pFolder)
256 {
257 LLInventoryModel::cat_array_t* pFolders;
258 LLInventoryModel::item_array_t* pItems;
259 gInventory.getDirectDescendentsOf(pFolder->getUUID(), pFolders, pItems);
260
261 if (pItems)
262 {
263 for (S32 idxItem = 0, cntItem = pItems->count(); idxItem < cntItem; idxItem++)
264 if (pItems->get(idxItem)->getType() == type)
265 cntType++;
266 }
267 }
268 return cntType;
269}
270
271// Checked: 2009-05-30 (RLVa-0.2.0e) | Added: RLVa-0.2.0e
272const LLUUID& RlvWearableItemCollector::getFoldedParent(const LLUUID& idFolder) const
273{
274 std::map<LLUUID, LLUUID>::const_iterator itFolder = m_Folding.end(), itCur = m_Folding.find(idFolder);
275 while (itCur != m_Folding.end())
276 {
277 itFolder = itCur;
278 itCur = m_Folding.find(itFolder->second);
279 }
280 return (m_Folding.end() == itFolder) ? idFolder : itFolder->second;
281}
282
283// Checked: 2009-07-29 (RLVa-1.0.1b) | Modified: RLVa-1.0.1b
284bool RlvWearableItemCollector::onCollectFolder(const LLInventoryCategory* pFolder)
285{
286 const LLUUID& idParent = pFolder->getParentUUID();
287 if (m_Wearable.end() == std::find(m_Wearable.begin(), m_Wearable.end(), idParent))
288 return false; // Not the child of a wearable folder == skip
289
290 const std::string& strFolder = pFolder->getName();
291 if (strFolder.empty()) // Shouldn't happen but does... naughty Lindens
292 return false;
293
294 #ifdef RLV_EXTENSION_FLAG_NOSTRIP
295 if ( (!m_fAttach) && (-1 != strFolder.find(RLV_FOLDER_FLAG_NOSTRIP)) ) // Don't process "nostrip" folders on detach
296 return false;
297 #endif // RLV_EXTENSION_FLAG_NOSTRIP
298
299 if (gRlvHandler.isFoldedFolder(pFolder, m_fAttach)) // Check for folder that should get folded under its parent
300 {
301 m_Tentative.push_front(pFolder->getUUID());
302 m_Folding.insert(std::pair<LLUUID, LLUUID>(pFolder->getUUID(), idParent));
303 }
304 else if ( (RLV_FOLDER_PREFIX_HIDDEN != strFolder[0]) && (m_fMatchAll) ) // Collect from any non-hidden child folder for *all
305 {
306 m_Wearable.push_front(pFolder->getUUID());
307 return (idParent == m_idFolder); // (Convenience for @getinvworn)
308 }
309 #ifdef RLV_EXPERIMENTAL_COMPOSITES
310 else if ( (RLV_FOLDER_PREFIX_HIDDEN == strFolder[0]) && // Hidden folder that's a...
311 (gRlvHandler.isCompositeFolder(pFolder)) && // ... composite folder which we...
312 ((m_fAttach) || (gRlvHandler.canTakeOffComposite(pFolder))) ) // ... attach or can detach (see composite locking)
313 {
314 m_Wearable.push_front(pFolder->getUUID());
315 m_Folding.insert(std::pair<LLUUID, LLUUID>(pFolder->getUUID(), idParent));
316 }
317 #endif // RLV_EXPERIMENTAL_COMPOSITES
318
319 return false;
320}
321
322// Checked: 2009-05-26 (RLVa-0.2.0d) | Modified: RLVa-0.2.0d
323bool RlvWearableItemCollector::onCollectItem(const LLInventoryItem* pItem)
324{
325 #ifdef RLV_EXTENSION_FLAG_NOSTRIP
326 if ( (!m_fAttach) && (-1 != pItem->getName().find(RLV_FOLDER_FLAG_NOSTRIP)) ) // Don't process "nostrip" items on detach
327 return false;
328 #endif // RLV_EXTENSION_FLAG_NOSTRIP
329
330 const LLUUID& idParent = pItem->getParentUUID(); bool fRet = false;
331 switch (pItem->getType())
332 {
333 case LLAssetType::AT_BODYPART:
334 if (!m_fAttach)
335 break; // Don't process body parts on detach
336 case LLAssetType::AT_CLOTHING:
337 #ifdef RLV_EXTENSION_FLAG_NOSTRIP
338 fRet = ( (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)) ||
339 ( (m_fAttach) && (m_Tentative.end() != std::find(m_Tentative.begin(), m_Tentative.end(), idParent)) &&
340 (gInventory.getCategory(pItem->getParentUUID())->getName() == ".("RLV_FOLDER_FLAG_NOSTRIP")") ) );
341 #else
342 fRet = (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent));
343 #endif // RLV_EXTENSION_FLAG_NOSTRIP
344 break;
345 case LLAssetType::AT_OBJECT:
346 fRet = ( (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)) ||
347 (m_Tentative.end() != std::find(m_Tentative.begin(), m_Tentative.end(), idParent)) ) &&
348 ( (!m_fAttach) || (gRlvHandler.hasAttachPointName(pItem, true)) ); // Only care about attach point on attach*
349 break;
350 #ifdef RLV_EXPERIMENTAL_FORCEWEAR_GESTURES
351 case LLAssetType::AT_GESTURE:
352 fRet = (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent));
353 break;
354 #endif // RLV_EXPERIMENTAL_FORCEWEAR_GESTURES
355 default:
356 break;
357 }
358 return fRet;
359}
360
361// Checked: 2009-05-26 (RLVa-0.2.0d) | Modified: RLVa-0.2.0d
362bool RlvWearableItemCollector::operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem)
363{
364 // NOTE: this is used for more than was originally intended so only modify if you're sure it won't break something obscure
365 return (pFolder) ? onCollectFolder(pFolder) : ( (pItem) ? onCollectItem(pItem) : false );
366}
367
368// Checked: 2009-07-06 (RLVa-1.0.0c) | Modified: RLVa-0.2.0f
369bool RlvSelectHasLockedAttach::apply(LLSelectNode* pNode)
370{
371 return (pNode->getObject()) ? !gRlvHandler.isDetachable(pNode->getObject()) : false;
372}
373
374// Checked: 2009-07-05 (RLVa-1.0.0b) | Modified: RLVa-0.2.0f
375bool RlvSelectIsOwnedByOrGroupOwned::apply(LLSelectNode* pNode)
376{
377 return (pNode->mPermissions->isGroupOwned()) || (pNode->mPermissions->getOwner() == m_idAgent);
378}
379
380// Checked: 2009-05-31 (RLVa-0.2.0f) | Modified: RLVa-0.2.0f
381bool RlvSelectIsSittingOn::apply(LLSelectNode* pNode)
382{
383 return (pNode->getObject()) && (pNode->getObject()->getRootEdit() == m_pObject);
384}
385
386// Checked: 2009-07-05 (RLVa-1.0.0b) | Modified: RLVa-0.2.0g
387bool rlvCanDeleteOrReturn()
388{
389 bool fIsAllowed = true;
390
391 if (gRlvHandler.hasBehaviour(RLV_BHVR_REZ))
392 {
393 // We'll allow if none of the prims are owned by the avie or group owned
394 LLObjectSelectionHandle handleSel = LLSelectMgr::getInstance()->getSelection();
395 RlvSelectIsOwnedByOrGroupOwned func(gAgent.getID());
396 if ( (handleSel.notNull()) && ((0 == handleSel->getRootObjectCount()) || (NULL != handleSel->getFirstRootNode(&func, FALSE))) )
397 fIsAllowed = false;
398 }
399
400 if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (gAgent.getAvatarObject()) )
401 {
402 // We'll allow if the avie isn't sitting on any of the selected objects
403 LLObjectSelectionHandle handleSel = LLSelectMgr::getInstance()->getSelection();
404 RlvSelectIsSittingOn func(gAgent.getAvatarObject()->getRoot());
405 if ( (handleSel.notNull()) && (handleSel->getFirstRootNode(&func, TRUE)) )
406 fIsAllowed = false;
407 }
408
409 return fIsAllowed;
410}
411
412// Checked: 2009-07-05 (RLVa-1.0.0c)
413BOOL rlvAttachToEnabler(void* pParam)
414{
415 // Enables/disables an option on the "Attach to (HUD)" submenu depending on whether it is (un)detachable
416 LLViewerJointAttachment* pAttachment = (LLViewerJointAttachment*)pParam;
417 return (!pAttachment) || (gRlvHandler.isDetachable(pAttachment->getObject()));
418}
419
420BOOL RlvGCTimer::tick()
421{
422 bool fContinue = gRlvHandler.onGC();
423 if (!fContinue)
424 gRlvHandler.m_pGCTimer = NULL;
425 return !fContinue;
426}
427
428void RlvCurrentlyWorn::fetchWorn()
429{
430 LLInventoryFetchObserver::item_ref_t idItems;
431
432 // Fetch all currently worn clothing layers and body parts
433 for (int type = 0; type < (int)WT_COUNT; type++)
434 {
435 const LLUUID& idItem = gAgent.getWearableItem((EWearableType)type);
436 if (idItem.notNull())
437 idItems.push_back(idItem);
438 }
439
440 // Fetch all currently worn attachments
441 LLVOAvatar* pAvatar = gAgent.getAvatarObject();
442 if (pAvatar)
443 {
444 for (LLVOAvatar::attachment_map_t::const_iterator itAttach = pAvatar->mAttachmentPoints.begin();
445 itAttach != pAvatar->mAttachmentPoints.end(); ++itAttach)
446 {
447 const LLUUID& idItem = itAttach->second->getItemID();
448 if (idItem.notNull())
449 idItems.push_back(idItem);
450 }
451 }
452
453 RlvCurrentlyWorn f;
454 f.fetchItems(idItems);
455}
456
457// =========================================================================
458
459// Checked: 2009-06-03 (RLVa-0.2.0h) | Added: RLVa-0.2.0h
460void RlvWLSnapshot::restoreSnapshot(const RlvWLSnapshot* pWLSnapshot)
461{
462 LLWLParamManager* pWLParams = LLWLParamManager::instance();
463 if ( (pWLSnapshot) && (pWLParams) )
464 {
465 pWLParams->mAnimator.mIsRunning = pWLSnapshot->fIsRunning;
466 pWLParams->mAnimator.mUseLindenTime = pWLSnapshot->fUseLindenTime;
467 pWLParams->mCurParams = pWLSnapshot->WLParams;
468 pWLParams->propagateParameters();
469 }
470}
471
472// Checked: 2009-06-03 (RLVa-0.2.0h) | Added: RLVa-0.2.0h
473RlvWLSnapshot* RlvWLSnapshot::takeSnapshot()
474{
475 RlvWLSnapshot* pWLSnapshot = NULL;
476 LLWLParamManager* pWLParams = LLWLParamManager::instance();
477 if (pWLParams)
478 {
479 pWLSnapshot = new RlvWLSnapshot();
480 pWLSnapshot->fIsRunning = pWLParams->mAnimator.mIsRunning;
481 pWLSnapshot->fUseLindenTime = pWLParams->mAnimator.mUseLindenTime;
482 pWLSnapshot->WLParams = pWLParams->mCurParams;
483 }
484 return pWLSnapshot;
485}
486
487// =========================================================================
488
489BOOL RlvSettings::fShowNameTags = FALSE;
490
491#ifdef RLV_EXTENSION_STARTLOCATION
492 // Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-0.2.1d
493 void RlvSettings::updateLoginLastLocation()
494 {
495 if (gSavedPerAccountSettings.controlExists(RLV_SETTING_LOGINLASTLOCATION))
496 {
497 BOOL fValue = (gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)) ||
498 ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) &&
499 (gAgent.getAvatarObject()) && (!gAgent.getAvatarObject()->mIsSitting) );
500 if (gSavedPerAccountSettings.getBOOL(RLV_SETTING_LOGINLASTLOCATION) != fValue)
501 {
502 gSavedPerAccountSettings.setBOOL(RLV_SETTING_LOGINLASTLOCATION, fValue);
503 gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE);
504 }
505 }
506 }
507#endif // RLV_EXTENSION_STARTLOCATION
508
509// =========================================================================
510
511#ifdef RLV_ADVANCED_TOGGLE_RLVA
512 // Checked: 2009-07-12 (RLVa-1.0.0h) | Modified: RLVa-1.0.0h
513 void rlvDbgToggleEnabled(void*)
514 {
515 gSavedSettings.setBOOL(RLV_SETTING_MAIN, !rlv_handler_t::isEnabled());
516
517 #if RLV_TARGET < RLV_MAKE_TARGET(1, 23, 0) // Version: 1.22.11
518 LLStringUtil::format_map_t args;
519 args["[MESSAGE]"] = llformat("Restrained Life Support will be %s after you restart",
520 (rlv_handler_t::isEnabled()) ? "disabled" : "enabled" );
521 gViewerWindow->alertXml("GenericAlert", args);
522 #else // Version: 1.23.4
523 LLSD args;
524 args["MESSAGE"] = llformat("Restrained Life Support will be %s after you restart",
525 (rlv_handler_t::isEnabled()) ? "disabled" : "enabled" );
526 LLNotifications::instance().add("GenericAlert", args);
527 #endif
528 }
529 // Checked: 2009-07-08 (RLVa-1.0.0e)
530 BOOL rlvDbgGetEnabled(void*)
531 {
532 return rlv_handler_t::isEnabled();
533 }
534#endif // RLV_ADVANCED_TOGGLE_RLVA
535
536// =========================================================================
537// Message sending functions
538//
539
540// Checked: 2009-08-11 (RLVa-1.0.1h) | Added: RLVa-1.0.1h
541void rlvForceDetach(LLViewerJointAttachment* pAttachPt)
542{
543 // Copy/paste from handle_detach_from_avatar()
544 LLViewerObject* attached_object = pAttachPt->getObject();
545 if (attached_object)
546 {
547 gMessageSystem->newMessage("ObjectDetach");
548 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
549 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
550 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
551
552 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
553 gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, attached_object->getLocalID());
554 gMessageSystem->sendReliable( gAgent.getRegionHost() );
555 }
556}
557
558void rlvSendBusyMessage(const LLUUID& idTo, const std::string& strMsg, const LLUUID& idSession)
559{
560 // (See process_improved_im)
561 std::string strFullName;
562 gAgent.buildFullname(strFullName);
563
564 pack_instant_message(gMessageSystem, gAgent.getID(), FALSE, gAgent.getSessionID(), idTo, strFullName,
565 strMsg, IM_ONLINE, IM_BUSY_AUTO_RESPONSE, idSession);
566 gAgent.sendReliableMessage();
567}
568
569// Checked: 2009-08-05 (RLVa-1.0.1e) | Modified: RLVa-1.0.1e
570bool rlvSendChatReply(S32 nChannel, const std::string& strReply)
571{
572 if (!rlvIsValidChannel(nChannel))
573 return false;
574
575 // Copy/paste from send_chat_from_viewer()
576 LLMessageSystem* msg = gMessageSystem;
577 msg->newMessageFast(_PREHASH_ChatFromViewer);
578 msg->nextBlockFast(_PREHASH_AgentData);
579 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
580 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
581 msg->nextBlockFast(_PREHASH_ChatData);
582 msg->addStringFast(_PREHASH_Message, strReply);
583 msg->addU8Fast(_PREHASH_Type, CHAT_TYPE_SHOUT);
584 msg->addS32("Channel", nChannel);
585 gAgent.sendReliableMessage();
586 LLViewerStats::getInstance()->incStat(LLViewerStats::ST_CHAT_COUNT);
587
588 return true;
589}
590
591// =========================================================================
592// String helper functions
593//
594
595// Checked: 2009-07-04 (RLVa-1.0.0a)
596void rlvStringReplace(std::string& strText, std::string strFrom, const std::string& strTo)
597{
598 if (strFrom.empty())
599 return;
600
601 size_t lenFrom = strFrom.length();
602 size_t lenTo = strTo.length();
603
604 std::string strTemp(strText);
605 LLStringUtil::toLower(strTemp);
606 LLStringUtil::toLower(strFrom);
607
608 std::string::size_type idxCur, idxStart = 0, idxOffset = 0;
609 while ( (idxCur = strTemp.find(strFrom, idxStart)) != std::string::npos)
610 {
611 strText.replace(idxCur + idxOffset, lenFrom, strTo);
612 idxStart = idxCur + lenFrom;
613 idxOffset += lenTo - lenFrom;
614 }
615}
616
617// Checked: 2009-07-29 (RLVa-1.0.1b) | Added: RLVa-1.0.1b
618std::string rlvGetFirstParenthesisedText(const std::string& strText, std::string::size_type* pidxMatch /*=NULL*/)
619{
620 if (pidxMatch)
621 *pidxMatch = std::string::npos; // Assume we won't find anything
622
623 std::string::size_type idxIt, idxStart; int cntLevel = 1;
624 if ((idxStart = strText.find_first_of('(')) == std::string::npos)
625 return std::string();
626
627 const char* pstrText = strText.c_str(); idxIt = idxStart;
628 while ( (cntLevel > 0) && (idxIt < strText.length()) )
629 {
630 if ('(' == pstrText[++idxIt])
631 cntLevel++;
632 else if (')' == pstrText[idxIt])
633 cntLevel--;
634 }
635
636 if (idxIt < strText.length())
637 {
638 if (pidxMatch)
639 *pidxMatch = idxStart; // Return the character index of the starting '('
640 return strText.substr(idxStart + 1, idxIt - idxStart - 1);
641 }
642 return std::string();
643}
644
645// Checked: 2009-07-29 (RLVa-1.0.1b) | Added: RLVa-1.0.1b
646std::string rlvGetLastParenthesisedText(const std::string& strText, std::string::size_type* pidxStart /*=NULL*/)
647{
648 if (pidxStart)
649 *pidxStart = std::string::npos; // Assume we won't find anything
650
651 // Extracts the last - matched - parenthesised text from the input string
652 std::string::size_type idxIt, idxEnd; int cntLevel = 1;
653 if ((idxEnd = strText.find_last_of(')')) == std::string::npos)
654 return std::string();
655
656 const char* pstrText = strText.c_str(); idxIt = idxEnd;
657 while ( (cntLevel > 0) && (idxIt >= 0) )
658 {
659 if (')' == pstrText[--idxIt])
660 cntLevel++;
661 else if ('(' == pstrText[idxIt])
662 cntLevel--;
663 }
664
665 if ( (idxIt >= 0) && (idxIt < strText.length()) ) // NOTE: allow for std::string::size_type to be signed or unsigned
666 {
667 if (pidxStart)
668 *pidxStart = idxIt; // Return the character index of the starting '('
669 return strText.substr(idxIt + 1, idxEnd - idxIt - 1);
670 }
671 return std::string();
672}
673
674// =========================================================================