PageRenderTime 533ms CodeModel.GetById 130ms app.highlight 277ms RepoModel.GetById 116ms app.codeStats 0ms

/indra/newview/llfloaterreporter.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 877 lines | 625 code | 135 blank | 117 comment | 60 complexity | 603759ec8d22072e3c980d088e9e934f MD5 | raw file
  1/** 
  2 * @file llfloaterreporter.cpp
  3 * @brief Abuse reports.
  4 *
  5 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "llviewerprecompiledheaders.h"
 28
 29// self include
 30#include "llfloaterreporter.h"
 31
 32#include <sstream>
 33
 34// linden library includes
 35#include "llassetstorage.h"
 36#include "llavatarnamecache.h"
 37#include "llcachename.h"
 38#include "llfontgl.h"
 39#include "llimagej2c.h"
 40#include "llinventory.h"
 41#include "llnotificationsutil.h"
 42#include "llstring.h"
 43#include "llsys.h"
 44#include "llvfile.h"
 45#include "llvfs.h"
 46#include "mean_collision_data.h"
 47#include "message.h"
 48#include "v3math.h"
 49
 50// viewer project includes
 51#include "llagent.h"
 52#include "llbutton.h"
 53#include "llfloaterreg.h"
 54#include "lltexturectrl.h"
 55#include "llscrolllistctrl.h"
 56#include "lldispatcher.h"
 57#include "llviewerobject.h"
 58#include "llviewerregion.h"
 59#include "llcombobox.h"
 60#include "lltooldraganddrop.h"
 61#include "lluiconstants.h"
 62#include "lluploaddialog.h"
 63#include "llcallingcard.h"
 64#include "llviewerobjectlist.h"
 65#include "lltoolobjpicker.h"
 66#include "lltoolmgr.h"
 67#include "llresourcedata.h"		// for LLResourceData
 68#include "llslurl.h"
 69#include "llviewerwindow.h"
 70#include "llviewertexturelist.h"
 71#include "llworldmap.h"
 72#include "llfilepicker.h"
 73#include "llfloateravatarpicker.h"
 74#include "lldir.h"
 75#include "llselectmgr.h"
 76#include "llversioninfo.h"
 77#include "lluictrlfactory.h"
 78#include "llviewernetwork.h"
 79
 80#include "llassetuploadresponders.h"
 81#include "llagentui.h"
 82
 83#include "lltrans.h"
 84
 85const U32 INCLUDE_SCREENSHOT  = 0x01 << 0;
 86
 87//-----------------------------------------------------------------------------
 88// Globals
 89//-----------------------------------------------------------------------------
 90
 91//-----------------------------------------------------------------------------
 92// Member functions
 93//-----------------------------------------------------------------------------
 94								 
 95LLFloaterReporter::LLFloaterReporter(const LLSD& key)
 96:	LLFloater(key),
 97	mReportType(COMPLAINT_REPORT),
 98	mObjectID(),
 99	mScreenID(),
100	mAbuserID(),
101	mOwnerName(),
102	mDeselectOnClose( FALSE ),
103	mPicking( FALSE), 
104	mPosition(),
105	mCopyrightWarningSeen( FALSE ),
106	mResourceDatap(new LLResourceData())
107{
108}
109
110// static
111void LLFloaterReporter::processRegionInfo(LLMessageSystem* msg)
112{
113	U32 region_flags;
114	msg->getU32("RegionInfo", "RegionFlags", region_flags);
115	
116	if ( LLFloaterReg::instanceVisible("reporter") )
117	{
118		LLNotificationsUtil::add("HelpReportAbuseEmailLL");
119	};
120}
121// virtual
122BOOL LLFloaterReporter::postBuild()
123{
124	LLSLURL slurl;
125	LLAgentUI::buildSLURL(slurl);
126	getChild<LLUICtrl>("abuse_location_edit")->setValue(slurl.getSLURLString());
127
128	enableControls(TRUE);
129
130	// convert the position to a string
131	LLVector3d pos = gAgent.getPositionGlobal();
132	LLViewerRegion *regionp = gAgent.getRegion();
133	if (regionp)
134	{
135		getChild<LLUICtrl>("sim_field")->setValue(regionp->getName());
136		pos -= regionp->getOriginGlobal();
137	}
138	setPosBox(pos);
139
140	// Take a screenshot, but don't draw this floater.
141	setVisible(FALSE);
142	takeScreenshot();
143	setVisible(TRUE);
144
145	// Default text to be blank
146	getChild<LLUICtrl>("object_name")->setValue(LLStringUtil::null);
147	getChild<LLUICtrl>("owner_name")->setValue(LLStringUtil::null);
148	mOwnerName = LLStringUtil::null;
149
150	getChild<LLUICtrl>("summary_edit")->setFocus(TRUE);
151
152	mDefaultSummary = getChild<LLUICtrl>("details_edit")->getValue().asString();
153
154	// send a message and ask for information about this region - 
155	// result comes back in processRegionInfo(..)
156	LLMessageSystem* msg = gMessageSystem;
157	msg->newMessage("RequestRegionInfo");
158	msg->nextBlock("AgentData");
159	msg->addUUID("AgentID", gAgent.getID());
160	msg->addUUID("SessionID", gAgent.getSessionID());
161	gAgent.sendReliableMessage();
162	
163	
164	// abuser name is selected from a list
165	LLUICtrl* le = getChild<LLUICtrl>("abuser_name_edit");
166	le->setEnabled( false );
167
168	setPosBox((LLVector3d)mPosition.getValue());
169	LLButton* pick_btn = getChild<LLButton>("pick_btn");
170	pick_btn->setImages(std::string("tool_face.tga"),
171						std::string("tool_face_active.tga") );
172	childSetAction("pick_btn", onClickObjPicker, this);
173
174	childSetAction("select_abuser", boost::bind(&LLFloaterReporter::onClickSelectAbuser, this));
175
176	childSetAction("send_btn", onClickSend, this);
177	childSetAction("cancel_btn", onClickCancel, this);
178	
179	// grab the user's name
180	std::string reporter = LLSLURL("agent", gAgent.getID(), "inspect").getSLURLString();
181	getChild<LLUICtrl>("reporter_field")->setValue(reporter);
182	
183	center();
184
185	return TRUE;
186}
187// virtual
188LLFloaterReporter::~LLFloaterReporter()
189{
190	// child views automatically deleted
191	mObjectID 		= LLUUID::null;
192
193	if (mPicking)
194	{
195		closePickTool(this);
196	}
197
198	mPosition.setVec(0.0f, 0.0f, 0.0f);
199
200	std::for_each(mMCDList.begin(), mMCDList.end(), DeletePointer() );
201	mMCDList.clear();
202
203	delete mResourceDatap;
204}
205
206// virtual
207void LLFloaterReporter::draw()
208{
209	getChildView("screen_check")->setEnabled(TRUE );
210
211	LLFloater::draw();
212}
213
214void LLFloaterReporter::enableControls(BOOL enable)
215{
216	getChildView("category_combo")->setEnabled(enable);
217	getChildView("chat_check")->setEnabled(enable);
218	getChildView("screen_check")->setEnabled(enable);
219	getChildView("screenshot")->setEnabled(FALSE);
220	getChildView("pick_btn")->setEnabled(enable);
221	getChildView("summary_edit")->setEnabled(enable);
222	getChildView("details_edit")->setEnabled(enable);
223	getChildView("send_btn")->setEnabled(enable);
224	getChildView("cancel_btn")->setEnabled(enable);
225}
226
227void LLFloaterReporter::getObjectInfo(const LLUUID& object_id)
228{
229	// TODO -- 
230	// 1 need to send to correct simulator if object is not 
231	//   in same simulator as agent
232	// 2 display info in widget window that gives feedback that
233	//   we have recorded the object info
234	// 3 can pick avatar ==> might want to indicate when a picked 
235	//   object is an avatar, attachment, or other category
236
237	mObjectID = object_id;
238
239	if (LLUUID::null != mObjectID)
240	{
241		// get object info for the user's benefit
242		LLViewerObject* objectp = NULL;
243		objectp = gObjectList.findObject( mObjectID );
244		if (objectp)
245		{
246			if ( objectp->isAttachment() )
247			{
248				objectp = (LLViewerObject*)objectp->getRoot();
249				mObjectID = objectp->getID();
250			}
251
252			// correct the region and position information
253			LLViewerRegion *regionp = objectp->getRegion();
254			if (regionp)
255			{
256				getChild<LLUICtrl>("sim_field")->setValue(regionp->getName());
257				LLVector3d global_pos;
258				global_pos.setVec(objectp->getPositionRegion());
259				setPosBox(global_pos);
260			}
261	
262			if (objectp->isAvatar())
263			{
264				setFromAvatarID(mObjectID);
265			}
266			else
267			{
268				// we have to query the simulator for information 
269				// about this object
270				LLMessageSystem* msg = gMessageSystem;
271				U32 request_flags = COMPLAINT_REPORT_REQUEST;
272				msg->newMessageFast(_PREHASH_RequestObjectPropertiesFamily);
273				msg->nextBlockFast(_PREHASH_AgentData);
274				msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
275				msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
276				msg->nextBlockFast(_PREHASH_ObjectData);
277				msg->addU32Fast(_PREHASH_RequestFlags, request_flags );
278				msg->addUUIDFast(_PREHASH_ObjectID, 	mObjectID);
279				LLViewerRegion* regionp = objectp->getRegion();
280				msg->sendReliable( regionp->getHost() );
281			}
282		}
283	}
284}
285
286void LLFloaterReporter::onClickSelectAbuser()
287{
288	gFloaterView->getParentFloater(this)->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLFloaterReporter::callbackAvatarID, this, _1, _2), FALSE, TRUE ));
289}
290
291void LLFloaterReporter::callbackAvatarID(const uuid_vec_t& ids, const std::vector<LLAvatarName> names)
292{
293	if (ids.empty() || names.empty()) return;
294
295	getChild<LLUICtrl>("abuser_name_edit")->setValue(names[0].getCompleteName());
296
297	mAbuserID = ids[0];
298
299	refresh();
300
301}
302
303void LLFloaterReporter::setFromAvatarID(const LLUUID& avatar_id)
304{
305	mAbuserID = mObjectID = avatar_id;
306	std::string avatar_link = LLSLURL("agent", mObjectID, "inspect").getSLURLString();
307	getChild<LLUICtrl>("owner_name")->setValue(avatar_link);
308
309	LLAvatarNameCache::get(avatar_id, boost::bind(&LLFloaterReporter::onAvatarNameCache, this, _1, _2));
310}
311
312void LLFloaterReporter::onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name)
313{
314	if (mObjectID == avatar_id)
315	{
316		mOwnerName = av_name.getCompleteName();
317		getChild<LLUICtrl>("object_name")->setValue(av_name.getCompleteName());
318		getChild<LLUICtrl>("object_name")->setToolTip(av_name.getCompleteName());
319		getChild<LLUICtrl>("abuser_name_edit")->setValue(av_name.getCompleteName());
320	}
321}
322
323
324// static
325void LLFloaterReporter::onClickSend(void *userdata)
326{
327	LLFloaterReporter *self = (LLFloaterReporter *)userdata;
328	
329	if (self->mPicking)
330	{
331		closePickTool(self);
332	}
333
334	if(self->validateReport())
335	{
336
337			const int IP_CONTENT_REMOVAL = 66;
338			const int IP_PERMISSONS_EXPLOIT = 37;
339			LLComboBox* combo = self->getChild<LLComboBox>( "category_combo");
340			int category_value = combo->getSelectedValue().asInteger(); 
341
342			if ( ! self->mCopyrightWarningSeen )
343			{
344
345				std::string details_lc = self->getChild<LLUICtrl>("details_edit")->getValue().asString();
346				LLStringUtil::toLower( details_lc );
347				std::string summary_lc = self->getChild<LLUICtrl>("summary_edit")->getValue().asString();
348				LLStringUtil::toLower( summary_lc );
349				if ( details_lc.find( "copyright" ) != std::string::npos ||
350					summary_lc.find( "copyright" ) != std::string::npos  ||
351					category_value == IP_CONTENT_REMOVAL ||
352					category_value == IP_PERMISSONS_EXPLOIT)
353				{
354					LLNotificationsUtil::add("HelpReportAbuseContainsCopyright");
355					self->mCopyrightWarningSeen = TRUE;
356					return;
357				}
358			}
359			else if (category_value == IP_CONTENT_REMOVAL)
360			{
361				// IP_CONTENT_REMOVAL *always* shows the dialog - 
362				// ergo you can never send that abuse report type.
363				LLNotificationsUtil::add("HelpReportAbuseContainsCopyright");
364				return;
365			}
366
367		LLUploadDialog::modalUploadDialog(LLTrans::getString("uploading_abuse_report"));
368		// *TODO don't upload image if checkbox isn't checked
369		std::string url = gAgent.getRegion()->getCapability("SendUserReport");
370		std::string sshot_url = gAgent.getRegion()->getCapability("SendUserReportWithScreenshot");
371		if(!url.empty() || !sshot_url.empty())
372		{
373			self->sendReportViaCaps(url, sshot_url, self->gatherReport());
374			self->closeFloater();
375		}
376		else
377		{
378			if(self->getChild<LLUICtrl>("screen_check")->getValue())
379			{
380				self->getChildView("send_btn")->setEnabled(FALSE);
381				self->getChildView("cancel_btn")->setEnabled(FALSE);
382				// the callback from uploading the image calls sendReportViaLegacy()
383				self->uploadImage();
384			}
385			else
386			{
387				self->sendReportViaLegacy(self->gatherReport());
388				LLUploadDialog::modalUploadFinished();
389				self->closeFloater();
390			}
391		}
392	}
393}
394
395
396// static
397void LLFloaterReporter::onClickCancel(void *userdata)
398{
399	LLFloaterReporter *self = (LLFloaterReporter *)userdata;
400
401	// reset flag in case the next report also contains this text
402	self->mCopyrightWarningSeen = FALSE;
403
404	if (self->mPicking)
405	{
406		closePickTool(self);
407	}
408	self->closeFloater();
409}
410
411
412// static 
413void LLFloaterReporter::onClickObjPicker(void *userdata)
414{
415	LLFloaterReporter *self = (LLFloaterReporter *)userdata;
416	LLToolObjPicker::getInstance()->setExitCallback(LLFloaterReporter::closePickTool, self);
417	LLToolMgr::getInstance()->setTransientTool(LLToolObjPicker::getInstance());
418	self->mPicking = TRUE;
419	self->getChild<LLUICtrl>("object_name")->setValue(LLStringUtil::null);
420	self->getChild<LLUICtrl>("owner_name")->setValue(LLStringUtil::null);
421	self->mOwnerName = LLStringUtil::null;
422	LLButton* pick_btn = self->getChild<LLButton>("pick_btn");
423	if (pick_btn) pick_btn->setToggleState(TRUE);
424}
425
426
427// static
428void LLFloaterReporter::closePickTool(void *userdata)
429{
430	LLFloaterReporter *self = (LLFloaterReporter *)userdata;
431
432	LLUUID object_id = LLToolObjPicker::getInstance()->getObjectID();
433	self->getObjectInfo(object_id);
434
435	LLToolMgr::getInstance()->clearTransientTool();
436	self->mPicking = FALSE;
437	LLButton* pick_btn = self->getChild<LLButton>("pick_btn");
438	if (pick_btn) pick_btn->setToggleState(FALSE);
439}
440
441
442// static
443void LLFloaterReporter::showFromMenu(EReportType report_type)
444{
445	if (COMPLAINT_REPORT != report_type)
446	{
447		llwarns << "Unknown LLViewerReporter type : " << report_type << llendl;
448		return;
449	}
450	
451	LLFloaterReporter* f = LLFloaterReg::showTypedInstance<LLFloaterReporter>("reporter", LLSD());
452	if (f)
453	{
454		f->setReportType(report_type);
455	}
456}
457
458// static
459void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_name)
460{
461	LLFloaterReporter* f = LLFloaterReg::showTypedInstance<LLFloaterReporter>("reporter");
462
463	if (avatar_name.empty())
464	{
465		// Request info for this object
466		f->getObjectInfo(object_id);
467	}
468	else
469	{
470		f->setFromAvatarID(object_id);
471	}
472
473	// Need to deselect on close
474	f->mDeselectOnClose = TRUE;
475
476	f->openFloater();
477}
478
479
480// static
481void LLFloaterReporter::showFromObject(const LLUUID& object_id)
482{
483	show(object_id);
484}
485
486// static
487void LLFloaterReporter::showFromAvatar(const LLUUID& avatar_id, const std::string avatar_name)
488{
489	show(avatar_id, avatar_name);
490}
491
492void LLFloaterReporter::setPickedObjectProperties(const std::string& object_name, const std::string& owner_name, const LLUUID owner_id)
493{
494	getChild<LLUICtrl>("object_name")->setValue(object_name);
495	std::string owner_link =
496		LLSLURL("agent", owner_id, "inspect").getSLURLString();
497	getChild<LLUICtrl>("owner_name")->setValue(owner_link);
498	getChild<LLUICtrl>("abuser_name_edit")->setValue(owner_name);
499	mAbuserID = owner_id;
500	mOwnerName = owner_name;
501}
502
503
504bool LLFloaterReporter::validateReport()
505{
506	// Ensure user selected a category from the list
507	LLSD category_sd = getChild<LLUICtrl>("category_combo")->getValue();
508	U8 category = (U8)category_sd.asInteger();
509	if (category == 0)
510	{
511		LLNotificationsUtil::add("HelpReportAbuseSelectCategory");
512		return false;
513	}
514
515
516	if ( getChild<LLUICtrl>("abuser_name_edit")->getValue().asString().empty() )
517	{
518		LLNotificationsUtil::add("HelpReportAbuseAbuserNameEmpty");
519		return false;
520	};
521
522	if ( getChild<LLUICtrl>("abuse_location_edit")->getValue().asString().empty() )
523	{
524		LLNotificationsUtil::add("HelpReportAbuseAbuserLocationEmpty");
525		return false;
526	};
527
528	if ( getChild<LLUICtrl>("abuse_location_edit")->getValue().asString().empty() )
529	{
530		LLNotificationsUtil::add("HelpReportAbuseAbuserLocationEmpty");
531		return false;
532	};
533
534
535	if ( getChild<LLUICtrl>("summary_edit")->getValue().asString().empty() )
536	{
537		LLNotificationsUtil::add("HelpReportAbuseSummaryEmpty");
538		return false;
539	};
540
541	if ( getChild<LLUICtrl>("details_edit")->getValue().asString() == mDefaultSummary )
542	{
543		LLNotificationsUtil::add("HelpReportAbuseDetailsEmpty");
544		return false;
545	};
546	return true;
547}
548
549LLSD LLFloaterReporter::gatherReport()
550{	
551	LLViewerRegion *regionp = gAgent.getRegion();
552	if (!regionp) return LLSD(); // *TODO handle this failure case more gracefully
553
554	// reset flag in case the next report also contains this text
555	mCopyrightWarningSeen = FALSE;
556
557	std::ostringstream summary;
558	if (!LLGridManager::getInstance()->isInProductionGrid())
559	{
560		summary << "Preview ";
561	}
562
563	std::string category_name;
564	LLComboBox* combo = getChild<LLComboBox>( "category_combo");
565	if (combo)
566	{
567		category_name = combo->getSelectedItemLabel(); // want label, not value
568	}
569
570#if LL_WINDOWS
571	const char* platform = "Win";
572#elif LL_DARWIN
573	const char* platform = "Mac";
574#elif LL_LINUX
575	const char* platform = "Lnx";
576#elif LL_SOLARIS
577	const char* platform = "Sol";
578	const char* short_platform = "O:S";
579#else
580	const char* platform = "???";
581#endif
582
583
584
585	summary << ""
586		<< " |" << regionp->getName() << "|"								// region reporter is currently in.
587		<< " (" << getChild<LLUICtrl>("abuse_location_edit")->getValue().asString() << ")"				// region abuse occured in (freeform text - no LLRegionPicker tool)
588		<< " [" << category_name << "] "									// updated category
589		<< " {" << getChild<LLUICtrl>("abuser_name_edit")->getValue().asString() << "} "					// name of abuse entered in report (chosen using LLAvatarPicker)
590		<< " \"" << getChild<LLUICtrl>("summary_edit")->getValue().asString() << "\"";		// summary as entered
591
592
593	std::ostringstream details;
594
595	details << "V" << LLVersionInfo::getVersion() << std::endl << std::endl;	// client version moved to body of email for abuse reports
596
597	std::string object_name = getChild<LLUICtrl>("object_name")->getValue().asString();
598	if (!object_name.empty() && !mOwnerName.empty())
599	{
600		details << "Object: " << object_name << "\n";
601		details << "Owner: " << mOwnerName << "\n";
602	}
603
604
605	details << "Abuser name: " << getChild<LLUICtrl>("abuser_name_edit")->getValue().asString() << " \n";
606	details << "Abuser location: " << getChild<LLUICtrl>("abuse_location_edit")->getValue().asString() << " \n";
607
608	details << getChild<LLUICtrl>("details_edit")->getValue().asString();
609
610	std::string version_string;
611	version_string = llformat(
612			"%s %s %s %s %s",
613			LLVersionInfo::getShortVersion().c_str(),
614			platform,
615			gSysCPU.getFamily().c_str(),
616			gGLManager.mGLRenderer.c_str(),
617			gGLManager.mDriverVersionVendorString.c_str());
618
619	// only send a screenshot ID if we're asked to and the email is 
620	// going to LL - Estate Owners cannot see the screenshot asset
621	LLUUID screenshot_id = LLUUID::null;
622	if (getChild<LLUICtrl>("screen_check")->getValue())
623	{
624		screenshot_id = getChild<LLUICtrl>("screenshot")->getValue();
625	};
626
627	LLSD report = LLSD::emptyMap();
628	report["report-type"] = (U8) mReportType;
629	report["category"] = getChild<LLUICtrl>("category_combo")->getValue();
630	report["position"] = mPosition.getValue();
631	report["check-flags"] = (U8)0; // this is not used
632	report["screenshot-id"] = screenshot_id;
633	report["object-id"] = mObjectID;
634	report["abuser-id"] = mAbuserID;
635	report["abuse-region-name"] = "";
636	report["abuse-region-id"] = LLUUID::null;
637	report["summary"] = summary.str();
638	report["version-string"] = version_string;
639	report["details"] = details.str();
640	return report;
641}
642
643void LLFloaterReporter::sendReportViaLegacy(const LLSD & report)
644{
645	LLViewerRegion *regionp = gAgent.getRegion();
646	if (!regionp) return;
647	LLMessageSystem *msg = gMessageSystem;
648	msg->newMessageFast(_PREHASH_UserReport);
649	msg->nextBlockFast(_PREHASH_AgentData);
650	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
651	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
652	
653	msg->nextBlockFast(_PREHASH_ReportData);
654	msg->addU8Fast(_PREHASH_ReportType, report["report-type"].asInteger());
655	msg->addU8(_PREHASH_Category, report["category"].asInteger());
656	msg->addVector3Fast(_PREHASH_Position, 	LLVector3(report["position"]));
657	msg->addU8Fast(_PREHASH_CheckFlags, report["check-flags"].asInteger());
658	msg->addUUIDFast(_PREHASH_ScreenshotID, report["screenshot-id"].asUUID());
659	msg->addUUIDFast(_PREHASH_ObjectID, report["object-id"].asUUID());
660	msg->addUUID("AbuserID", report["abuser-id"].asUUID());
661	msg->addString("AbuseRegionName", report["abuse-region-name"].asString());
662	msg->addUUID("AbuseRegionID", report["abuse-region-id"].asUUID());
663
664	msg->addStringFast(_PREHASH_Summary, report["summary"].asString());
665	msg->addString("VersionString", report["version-string"]);
666	msg->addStringFast(_PREHASH_Details, report["details"] );
667	
668	msg->sendReliable(regionp->getHost());
669}
670
671class LLUserReportScreenshotResponder : public LLAssetUploadResponder
672{
673public:
674	LLUserReportScreenshotResponder(const LLSD & post_data, 
675									const LLUUID & vfile_id, 
676									LLAssetType::EType asset_type):
677	  LLAssetUploadResponder(post_data, vfile_id, asset_type)
678	{
679	}
680	void uploadFailed(const LLSD& content)
681	{
682		// *TODO pop up a dialog so the user knows their report screenshot didn't make it
683		LLUploadDialog::modalUploadFinished();
684	}
685	void uploadComplete(const LLSD& content)
686	{
687		// we don't care about what the server returns from this post, just clean up the UI
688		LLUploadDialog::modalUploadFinished();
689	}
690};
691
692class LLUserReportResponder : public LLHTTPClient::Responder
693{
694public:
695	LLUserReportResponder(): LLHTTPClient::Responder()  {}
696
697	void error(U32 status, const std::string& reason)
698	{
699		// *TODO do some user messaging here
700		LLUploadDialog::modalUploadFinished();
701	}
702	void result(const LLSD& content)
703	{
704		// we don't care about what the server returns
705		LLUploadDialog::modalUploadFinished();
706	}
707};
708
709void LLFloaterReporter::sendReportViaCaps(std::string url, std::string sshot_url, const LLSD& report)
710{
711	if(getChild<LLUICtrl>("screen_check")->getValue().asBoolean() && !sshot_url.empty())
712	{
713		// try to upload screenshot
714		LLHTTPClient::post(sshot_url, report, new LLUserReportScreenshotResponder(report, 
715															mResourceDatap->mAssetInfo.mUuid, 
716															mResourceDatap->mAssetInfo.mType));			
717	}
718	else
719	{
720		// screenshot not wanted or we don't have screenshot cap
721		LLHTTPClient::post(url, report, new LLUserReportResponder());			
722	}
723}
724
725void LLFloaterReporter::takeScreenshot()
726{
727	const S32 IMAGE_WIDTH = 1024;
728	const S32 IMAGE_HEIGHT = 768;
729
730	LLPointer<LLImageRaw> raw = new LLImageRaw;
731	if( !gViewerWindow->rawSnapshot(raw, IMAGE_WIDTH, IMAGE_HEIGHT, TRUE, FALSE, TRUE, FALSE))
732	{
733		llwarns << "Unable to take screenshot" << llendl;
734		return;
735	}
736	LLPointer<LLImageJ2C> upload_data = LLViewerTextureList::convertToUploadFile(raw);
737
738	// create a resource data
739	mResourceDatap->mInventoryType = LLInventoryType::IT_NONE;
740	mResourceDatap->mNextOwnerPerm = 0; // not used
741	mResourceDatap->mExpectedUploadCost = 0; // we expect that abuse screenshots are free
742	mResourceDatap->mAssetInfo.mTransactionID.generate();
743	mResourceDatap->mAssetInfo.mUuid = mResourceDatap->mAssetInfo.mTransactionID.makeAssetID(gAgent.getSecureSessionID());
744
745	if (COMPLAINT_REPORT == mReportType)
746	{
747		mResourceDatap->mAssetInfo.mType = LLAssetType::AT_TEXTURE;
748		mResourceDatap->mPreferredLocation = LLFolderType::EType(LLResourceData::INVALID_LOCATION);
749	}
750	else
751	{
752		llwarns << "Unknown LLFloaterReporter type" << llendl;
753	}
754	mResourceDatap->mAssetInfo.mCreatorID = gAgentID;
755	mResourceDatap->mAssetInfo.setName("screenshot_name");
756	mResourceDatap->mAssetInfo.setDescription("screenshot_descr");
757
758	// store in VFS
759	LLVFile::writeFile(upload_data->getData(), 
760						upload_data->getDataSize(), 
761						gVFS, 
762						mResourceDatap->mAssetInfo.mUuid, 
763						mResourceDatap->mAssetInfo.mType);
764
765	// store in the image list so it doesn't try to fetch from the server
766	LLPointer<LLViewerFetchedTexture> image_in_list = 
767		LLViewerTextureManager::getFetchedTexture(mResourceDatap->mAssetInfo.mUuid, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::FETCHED_TEXTURE);
768	image_in_list->createGLTexture(0, raw, 0, TRUE, LLViewerTexture::OTHER);
769	
770	// the texture picker then uses that texture
771	LLTexturePicker* texture = getChild<LLTextureCtrl>("screenshot");
772	if (texture)
773	{
774		texture->setImageAssetID(mResourceDatap->mAssetInfo.mUuid);
775		texture->setDefaultImageAssetID(mResourceDatap->mAssetInfo.mUuid);
776		texture->setCaption(getString("Screenshot"));
777	}
778
779}
780
781void LLFloaterReporter::uploadImage()
782{
783	llinfos << "*** Uploading: " << llendl;
784	llinfos << "Type: " << LLAssetType::lookup(mResourceDatap->mAssetInfo.mType) << llendl;
785	llinfos << "UUID: " << mResourceDatap->mAssetInfo.mUuid << llendl;
786	llinfos << "Name: " << mResourceDatap->mAssetInfo.getName() << llendl;
787	llinfos << "Desc: " << mResourceDatap->mAssetInfo.getDescription() << llendl;
788
789	gAssetStorage->storeAssetData(mResourceDatap->mAssetInfo.mTransactionID,
790									mResourceDatap->mAssetInfo.mType,
791									LLFloaterReporter::uploadDoneCallback,
792									(void*)mResourceDatap, TRUE);
793}
794
795
796// static
797void LLFloaterReporter::uploadDoneCallback(const LLUUID &uuid, void *user_data, S32 result, LLExtStat ext_status) // StoreAssetData callback (fixed)
798{
799	LLUploadDialog::modalUploadFinished();
800
801	LLResourceData* data = (LLResourceData*)user_data;
802
803	if(result < 0)
804	{
805		LLSD args;
806		args["REASON"] = std::string(LLAssetStorage::getErrorString(result));
807		LLNotificationsUtil::add("ErrorUploadingReportScreenshot", args);
808
809		std::string err_msg("There was a problem uploading a report screenshot");
810		err_msg += " due to the following reason: " + args["REASON"].asString();
811		llwarns << err_msg << llendl;
812		return;
813	}
814
815	EReportType report_type = UNKNOWN_REPORT;
816	if (data->mPreferredLocation == LLResourceData::INVALID_LOCATION)
817	{
818		report_type = COMPLAINT_REPORT;
819	}
820	else 
821	{
822		llwarns << "Unknown report type : " << data->mPreferredLocation << llendl;
823	}
824
825	LLFloaterReporter *self = LLFloaterReg::findTypedInstance<LLFloaterReporter>("reporter");
826	if (self)
827	{
828		self->mScreenID = uuid;
829		llinfos << "Got screen shot " << uuid << llendl;
830		self->sendReportViaLegacy(self->gatherReport());
831		self->closeFloater();
832	}
833}
834
835
836void LLFloaterReporter::setPosBox(const LLVector3d &pos)
837{
838	mPosition.setVec(pos);
839	std::string pos_string = llformat("{%.1f, %.1f, %.1f}",
840		mPosition.mV[VX],
841		mPosition.mV[VY],
842		mPosition.mV[VZ]);
843	getChild<LLUICtrl>("pos_field")->setValue(pos_string);
844}
845
846// void LLFloaterReporter::setDescription(const std::string& description, LLMeanCollisionData *mcd)
847// {
848// 	LLFloaterReporter *self = LLFloaterReg::findTypedInstance<LLFloaterReporter>("reporter");
849// 	if (self)
850// 	{
851// 		self->getChild<LLUICtrl>("details_edit")->setValue(description);
852
853// 		for_each(self->mMCDList.begin(), self->mMCDList.end(), DeletePointer());
854// 		self->mMCDList.clear();
855// 		if (mcd)
856// 		{
857// 			self->mMCDList.push_back(new LLMeanCollisionData(mcd));
858// 		}
859// 	}
860// }
861
862// void LLFloaterReporter::addDescription(const std::string& description, LLMeanCollisionData *mcd)
863// {
864// 	LLFloaterReporter *self = LLFloaterReg::findTypedInstance<LLFloaterReporter>("reporter");
865// 	if (self)
866// 	{
867// 		LLTextEditor* text = self->getChild<LLTextEditor>("details_edit");
868// 		if (text)
869// 		{	
870// 			text->insertText(description);
871// 		}
872// 		if (mcd)
873// 		{
874// 			self->mMCDList.push_back(new LLMeanCollisionData(mcd));
875// 		}
876// 	}
877// }