svn merge svn+ssh://svn.lindenlab.com/svn/linden/release@59161 svn+ssh://svn.lindenlab.com/svn/linden/branches/release-candidate@59163 --> release

master
Josh Bell 2007-03-14 23:03:50 +00:00
parent cf40518428
commit 00dbacb215
35 changed files with 1598 additions and 1057 deletions

View File

@ -4,7 +4,7 @@ along with the issue identifier corresponding to the patches we've
received from them. To see more about these contributions, visit
http://jira.secondlife.com/ , and enter the issue identifier.
Alissa Sabre - VWR-81, VWR-86
Alissa Sabre - VWR-81, VWR-83
blino Nakamura - VWR-17
Drewan Keats - VWR-28
Dylan Haskell - VWR-72

View File

@ -97,6 +97,7 @@ const U32 DEFAULT_USER_SERVER_PORT = 12036;
const U32 DEFAULT_RPC_SERVER_PORT = 12037;
const U32 DEFAULT_LOG_DATA_SERVER_PORT = 12039;
const U32 DEFAULT_BACKBONE_PORT = 12040;
const U32 DEFAULT_CGI_SERVICES_PORT = 12045;
const U32 DEFAULT_LOCAL_ASSET_PORT = 12041;
//const U32 DEFAULT_BACKBONE_CAP_PORT = 12042; // Deprecated
const U32 DEFAULT_CAP_PROXY_PORT = 12043;

View File

@ -534,7 +534,7 @@ std::istream& fullread(std::istream& str, char *buf, std::streamsize requested)
std::istream& operator>>(std::istream& str, const char *tocheck)
{
char c;
char c = '\0';
const char *p;
p = tocheck;
while (*p && !str.bad())

View File

@ -13,273 +13,86 @@
#include "llapp.h"
#include "lluri.h"
#include "llsd.h"
#include <iomanip>
#include "../llmath/lluuid.h"
// uric = reserved | unreserved | escaped
// reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
// unreserved = alphanum | mark
// mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
// escaped = "%" hex hex
static const char* ESCAPED_CHARACTERS[256] =
// static
std::string LLURI::escape(const std::string& str, const std::string & allowed)
{
"%00", // 0
"%01", // 1
"%02", // 2
"%03", // 3
"%04", // 4
"%05", // 5
"%06", // 6
"%07", // 7
"%08", // 8
"%09", // 9
"%0a", // 10
"%0b", // 11
"%0c", // 12
"%0d", // 13
"%0e", // 14
"%0f", // 15
"%10", // 16
"%11", // 17
"%12", // 18
"%13", // 19
"%14", // 20
"%15", // 21
"%16", // 22
"%17", // 23
"%18", // 24
"%19", // 25
"%1a", // 26
"%1b", // 27
"%1c", // 28
"%1d", // 29
"%1e", // 30
"%1f", // 31
"%20", // 32
"!", // 33
"%22", // 34
"%23", // 35
"$", // 36
"%25", // 37
"&", // 38
"'", // 39
"(", // 40
")", // 41
"*", // 42
"+", // 43
",", // 44
"-", // 45
".", // 46
"/", // 47
"0", // 48
"1", // 49
"2", // 50
"3", // 51
"4", // 52
"5", // 53
"6", // 54
"7", // 55
"8", // 56
"9", // 57
":", // 58
";", // 59
"%3c", // 60
"=", // 61
"%3e", // 62
"?", // 63
"@", // 64
"A", // 65
"B", // 66
"C", // 67
"D", // 68
"E", // 69
"F", // 70
"G", // 71
"H", // 72
"I", // 73
"J", // 74
"K", // 75
"L", // 76
"M", // 77
"N", // 78
"O", // 79
"P", // 80
"Q", // 81
"R", // 82
"S", // 83
"T", // 84
"U", // 85
"V", // 86
"W", // 87
"X", // 88
"Y", // 89
"Z", // 90
"%5b", // 91
"%5c", // 92
"%5d", // 93
"%5e", // 94
"_", // 95
"%60", // 96
"a", // 97
"b", // 98
"c", // 99
"d", // 100
"e", // 101
"f", // 102
"g", // 103
"h", // 104
"i", // 105
"j", // 106
"k", // 107
"l", // 108
"m", // 109
"n", // 110
"o", // 111
"p", // 112
"q", // 113
"r", // 114
"s", // 115
"t", // 116
"u", // 117
"v", // 118
"w", // 119
"x", // 120
"y", // 121
"z", // 122
"%7b", // 123
"%7c", // 124
"%7d", // 125
"~", // 126
"%7f", // 127
"%80", // 128
"%81", // 129
"%82", // 130
"%83", // 131
"%84", // 132
"%85", // 133
"%86", // 134
"%87", // 135
"%88", // 136
"%89", // 137
"%8a", // 138
"%8b", // 139
"%8c", // 140
"%8d", // 141
"%8e", // 142
"%8f", // 143
"%90", // 144
"%91", // 145
"%92", // 146
"%93", // 147
"%94", // 148
"%95", // 149
"%96", // 150
"%97", // 151
"%98", // 152
"%99", // 153
"%9a", // 154
"%9b", // 155
"%9c", // 156
"%9d", // 157
"%9e", // 158
"%9f", // 159
"%a0", // 160
"%a1", // 161
"%a2", // 162
"%a3", // 163
"%a4", // 164
"%a5", // 165
"%a6", // 166
"%a7", // 167
"%a8", // 168
"%a9", // 169
"%aa", // 170
"%ab", // 171
"%ac", // 172
"%ad", // 173
"%ae", // 174
"%af", // 175
"%b0", // 176
"%b1", // 177
"%b2", // 178
"%b3", // 179
"%b4", // 180
"%b5", // 181
"%b6", // 182
"%b7", // 183
"%b8", // 184
"%b9", // 185
"%ba", // 186
"%bb", // 187
"%bc", // 188
"%bd", // 189
"%be", // 190
"%bf", // 191
"%c0", // 192
"%c1", // 193
"%c2", // 194
"%c3", // 195
"%c4", // 196
"%c5", // 197
"%c6", // 198
"%c7", // 199
"%c8", // 200
"%c9", // 201
"%ca", // 202
"%cb", // 203
"%cc", // 204
"%cd", // 205
"%ce", // 206
"%cf", // 207
"%d0", // 208
"%d1", // 209
"%d2", // 210
"%d3", // 211
"%d4", // 212
"%d5", // 213
"%d6", // 214
"%d7", // 215
"%d8", // 216
"%d9", // 217
"%da", // 218
"%db", // 219
"%dc", // 220
"%dd", // 221
"%de", // 222
"%df", // 223
"%e0", // 224
"%e1", // 225
"%e2", // 226
"%e3", // 227
"%e4", // 228
"%e5", // 229
"%e6", // 230
"%e7", // 231
"%e8", // 232
"%e9", // 233
"%ea", // 234
"%eb", // 235
"%ec", // 236
"%ed", // 237
"%ee", // 238
"%ef", // 239
"%f0", // 240
"%f1", // 241
"%f2", // 242
"%f3", // 243
"%f4", // 244
"%f5", // 245
"%f6", // 246
"%f7", // 247
"%f8", // 248
"%f9", // 249
"%fa", // 250
"%fb", // 251
"%fc", // 252
"%fd", // 253
"%fe", // 254
"%ff" // 255
};
std::ostringstream ostr;
std::string::const_iterator it = str.begin();
std::string::const_iterator end = str.end();
for(; it != end; ++it)
{
std::string::value_type c = *it;
if(allowed.find(c) == std::string::npos)
{
ostr << "%"
<< std::uppercase << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<U32>(c);
}
else
{
ostr << c;
}
}
return ostr.str();
}
// static
std::string LLURI::unescape(const std::string& str)
{
std::ostringstream ostr;
std::string::const_iterator it = str.begin();
std::string::const_iterator end = str.end();
for(; it != end; ++it)
{
if((*it) == '%')
{
++it;
if(it == end) break;
U8 c = hex_as_nybble(*it++);
c = c << 4;
if (it == end) break;
c |= hex_as_nybble(*it);
ostr.put((char)c);
}
else
{
ostr.put(*it);
}
}
return ostr.str();
}
namespace
{
const std::string unreserved()
{
static const std::string s =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
"0123456789"
"-._~";
return s;
}
const std::string sub_delims()
{
static const std::string s = "!$&'()*+,;=";
return s;
}
std::string escapeHostAndPort(const std::string& s)
{ return LLURI::escape(s, unreserved() + sub_delims() +":"); }
std::string escapePathComponent(const std::string& s)
{ return LLURI::escape(s, unreserved() + sub_delims() + ":@"); }
std::string escapeQueryVariable(const std::string& s)
{ return LLURI::escape(s, unreserved() + ":@!$'()*+,"); } // sub_delims - "&;=" + ":@"
std::string escapeQueryValue(const std::string& s)
{ return LLURI::escape(s, unreserved() + ":@!$'()*+,="); } // sub_delims - "&;" + ":@"
}
LLURI::LLURI()
{
@ -352,23 +165,23 @@ LLURI::~LLURI()
{
}
LLURI LLURI::buildHTTP(const std::string& host_port,
// static
LLURI LLURI::buildHTTP(const std::string& prefix,
const LLSD& path)
{
LLURI result;
// TODO: deal with '/' '?' '#' in host_port
if (host_port.find("://") != host_port.npos)
if (prefix.find("://") != prefix.npos)
{
// The scheme is part of the host_port
result.mScheme = "";
result.mEscapedAuthority = escape(host_port);
// it is a prefix
result = LLURI(prefix);
}
else
{
result.mScheme = "HTTP";
result.mEscapedAuthority = "//" + escape(host_port);
// it is just a host and optional port
result.mScheme = "http";
result.mEscapedAuthority = escapeHostAndPort(prefix);
}
if (path.isArray())
@ -379,20 +192,20 @@ LLURI LLURI::buildHTTP(const std::string& host_port,
++it)
{
lldebugs << "PATH: inserting " << it->asString() << llendl;
result.mEscapedPath += "/" + escape(it->asString());
result.mEscapedPath += "/" + escapePathComponent(it->asString());
}
}
result.mEscapedOpaque = result.mEscapedAuthority +
result.mEscapedOpaque = "//" + result.mEscapedAuthority +
result.mEscapedPath;
return result;
}
// static
LLURI LLURI::buildHTTP(const std::string& host_port,
LLURI LLURI::buildHTTP(const std::string& prefix,
const LLSD& path,
const LLSD& query)
{
LLURI result = buildHTTP(host_port, path);
LLURI result = buildHTTP(prefix, path);
// break out and escape each query component
if (query.isMap())
{
@ -400,8 +213,8 @@ LLURI LLURI::buildHTTP(const std::string& host_port,
it != query.endMap();
it++)
{
result.mEscapedQuery += escape(it->first) +
(it->second.isUndefined() ? "" : "=" + it->second.asString()) +
result.mEscapedQuery += escapeQueryVariable(it->first) +
(it->second.isUndefined() ? "" : "=" + escapeQueryValue(it->second.asString())) +
"&";
}
if (query.size() > 0)
@ -412,57 +225,63 @@ LLURI LLURI::buildHTTP(const std::string& host_port,
return result;
}
// static
LLURI LLURI::buildHTTP(const std::string& host,
const U32& port,
const LLSD& path)
{
return LLURI::buildHTTP(llformat("%s:%u", host.c_str(), port), path);
}
// static
LLURI LLURI::buildHTTP(const std::string& host,
const U32& port,
const LLSD& path,
const LLSD& query)
{
return LLURI::buildHTTP(llformat("%s:%u", host.c_str(), port), path, query);
}
namespace {
LLURI buildBackboneURL(LLApp* app,
const std::string& p1 = "",
const std::string& p2 = "",
const std::string& p3 = "")
{
std::string host = "localhost:12040";
if (app)
{
host = app->getOption("backbone-host-port").asString();
}
LLSD path = LLSD::emptyArray();
if (!p1.empty()) path.append(p1);
if (!p2.empty()) path.append(p2);
if (!p3.empty()) path.append(p3);
return LLURI::buildHTTP(host, path);
}
}
// static
LLURI LLURI::buildAgentPresenceURI(const LLUUID& agent_id, LLApp* app)
{
std::string host = "localhost:12040";
if (app)
{
host = app->getOption("backbone-host-port").asString();
}
LLSD path = LLSD::emptyArray();
path.append("agent");
path.append(agent_id);
path.append("presence");
return buildHTTP(host, path);
return buildBackboneURL(app, "agent", agent_id.asString(), "presence");
}
// static
LLURI LLURI::buildBulkAgentPresenceURI(LLApp* app)
{
std::string host = "localhost:12040";
if (app)
{
host = app->getOption("backbone-host-port").asString();
}
LLSD path = LLSD::emptyArray();
path.append("agent");
path.append("presence");
return buildHTTP(host, path);
return buildBackboneURL(app, "agent", "presence");
}
// static
LLURI LLURI::buildAgentSessionURI(const LLUUID& agent_id, LLApp* app)
{
std::string host = "localhost:12040";
if (app)
{
host = app->getOption("backbone-host-port").asString();
}
LLSD path = LLSD::emptyArray();
path.append("agent");
path.append(agent_id);
path.append("session");
return buildHTTP(host, path);
return buildBackboneURL(app, "agent", agent_id.asString(), "session");
}
// static
@ -635,43 +454,3 @@ LLSD LLURI::queryMap(std::string escaped_query_string)
return result;
}
// static
std::string LLURI::escape(const std::string& str)
{
std::ostringstream ostr;
std::string::const_iterator it = str.begin();
std::string::const_iterator end = str.end();
S32 c;
for(; it != end; ++it)
{
c = (S32)(*it);
ostr << ESCAPED_CHARACTERS[c];
}
return ostr.str();
}
// static
std::string LLURI::unescape(const std::string& str)
{
std::ostringstream ostr;
std::string::const_iterator it = str.begin();
std::string::const_iterator end = str.end();
for(; it != end; ++it)
{
if((*it) == '%')
{
++it;
if(it == end) break;
U8 c = hex_as_nybble(*it++);
c = c << 4;
if (it == end) break;
c |= hex_as_nybble(*it);
ostr.put((char)c);
}
else
{
ostr.put(*it);
}
}
return ostr.str();
}

View File

@ -26,42 +26,55 @@ class LLApp;
class LLURI
{
public:
LLURI();
LLURI(const std::string& escaped_str);
// construct from escaped string, as would be transmitted on the net
LLURI();
LLURI(const std::string& escaped_str);
// construct from escaped string, as would be transmitted on the net
~LLURI();
~LLURI();
static LLURI buildHTTP(const std::string& host_port,
const LLSD& path);
static LLURI buildHTTP(const std::string& host_port,
const LLSD& path,
const LLSD& query);
std::string asString() const;
// the whole URI, escaped as needed
static LLURI buildHTTP(const std::string& prefix,
const LLSD& path);
static LLURI buildHTTP(const std::string& prefix,
const LLSD& path,
const LLSD& query);
// prefix is either a full URL prefix of the form "http://example.com:8080",
// or it can be simply a host and optional port like "example.com" or
// "example.com:8080", in these cases, the "http://" will be added
// Parts of a URI
// These functions return parts of the decoded URI. The returned
// strings are un-escaped as needed
// for all schemes
std::string scheme() const; // ex.: "http", note lack of colon
std::string opaque() const; // everything after the colon
static LLURI buildHTTP(const std::string& host,
const U32& port,
const LLSD& path);
static LLURI buildHTTP(const std::string& host,
const U32& port,
const LLSD& path,
const LLSD& query);
std::string asString() const;
// the whole URI, escaped as needed
// Parts of a URI
// These functions return parts of the decoded URI. The returned
// strings are un-escaped as needed
// for all schemes
std::string scheme() const; // ex.: "http", note lack of colon
std::string opaque() const; // everything after the colon
// for schemes that follow path like syntax (http, https, ftp)
std::string authority() const; // ex.: "host.com:80"
std::string hostName() const; // ex.: "host.com"
U16 hostPort() const; // ex.: 80, will include implicit port
std::string path() const; // ex.: "/abc/def", includes leading slash
// LLSD pathArray() const; // above decoded into an array of strings
std::string query() const; // ex.: "x=34", section after "?"
LLSD queryMap() const; // above decoded into a map
static LLSD queryMap(std::string escaped_query_string);
// for schemes that follow path like syntax (http, https, ftp)
std::string authority() const; // ex.: "bob@host.com:80"
std::string hostName() const; // ex.: "host.com"
U16 hostPort() const; // ex.: 80, will include implicit port
std::string path() const; // ex.: "/abc/def", includes leading slash
// LLSD pathArray() const; // above decoded into an array of strings
std::string query() const; // ex.: "x=34", section after "?"
LLSD queryMap() const; // above decoded into a map
static LLSD queryMap(std::string escaped_query_string);
// Escaping Utilities
static std::string escape(const std::string& str);
static std::string unescape(const std::string& str);
// Escaping Utilities
// Escape a string by urlencoding all the characters that aren't in the allowed string.
static std::string escape(const std::string& str, const std::string & allowed);
static std::string unescape(const std::string& str);
// Functions for building specific URIs for web services
static LLURI buildAgentPresenceURI(const LLUUID& agent_id, LLApp* app);
@ -71,11 +84,11 @@ public:
static LLURI buildInventoryHostURI(const LLUUID& agent_id, LLApp* app);
private:
std::string mScheme;
std::string mEscapedOpaque;
std::string mEscapedAuthority;
std::string mEscapedPath;
std::string mEscapedQuery;
std::string mScheme;
std::string mEscapedOpaque;
std::string mEscapedAuthority;
std::string mEscapedPath;
std::string mEscapedQuery;
};
#endif // LL_LLURI_H

View File

@ -22,6 +22,24 @@
#include "llsdutil.h"
///----------------------------------------------------------------------------
/// exported functions
///----------------------------------------------------------------------------
static const std::string INV_ITEM_ID_LABEL("item_id");
static const std::string INV_FOLDER_ID_LABEL("folder_id");
static const std::string INV_PARENT_ID_LABEL("parent_id");
static const std::string INV_ASSET_TYPE_LABEL("type");
static const std::string INV_PREFERRED_TYPE_LABEL("preferred_type");
static const std::string INV_INVENTORY_TYPE_LABEL("inv_type");
static const std::string INV_NAME_LABEL("name");
static const std::string INV_DESC_LABEL("desc");
static const std::string INV_PERMISSIONS_LABEL("permissions");
static const std::string INV_ASSET_ID_LABEL("asset_id");
static const std::string INV_SALE_INFO_LABEL("sale_info");
static const std::string INV_FLAGS_LABEL("flags");
static const std::string INV_CREATION_DATE_LABEL("created_at");
///----------------------------------------------------------------------------
/// Local function declarations, constants, enums, and typedefs
///----------------------------------------------------------------------------
@ -1113,24 +1131,24 @@ bool LLInventoryItem::fromLLSD(LLSD& sd)
{
mInventoryType = LLInventoryType::IT_NONE;
mAssetUUID.setNull();
const char *w;
std::string w;
w = "item_id";
w = INV_ITEM_ID_LABEL;
if (sd.has(w))
{
mUUID = sd[w];
}
w = "parent_id";
w = INV_PARENT_ID_LABEL;
if (sd.has(w))
{
mParentUUID = sd[w];
}
w = "permissions";
w = INV_PERMISSIONS_LABEL;
if (sd.has(w))
{
mPermissions = ll_permissions_from_sd(sd[w]);
}
w = "sale_info";
w = INV_SALE_INFO_LABEL;
if (sd.has(w))
{
// Sale info used to contain next owner perm. It is now in
@ -1164,40 +1182,40 @@ bool LLInventoryItem::fromLLSD(LLSD& sd)
LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES);
cipher.decrypt(mAssetUUID.mData, UUID_BYTES);
}
w = "asset_id";
w = INV_ASSET_ID_LABEL;
if (sd.has(w))
{
mAssetUUID = sd[w];
}
w = "type";
w = INV_ASSET_TYPE_LABEL;
if (sd.has(w))
{
mType = LLAssetType::lookup(sd[w].asString().c_str());
}
w = "inv_type";
w = INV_INVENTORY_TYPE_LABEL;
if (sd.has(w))
{
mInventoryType = LLInventoryType::lookup(sd[w].asString().c_str());
}
w = "flags";
w = INV_FLAGS_LABEL;
if (sd.has(w))
{
mFlags = ll_U32_from_sd(sd[w]);
}
w = "name";
w = INV_NAME_LABEL;
if (sd.has(w))
{
mName = sd[w].asString();
LLString::replaceNonstandardASCII(mName, ' ');
LLString::replaceChar(mName, '|', ' ');
}
w = "desc";
w = INV_DESC_LABEL;
if (sd.has(w))
{
mDescription = sd[w].asString();
LLString::replaceNonstandardASCII(mDescription, ' ');
}
w = "creation_date";
w = INV_CREATION_DATE_LABEL;
if (sd.has(w))
{
mCreationDate = sd[w];
@ -1720,24 +1738,6 @@ bool inventory_and_asset_types_match(
return rv;
}
///----------------------------------------------------------------------------
/// exported functions
///----------------------------------------------------------------------------
static const std::string INV_ITEM_ID_LABEL("item_id");
static const std::string INV_FOLDER_ID_LABEL("folder_id");
static const std::string INV_PARENT_ID_LABEL("parent_id");
static const std::string INV_ASSET_TYPE_LABEL("type");
static const std::string INV_PREFERRED_TYPE_LABEL("preferred_type");
static const std::string INV_INVENTORY_TYPE_LABEL("inv_type");
static const std::string INV_NAME_LABEL("name");
static const std::string INV_DESC_LABEL("desc");
static const std::string INV_PERMISSIONS_LABEL("permissions");
static const std::string INV_ASSET_ID_LABEL("asset_id");
static const std::string INV_SALE_INFO_LABEL("sale_info");
static const std::string INV_FLAGS_LABEL("flags");
static const std::string INV_CREATION_DATE_LABEL("created_at");
LLSD ll_create_sd_from_inventory_item(LLPointer<LLInventoryItem> item)
{
LLSD rv;

View File

@ -7,11 +7,10 @@
*/
#include "linden_common.h"
#include "llinventory.h"
#include "llnotecard.h"
#include "llstreamtools.h"
LLNotecard::LLNotecard(U32 max_text)
LLNotecard::LLNotecard(S32 max_text)
: mMaxText(max_text)
{
}
@ -179,7 +178,7 @@ bool LLNotecard::importStream(std::istream& str)
}
line_buf[STD_STRING_STR_LEN] = '\0';
U32 text_len = 0;
S32 text_len = 0;
if( 1 != sscanf(line_buf, "Text length %d", &text_len) )
{
llwarns << "Invalid Linden text length field" << llendl;

View File

@ -9,12 +9,21 @@
#ifndef LL_NOTECARD_H
#define LL_NOTECARD_H
const S32 MAX_NOTECARD_SIZE = 65536;
#include "llmemory.h"
#include "llinventory.h"
class LLNotecard
{
public:
LLNotecard(U32 max_text);
/**
* @brief anonymous enumeration to set max size.
*/
enum
{
MAX_SIZE = 65536
};
LLNotecard(S32 max_text = LLNotecard::MAX_SIZE);
virtual ~LLNotecard();
bool importStream(std::istream& str);
@ -33,7 +42,7 @@ private:
bool exportEmbeddedItemsStream(std::ostream& str);
std::vector<LLPointer<LLInventoryItem> > mItems;
LLString mText;
U32 mMaxText;
S32 mMaxText;
S32 mVersion;
S32 mEmbeddedVersion;
};

View File

@ -131,6 +131,27 @@ namespace
const LLSD mSD;
};
class RawInjector : public Injector
{
public:
RawInjector(const U8* data, S32 size) : mData(data), mSize(size) {}
virtual ~RawInjector() {}
const char* contentType() { return "application/octet-stream"; }
virtual EStatus process_impl(const LLChannelDescriptors& channels,
buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump)
{
LLBufferStream ostream(channels, buffer.get());
ostream.write((const char *)mData, mSize); // hopefully chars are always U8s
eos = true;
return STATUS_DONE;
}
const U8* mData;
S32 mSize;
};
class FileInjector : public Injector
{
@ -301,6 +322,11 @@ void LLHTTPClient::post(const std::string& url, const LLSD& body, ResponderPtr r
request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder);
}
void LLHTTPClient::post(const std::string& url, const U8* data, S32 size, ResponderPtr responder)
{
request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder);
}
void LLHTTPClient::del(const std::string& url, ResponderPtr responder)
{
request(url, LLURLRequest::HTTP_DELETE, NULL, responder);

View File

@ -54,6 +54,7 @@ public:
static void put(const std::string& url, const LLSD& body, ResponderPtr);
///< non-blocking
static void post(const std::string& url, const LLSD& body, ResponderPtr);
static void post(const std::string& url, const U8* data, S32 size, ResponderPtr responder);
static void postFile(const std::string& url, const std::string& filename, ResponderPtr);
static void postFile(const std::string& url, const LLUUID& uuid,
LLAssetType::EType asset_type, ResponderPtr responder);

View File

@ -1,5 +1,5 @@
/* Localized versions of Info.plist keys */
CFBundleName = "Second Life";
CFBundleShortVersionString = "Second Life version 1.13.3.3";
CFBundleGetInfoString = "Second Life version 1.13.3.3, Copyright 2004-2006 Linden Research, Inc.";
CFBundleShortVersionString = "Second Life version 1.13.4.8";
CFBundleGetInfoString = "Second Life version 1.13.4.8, Copyright 2004-2007 Linden Research, Inc.";

View File

@ -32,7 +32,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.13.3.3</string>
<string>1.13.4.8</string>
<key>CSResourcesFileMapped</key>
<true/>
</dict>

View File

@ -1,10 +1,6 @@
/**
* @file llmapresponders.h
* @brief Processes responses received for asset upload requests.
*
* Copyright (c) 2006-$CurrentYear$, Linden Research, Inc.
* $License$
*/
// llassetuploadresponders.cpp
// Copyright 2006, Linden Research, Inc.
// Processes responses received for asset upload requests.
#include "llviewerprecompiledheaders.h"
@ -19,39 +15,71 @@
#include "llinventorymodel.h"
#include "llinventoryview.h"
#include "llpermissionsflags.h"
#include "llpreviewnotecard.h"
#include "llpreviewscript.h"
#include "llscrolllistctrl.h"
#include "lluploaddialog.h"
#include "llviewermenu.h" // for upload_new_resource()
#include "llviewerobject.h"
#include "llviewerobjectlist.h"
#include "llviewermenu.h"
#include "llviewerwindow.h"
#include "viewer.h"
LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(const LLUUID& uuid,
const LLSD &post_data)
: LLHTTPClient::Responder()
void dialog_refresh_all();
LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data,
const LLUUID& vfile_id,
LLAssetType::EType asset_type)
: LLHTTPClient::Responder(),
mPostData(post_data),
mVFileID(vfile_id),
mAssetType(asset_type)
{
mUUID = uuid;
mPostData = post_data;
if (!gVFS->getExists(vfile_id, asset_type))
{
llwarns << "LLAssetUploadResponder called with nonexistant vfile_id" << llendl;
mVFileID.setNull();
mAssetType = LLAssetType::AT_NONE;
return;
}
}
LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data,
const std::string& file_name)
: LLHTTPClient::Responder(),
mPostData(post_data),
mFileName(file_name)
{
}
LLAssetUploadResponder::~LLAssetUploadResponder()
{
if (!mFileName.empty())
{
// Delete temp file
LLFile::remove(mFileName.c_str());
}
}
// virtual
void LLNewAgentInventoryResponder::error(U32 statusNum, const std::string& reason)
void LLAssetUploadResponder::error(U32 statusNum, const std::string& reason)
{
llinfos << "LLNewAgentInventoryResponder::error " << statusNum << llendl;
llinfos << "LLAssetUploadResponder::error " << statusNum
<< " reason: " << reason << llendl;
LLStringBase<char>::format_map_t args;
switch(statusNum)
{
case 400:
args["[FILE]"] = mPostData["inventory_type"].asString();
args["[REASON]"] = "invalid parameters in upload request";
args["[FILE]"] = (mFileName.empty() ? mVFileID.asString() : mFileName);
args["[REASON]"] = "Error in upload request. Please contact "
"support@lindenlab.com for help fixing this problem.";
gViewerWindow->alertXml("CannotUploadReason", args);
break;
case 402:
//(result["message"].asString() == "insufficient funds")
LLFloaterBuyCurrency::buyCurrency("Uploading costs", gGlobalEconomy->getPriceUpload());
break;
case 500:
default:
args["[FILE]"] = mPostData["inventory_type"].asString();
args["[REASON]"] = "the server is experiencing unexpected difficulties";
args["[FILE]"] = (mFileName.empty() ? mVFileID.asString() : mFileName);
args["[REASON]"] = "The server is experiencing unexpected "
"difficulties. Please try again later.";
gViewerWindow->alertXml("CannotUploadReason", args);
break;
}
@ -59,139 +87,373 @@ void LLNewAgentInventoryResponder::error(U32 statusNum, const std::string& reaso
}
//virtual
void LLNewAgentInventoryResponder::result(const LLSD& result)
void LLAssetUploadResponder::result(const LLSD& content)
{
lldebugs << "LLAssetUploadResponder::result from capabilities" << llendl;
std::string state = content["state"];
if (state == "upload")
{
uploadUpload(content);
}
else if (state == "complete")
{
// rename file in VFS with new asset id
if (mFileName.empty())
{
// rename the file in the VFS to the actual asset id
gVFS->renameFile(mVFileID, mAssetType, content["new_asset"].asUUID(), mAssetType);
}
uploadComplete(content);
}
else
{
uploadFailure(content);
}
}
void LLAssetUploadResponder::uploadUpload(const LLSD& content)
{
std::string uploader = content["uploader"];
if (mFileName.empty())
{
LLHTTPClient::postFile(uploader, mVFileID, mAssetType, this);
}
else
{
LLHTTPClient::postFile(uploader, mFileName, this);
}
}
void LLAssetUploadResponder::uploadFailure(const LLSD& content)
{
std::string reason = content["state"];
// deal with money errors
if (reason == "insufficient funds")
{
LLFloaterBuyCurrency::buyCurrency("Uploading costs", gGlobalEconomy->getPriceUpload());
}
else
{
LLStringBase<char>::format_map_t args;
args["[FILE]"] = (mFileName.empty() ? mVFileID.asString() : mFileName);
args["[REASON]"] = content["message"].asString();
gViewerWindow->alertXml("CannotUploadReason", args);
}
}
void LLAssetUploadResponder::uploadComplete(const LLSD& content)
{
}
LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(const LLSD& post_data,
const LLUUID& vfile_id,
LLAssetType::EType asset_type)
: LLAssetUploadResponder(post_data, vfile_id, asset_type)
{
}
LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(const LLSD& post_data, const std::string& file_name)
: LLAssetUploadResponder(post_data, file_name)
{
}
//virtual
void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content)
{
lldebugs << "LLNewAgentInventoryResponder::result from capabilities" << llendl;
if (!result["success"])
{
LLStringBase<char>::format_map_t args;
args["[FILE]"] = mPostData["inventory_type"].asString();
args["[REASON]"] = "the server is experiencing unexpected difficulties";
gViewerWindow->alertXml("CannotUploadReason", args);
return;
}
std::string uploader = result["uploader"];
LLAssetType::EType asset_type = LLAssetType::lookup(mPostData["asset_type"].asString().c_str());
LLInventoryType::EType inventory_type = LLInventoryType::lookup(mPostData["inventory_type"].asString().c_str());
// request succeeded
if (!uploader.empty())
// Update money and ownership credit information
// since it probably changed on the server
if (asset_type == LLAssetType::AT_TEXTURE ||
asset_type == LLAssetType::AT_SOUND ||
asset_type == LLAssetType::AT_ANIMATION)
{
LLHTTPClient::postFile(uploader, mUUID, asset_type, this);
gMessageSystem->newMessageFast(_PREHASH_MoneyBalanceRequest);
gMessageSystem->nextBlockFast(_PREHASH_AgentData);
gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
gMessageSystem->nextBlockFast(_PREHASH_MoneyData);
gMessageSystem->addUUIDFast(_PREHASH_TransactionID, LLUUID::null );
gAgent.sendReliableMessage();
LLString::format_map_t args;
args["[AMOUNT]"] = llformat("%d",gGlobalEconomy->getPriceUpload());
LLNotifyBox::showXml("UploadPayment", args);
}
// upload succeeded
else
// Actually add the upload to viewer inventory
llinfos << "Adding " << content["new_inventory_item"].asUUID() << " "
<< content["new_asset"].asUUID() << " to inventory." << llendl;
if(mPostData["folder_id"].asUUID().notNull())
{
// rename the file in the VFS to the actual asset id
gVFS->renameFile(mUUID, asset_type, result["new_asset"].asUUID(), asset_type);
// TODO: only request for textures, sound, and animation uploads
// Update money and ownership credit information
// since it probably changed on the server
if (mPostData["asset_type"].asString() == "texture" ||
mPostData["asset_type"].asString() == "sound" ||
mPostData["asset_type"].asString() == "animatn")
LLPermissions perm;
U32 next_owner_perm;
perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null);
if (mPostData["inventory_type"].asString() == "snapshot")
{
gMessageSystem->newMessageFast(_PREHASH_MoneyBalanceRequest);
gMessageSystem->nextBlockFast(_PREHASH_AgentData);
gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
gMessageSystem->nextBlockFast(_PREHASH_MoneyData);
gMessageSystem->addUUIDFast(_PREHASH_TransactionID, LLUUID::null );
gAgent.sendReliableMessage();
LLString::format_map_t args;
args["[AMOUNT]"] = llformat("%d",gGlobalEconomy->getPriceUpload());
LLNotifyBox::showXml("UploadPayment", args);
}
// Actually add the upload to viewer inventory
llinfos << "Adding " << result["new_inventory_item"].asUUID() << " "
<< result["new_asset"].asUUID() << " to inventory." << llendl;
if(mPostData["folder_id"].asUUID().notNull())
{
LLPermissions perm;
U32 next_owner_perm;
perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null);
if (mPostData["inventory_type"].asString() == "snapshot")
{
next_owner_perm = PERM_ALL;
}
else
{
next_owner_perm = PERM_MOVE | PERM_TRANSFER;
}
perm.initMasks(PERM_ALL, PERM_ALL, PERM_NONE, PERM_NONE, next_owner_perm);
S32 creation_date_now = time_corrected();
LLPointer<LLViewerInventoryItem> item
= new LLViewerInventoryItem(result["new_inventory_item"].asUUID(),
mPostData["folder_id"].asUUID(),
perm,
result["new_asset"].asUUID(),
asset_type,
inventory_type,
mPostData["name"].asString(),
mPostData["description"].asString(),
LLSaleInfo::DEFAULT,
LLInventoryItem::II_FLAGS_NONE,
creation_date_now);
gInventory.updateItem(item);
gInventory.notifyObservers();
// Show the preview panel for textures and sounds to let
// user know that the image (or snapshot) arrived intact.
LLInventoryView* view = LLInventoryView::getActiveInventory();
if(view)
{
LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus();
LLFocusMgr::FocusLostCallback callback = gFocusMgr.getFocusCallback();
view->getPanel()->setSelection(result["new_inventory_item"].asUUID(), TAKE_FOCUS_NO);
if((LLAssetType::AT_TEXTURE == asset_type)
|| (LLAssetType::AT_SOUND == asset_type))
{
view->getPanel()->openSelected();
}
//LLInventoryView::dumpSelectionInformation((void*)view);
// restore keyboard focus
gFocusMgr.setKeyboardFocus(focus_ctrl, callback);
}
next_owner_perm = PERM_ALL;
}
else
{
llwarns << "Can't find a folder to put it in" << llendl;
next_owner_perm = PERM_MOVE | PERM_TRANSFER;
}
perm.initMasks(PERM_ALL, PERM_ALL, PERM_NONE, PERM_NONE, next_owner_perm);
S32 creation_date_now = time_corrected();
LLPointer<LLViewerInventoryItem> item
= new LLViewerInventoryItem(content["new_inventory_item"].asUUID(),
mPostData["folder_id"].asUUID(),
perm,
content["new_asset"].asUUID(),
asset_type,
inventory_type,
mPostData["name"].asString(),
mPostData["description"].asString(),
LLSaleInfo::DEFAULT,
LLInventoryItem::II_FLAGS_NONE,
creation_date_now);
gInventory.updateItem(item);
gInventory.notifyObservers();
// remove the "Uploading..." message
LLUploadDialog::modalUploadFinished();
// *NOTE: This is a pretty big hack. What this does is check
// the file picker if there are any more pending uploads. If
// so, upload that file.
const char* next_file = LLFilePicker::instance().getNextFile();
if(next_file)
// Show the preview panel for textures and sounds to let
// user know that the image (or snapshot) arrived intact.
LLInventoryView* view = LLInventoryView::getActiveInventory();
if(view)
{
const char* name = LLFilePicker::instance().getDirname();
LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus();
LLFocusMgr::FocusLostCallback callback = gFocusMgr.getFocusCallback();
LLString asset_name = name;
LLString::replaceNonstandardASCII( asset_name, '?' );
LLString::replaceChar(asset_name, '|', '?');
LLString::stripNonprintable(asset_name);
LLString::trim(asset_name);
char* asset_name_str = (char*)asset_name.c_str();
char* end_p = strrchr(asset_name_str, '.'); // strip extension if exists
if( !end_p )
view->getPanel()->setSelection(content["new_inventory_item"].asUUID(), TAKE_FOCUS_NO);
if((LLAssetType::AT_TEXTURE == asset_type)
|| (LLAssetType::AT_SOUND == asset_type))
{
end_p = asset_name_str + strlen( asset_name_str ); /*Flawfinder: ignore*/
view->getPanel()->openSelected();
}
S32 len = llmin( (S32) (DB_INV_ITEM_NAME_STR_LEN), (S32) (end_p - asset_name_str) );
asset_name = asset_name.substr( 0, len );
upload_new_resource(next_file, asset_name, asset_name,
0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE);
//LLInventoryView::dumpSelectionInformation((void*)view);
// restore keyboard focus
gFocusMgr.setKeyboardFocus(focus_ctrl, callback);
}
}
else
{
llwarns << "Can't find a folder to put it in" << llendl;
}
// remove the "Uploading..." message
LLUploadDialog::modalUploadFinished();
// *FIX: This is a pretty big hack. What this does is check the
// file picker if there are any more pending uploads. If so,
// upload that file.
const char* next_file = LLFilePicker::instance().getNextFile();
if(next_file)
{
const char* name = LLFilePicker::instance().getDirname();
LLString asset_name = name;
LLString::replaceNonstandardASCII( asset_name, '?' );
LLString::replaceChar(asset_name, '|', '?');
LLString::stripNonprintable(asset_name);
LLString::trim(asset_name);
char* asset_name_str = (char*)asset_name.c_str();
char* end_p = strrchr(asset_name_str, '.'); // strip extension if exists
if( !end_p )
{
end_p = asset_name_str + strlen( asset_name_str ); /*Flawfinder: ignore*/
}
S32 len = llmin( (S32) (DB_INV_ITEM_NAME_STR_LEN), (S32) (end_p - asset_name_str) );
asset_name = asset_name.substr( 0, len );
upload_new_resource(next_file, asset_name, asset_name,
0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE);
}
}
LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(const LLSD& post_data,
const LLUUID& vfile_id,
LLAssetType::EType asset_type)
: LLAssetUploadResponder(post_data, vfile_id, asset_type)
{
}
LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(const LLSD& post_data,
const std::string& file_name)
: LLAssetUploadResponder(post_data, file_name)
{
}
//virtual
void LLUpdateAgentInventoryResponder::uploadComplete(const LLSD& content)
{
llinfos << "LLUpdateAgentInventoryResponder::result from capabilities" << llendl;
LLUUID item_id = mPostData["item_id"];
LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(item_id);
if(!item)
{
llwarns << "Inventory item for " << mVFileID
<< " is no longer in agent inventory." << llendl;
return;
}
// Update viewer inventory item
LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
new_item->setAssetUUID(content["new_asset"].asUUID());
gInventory.updateItem(new_item);
gInventory.notifyObservers();
llinfos << "Inventory item " << item->getName() << " saved into "
<< content["new_asset"].asString() << llendl;
LLInventoryType::EType inventory_type = new_item->getInventoryType();
switch(inventory_type)
{
case LLInventoryType::IT_NOTECARD:
{
// Update the UI with the new asset.
LLPreviewNotecard* nc;
nc = (LLPreviewNotecard*)LLPreview::find(new_item->getUUID());
if(nc)
{
// *HACK: we have to delete the asset in the VFS so
// that the viewer will redownload it. This is only
// really necessary if the asset had to be modified by
// the uploader, so this can be optimized away in some
// cases. A better design is to have a new uuid if the
// script actually changed the asset.
if(nc->hasEmbeddedInventory())
{
gVFS->removeFile(
content["new_asset"].asUUID(),
LLAssetType::AT_NOTECARD);
}
nc->refreshFromInventory();
}
}
break;
case LLInventoryType::IT_LSL:
{
// Find our window and close it if requested.
LLPreviewLSL* preview = (LLPreviewLSL*)LLPreview::find(item_id);
if (preview)
{
// Bytecode save completed
if (content["compiled"])
{
preview->callbackLSLCompileSucceeded();
}
else
{
preview->callbackLSLCompileFailed(content["errors"]);
}
}
}
break;
case LLInventoryType::IT_WEARABLE:
default:
break;
}
}
LLUpdateTaskInventoryResponder::LLUpdateTaskInventoryResponder(const LLSD& post_data,
const LLUUID& vfile_id,
LLAssetType::EType asset_type)
: LLAssetUploadResponder(post_data, vfile_id, asset_type)
{
}
LLUpdateTaskInventoryResponder::LLUpdateTaskInventoryResponder(const LLSD& post_data,
const std::string& file_name)
: LLAssetUploadResponder(post_data, file_name)
{
}
//virtual
void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content)
{
llinfos << "LLUpdateTaskInventoryResponder::result from capabilities" << llendl;
LLUUID item_id = mPostData["item_id"];
LLUUID task_id = mPostData["task_id"];
LLViewerObject* object = gObjectList.findObject(task_id);
if (!object)
{
llwarns << "LLUpdateTaskInventoryResponder::uploadComplete task " << task_id
<< " no longer exist." << llendl;
return;
}
LLViewerInventoryItem* item = (LLViewerInventoryItem*)object->getInventoryObject(item_id);
if (!item)
{
llwarns << "LLUpdateTaskInventoryResponder::uploadComplete item "
<< item_id << " is no longer in task " << task_id
<< "'s inventory." << llendl;
return;
}
LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
// Update Viewer inventory
object->updateViewerInventoryAsset(new_item, content["new_asset"]);
dialog_refresh_all();
LLInventoryType::EType inventory_type = new_item->getInventoryType();
switch(inventory_type)
{
case LLInventoryType::IT_NOTECARD:
{
// Update the UI with the new asset.
LLPreviewNotecard* nc;
nc = (LLPreviewNotecard*)LLPreview::find(new_item->getUUID());
if(nc)
{
// *HACK: we have to delete the asset in the VFS so
// that the viewer will redownload it. This is only
// really necessary if the asset had to be modified by
// the uploader, so this can be optimized away in some
// cases. A better design is to have a new uuid if the
// script actually changed the asset.
if(nc->hasEmbeddedInventory())
{
gVFS->removeFile(
content["new_asset"].asUUID(),
LLAssetType::AT_NOTECARD);
}
nc->refreshFromInventory();
}
}
break;
case LLInventoryType::IT_LSL:
{
LLLiveLSLEditor* preview = LLLiveLSLEditor::find(item_id, task_id);
if (preview)
{
// Bytecode save completed
if (content["compiled"])
{
preview->callbackLSLCompileSucceeded(
task_id,
item_id,
mPostData["is_script_running"]);
}
else
{
preview->callbackLSLCompileFailed(content["errors"]);
}
}
}
break;
case LLInventoryType::IT_WEARABLE:
default:
break;
}
}

View File

@ -1,26 +1,65 @@
/**
* @file llmapresponders.h
* @brief Processes responses received for asset upload requests.
*
* Copyright (c) 2006-$CurrentYear$, Linden Research, Inc.
* $License$
*/
// llassetuploadresponders.h
// Copyright 2006, Linden Research, Inc.
// Processes responses received for asset upload requests.
#ifndef LL_LLNEWAGENTINVENTORYRESPONDER_H
#define LL_LLNEWAGENTINVENTORYRESPONDER_H
#ifndef LL_LLASSETUPLOADRESPONDER_H
#define LL_LLASSETUPLOADRESPONDER_H
#include "llhttpclient.h"
class LLNewAgentInventoryResponder : public LLHTTPClient::Responder
// Abstract class for supporting asset upload
// via capabilities
class LLAssetUploadResponder : public LLHTTPClient::Responder
{
public:
LLNewAgentInventoryResponder(const LLUUID& uuid, const LLSD& post_data);
void error(U32 statusNum, const std::string& reason);
LLAssetUploadResponder(const LLSD& post_data,
const LLUUID& vfile_id,
LLAssetType::EType asset_type);
LLAssetUploadResponder(const LLSD& post_data, const std::string& file_name);
~LLAssetUploadResponder();
virtual void error(U32 statusNum, const std::string& reason);
virtual void result(const LLSD& content);
virtual void uploadUpload(const LLSD& content);
virtual void uploadComplete(const LLSD& content);
virtual void uploadFailure(const LLSD& content);
private:
LLUUID mUUID;
protected:
LLSD mPostData;
LLUUID mVFileID;
LLAssetType::EType mAssetType;
std::string mFileName;
};
#endif // LL_LLNEWAGENTINVENTORYRESPONDER_H
class LLNewAgentInventoryResponder : public LLAssetUploadResponder
{
public:
LLNewAgentInventoryResponder(const LLSD& post_data,
const LLUUID& vfile_id,
LLAssetType::EType asset_type);
LLNewAgentInventoryResponder(const LLSD& post_data, const std::string& file_name);
virtual void uploadComplete(const LLSD& content);
};
class LLUpdateAgentInventoryResponder : public LLAssetUploadResponder
{
public:
LLUpdateAgentInventoryResponder(const LLSD& post_data,
const LLUUID& vfile_id,
LLAssetType::EType asset_type);
LLUpdateAgentInventoryResponder(const LLSD& post_data,
const std::string& file_name);
virtual void uploadComplete(const LLSD& content);
};
class LLUpdateTaskInventoryResponder : public LLAssetUploadResponder
{
public:
LLUpdateTaskInventoryResponder(const LLSD& post_data,
const LLUUID& vfile_id,
LLAssetType::EType asset_type);
LLUpdateTaskInventoryResponder(const LLSD& post_data,
const std::string& file_name);
virtual void uploadComplete(const LLSD& content);
};
#endif // LL_LLASSETUPLOADRESPONDER_H

View File

@ -39,6 +39,8 @@
#include "llvfs.h"
#include "viewer.h"
#include "llassetuploadresponders.h"
///----------------------------------------------------------------------------
/// Local function declarations, constants, enums, and typedefs
///----------------------------------------------------------------------------
@ -206,6 +208,23 @@ void LLFloaterPostcard::onClickCancel(void* data)
}
}
class LLSendPostcardResponder : public LLAssetUploadResponder
{
public:
LLSendPostcardResponder(const LLSD &post_data,
const LLUUID& vfile_id,
LLAssetType::EType asset_type):
LLAssetUploadResponder(post_data, vfile_id, asset_type)
{
}
// *TODO define custom uploadFailed here so it's not such a generic message
void LLSendPostcardResponder::uploadComplete(const LLSD& content)
{
// we don't care about what the server returns from this post, just clean up the UI
LLUploadDialog::modalUploadFinished();
}
};
// static
void LLFloaterPostcard::onClickSend(void* data)
{
@ -230,12 +249,31 @@ void LLFloaterPostcard::onClickSend(void* data)
if (self->mJPEGImage.notNull())
{
// upload the image
self->mTransactionID.generate();
self->mAssetID = self->mTransactionID.makeAssetID(gAgent.getSecureSessionID());
LLVFile::writeFile(self->mJPEGImage->getData(), self->mJPEGImage->getDataSize(), gVFS, self->mAssetID, LLAssetType::AT_IMAGE_JPEG);
gAssetStorage->storeAssetData(self->mTransactionID, LLAssetType::AT_IMAGE_JPEG, &uploadCallback, (void *)self, FALSE);
// upload the image
std::string url = gAgent.getRegion()->getCapability("SendPostcard");
if(!url.empty())
{
llinfos << "Send Postcard via capability" << llendl;
LLSD body = LLSD::emptyMap();
// the capability already encodes: agent ID, region ID
body["pos-global"] = self->mPosTakenGlobal.getValue();
body["to"] = self->childGetValue("to_form").asString();
body["from"] = self->childGetValue("from_form").asString();
body["name"] = self->childGetValue("name_form").asString();
body["subject"] = self->childGetValue("subject_form").asString();
body["msg"] = self->childGetValue("msg_form").asString();
body["allow-publish"] = self->childGetValue("allow_publish_check").asBoolean();
body["mature-publish"] = self->childGetValue("mature_check").asBoolean();
LLHTTPClient::post(url, body, new LLSendPostcardResponder(body, self->mAssetID, LLAssetType::AT_IMAGE_JPEG));
}
else
{
gAssetStorage->storeAssetData(self->mTransactionID, LLAssetType::AT_IMAGE_JPEG, &uploadCallback, (void *)self, FALSE);
}
LLUploadDialog::modalUploadDialog("Uploading...\n\nPostcard");

View File

@ -44,6 +44,7 @@
#include "lltooldraganddrop.h"
#include "llfloatermap.h"
#include "lluiconstants.h"
#include "lluploaddialog.h"
#include "llcallingcard.h"
#include "llviewerobjectlist.h"
#include "llagent.h"
@ -61,6 +62,7 @@
#include "llvieweruictrlfactory.h"
#include "viewer.h"
#include "llassetuploadresponders.h"
const U32 INCLUDE_SCREENSHOT = 0x01 << 0;
@ -96,7 +98,8 @@ LLFloaterReporter::LLFloaterReporter(
mDeselectOnClose( FALSE ),
mPicking( FALSE),
mPosition(),
mCopyrightWarningSeen( FALSE )
mCopyrightWarningSeen( FALSE ),
mResourceDatap(new LLResourceData())
{
if (report_type == BUG_REPORT)
{
@ -147,9 +150,9 @@ LLFloaterReporter::LLFloaterReporter(
gReporterInstances.addData(report_type, this);
// Upload a screenshot, but don't draw this floater.
// Take a screenshot, but don't draw this floater.
setVisible(FALSE);
uploadScreenshot();
takeScreenshot();
setVisible(TRUE);
// Default text to be blank
@ -211,6 +214,7 @@ LLFloaterReporter::~LLFloaterReporter()
std::for_each(mMCDList.begin(), mMCDList.end(), DeletePointer() );
mMCDList.clear();
delete mResourceDatap;
gDialogVisible = FALSE;
}
@ -344,7 +348,7 @@ void LLFloaterReporter::callbackAvatarID(const std::vector<std::string>& names,
if ( self->mReportType != BUG_REPORT )
{
self->childSetText("abuser_name_edit", names[0] );
self->mAbuserID = ids[0];
self->refresh();
@ -355,31 +359,59 @@ void LLFloaterReporter::callbackAvatarID(const std::vector<std::string>& names,
void LLFloaterReporter::onClickSend(void *userdata)
{
LLFloaterReporter *self = (LLFloaterReporter *)userdata;
// only do this for abuse reports
if ( self->mReportType != BUG_REPORT )
{
if ( ! self->mCopyrightWarningSeen )
{
LLString details_lc = self->childGetText("details_edit");
LLString::toLower( details_lc );
LLString summary_lc = self->childGetText("summary_edit");
LLString::toLower( summary_lc );
if ( details_lc.find( "copyright" ) != std::string::npos ||
summary_lc.find( "copyright" ) != std::string::npos )
{
gViewerWindow->alertXml("HelpReportAbuseContainsCopyright");
self->mCopyrightWarningSeen = TRUE;
return;
};
};
};
if (self->mPicking)
{
closePickTool(self);
}
self->sendReport();
if(self->validateReport())
{
// only show copyright alert for abuse reports
if ( self->mReportType != BUG_REPORT )
{
if ( ! self->mCopyrightWarningSeen )
{
LLString details_lc = self->childGetText("details_edit");
LLString::toLower( details_lc );
LLString summary_lc = self->childGetText("summary_edit");
LLString::toLower( summary_lc );
if ( details_lc.find( "copyright" ) != std::string::npos ||
summary_lc.find( "copyright" ) != std::string::npos )
{
gViewerWindow->alertXml("HelpReportAbuseContainsCopyright");
self->mCopyrightWarningSeen = TRUE;
return;
};
};
};
LLUploadDialog::modalUploadDialog("Uploading...\n\nReport");
// *TODO don't upload image if checkbox isn't checked
std::string url = gAgent.getRegion()->getCapability("SendUserReport");
std::string sshot_url = gAgent.getRegion()->getCapability("SendUserReportWithScreenshot");
if(!url.empty() || !sshot_url.empty())
{
self->sendReportViaCaps(url, sshot_url, self->gatherReport());
self->close();
}
else
{
if(self->childGetValue("screen_check"))
{
self->childDisable("send_btn");
self->childDisable("cancel_btn");
// the callback from uploading the image calls sendReportViaLegacy()
self->uploadImage();
}
else
{
self->sendReportViaLegacy(self->gatherReport());
LLUploadDialog::modalUploadFinished();
self->close();
}
}
}
}
@ -532,10 +564,9 @@ void LLFloaterReporter::setPickedObjectProperties(const char *object_name, const
childSetText("owner_name", owner_name);
}
void LLFloaterReporter::sendReport()
bool LLFloaterReporter::validateReport()
{
LLViewerRegion *regionp = gAgent.getRegion();
if (!regionp) return;
// Ensure user selected a category from the list
LLSD category_sd = childGetValue("category_combo");
U8 category = (U8)category_sd.asInteger();
@ -549,7 +580,7 @@ void LLFloaterReporter::sendReport()
{
gViewerWindow->alertXml("HelpReportBugSelectCategory");
}
return;
return false;
}
if ( mReportType != BUG_REPORT )
@ -557,13 +588,13 @@ void LLFloaterReporter::sendReport()
if ( childGetText("abuser_name_edit").empty() )
{
gViewerWindow->alertXml("HelpReportAbuseAbuserNameEmpty");
return;
return false;
};
if ( childGetText("abuse_location_edit").empty() )
{
gViewerWindow->alertXml("HelpReportAbuseAbuserLocationEmpty");
return;
return false;
};
};
@ -577,7 +608,7 @@ void LLFloaterReporter::sendReport()
{
gViewerWindow->alertXml("HelpReportBugSummaryEmpty");
}
return;
return false;
};
if ( childGetText("details_edit") == mDefaultSummary )
@ -590,53 +621,19 @@ void LLFloaterReporter::sendReport()
{
gViewerWindow->alertXml("HelpReportBugDetailsEmpty");
}
return;
return false;
};
return true;
}
LLSD LLFloaterReporter::gatherReport()
{
LLViewerRegion *regionp = gAgent.getRegion();
if (!regionp) return LLSD(); // *TODO handle this failure case more gracefully
// reset flag in case the next report also contains this text
mCopyrightWarningSeen = FALSE;
U32 check_flags = 0;
if (childGetValue("screen_check"))
{
check_flags |= INCLUDE_SCREENSHOT;
}
LLMessageSystem *msg = gMessageSystem;
msg->newMessageFast(_PREHASH_UserReport);
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
msg->nextBlockFast(_PREHASH_ReportData);
msg->addU8Fast(_PREHASH_ReportType, (U8) mReportType);
msg->addU8(_PREHASH_Category, category);
msg->addVector3Fast(_PREHASH_Position, mPosition);
msg->addU8Fast(_PREHASH_CheckFlags, (U8) check_flags);
// only send a screenshot ID if we're asked too and the email is
// going to LL - Estate Owners cannot see the screenshot asset
LLSD screenshot_id = LLUUID::null;
if (childGetValue("screen_check"))
{
if ( mReportType != BUG_REPORT )
{
if ( gEmailToEstateOwner == FALSE )
{
screenshot_id = childGetValue("screenshot");
}
}
else
{
screenshot_id = childGetValue("screenshot");
};
};
msg->addUUIDFast(_PREHASH_ScreenshotID, screenshot_id);
msg->addUUIDFast(_PREHASH_ObjectID, mObjectID);
msg->addUUID("AbuserID", mAbuserID );
msg->addString("AbuseRegionName", "");
msg->addUUID("AbuseRegionID", LLUUID::null);
std::ostringstream summary;
if (!gInProductionGrid)
{
@ -684,7 +681,6 @@ void LLFloaterReporter::sendReport()
<< " {" << childGetText("abuser_name_edit") << "} " // name of abuse entered in report (chosen using LLAvatarPicker)
<< " \"" << childGetValue("summary_edit").asString() << "\""; // summary as entered
};
msg->addStringFast(_PREHASH_Summary, summary.str().c_str());
std::ostringstream details;
if (mReportType != BUG_REPORT)
@ -709,7 +705,6 @@ void LLFloaterReporter::sendReport()
};
details << childGetValue("details_edit").asString();
msg->addStringFast(_PREHASH_Details, details.str() );
char version_string[MAX_STRING]; /* Flawfinder: ignore */
snprintf(version_string, /* Flawfinder: ignore */
@ -722,120 +717,204 @@ void LLFloaterReporter::sendReport()
gSysCPU.getFamily().c_str(),
gGLManager.mGLRenderer.c_str(),
gGLManager.mDriverVersionVendorString.c_str());
msg->addString("VersionString", version_string);
msg->sendReliable(regionp->getHost());
close();
}
void LLFloaterReporter::uploadScreenshot()
{
const S32 IMAGE_WIDTH = 1024;
const S32 IMAGE_HEIGHT = 768;
LLString filename("report_screenshot.bmp");
if( !gViewerWindow->saveSnapshot( filename, IMAGE_WIDTH, IMAGE_HEIGHT, TRUE, FALSE ) )
// only send a screenshot ID if we're asked to and the email is
// going to LL - Estate Owners cannot see the screenshot asset
LLUUID screenshot_id = LLUUID::null;
if (childGetValue("screen_check"))
{
return;
}
// Generate the temporary filename
std::string temp_filename = gDirUtilp->getTempFilename();
// try to create the upload file
if (!LLViewerImageList::createUploadFile(filename,
temp_filename,
IMG_CODEC_BMP ))
{
llwarns << "Unable to upload report screenshot " << filename << ":\n\n" << LLImageBase::getLastError() << "\n" << llendl;
if(LLFile::remove(temp_filename.c_str()) == -1)
if ( mReportType != BUG_REPORT )
{
lldebugs << "unable to remove temp file" << llendl;
}
LLFilePicker::instance().reset();
}
else
{
// create a resource data
LLResourceData* data = NULL;
data = new LLResourceData;
data->mInventoryType = LLInventoryType::IT_NONE;
data->mAssetInfo.mTransactionID.generate();
data->mAssetInfo.mUuid = data->mAssetInfo.mTransactionID.makeAssetID(gAgent.getSecureSessionID());
if (BUG_REPORT == mReportType)
{
//data->mAssetInfo.mType = LLAssetType::AT_BUG_REPORT_SCREENSHOT;
data->mAssetInfo.mType = LLAssetType::AT_TEXTURE;
data->mPreferredLocation = LLAssetType::EType(-1);
}
else if (COMPLAINT_REPORT == mReportType)
{
//data->mAssetInfo.mType = LLAssetType::AT_COMPLAINT_REPORT_SCREENSHOT;
data->mAssetInfo.mType = LLAssetType::AT_TEXTURE;
data->mPreferredLocation = LLAssetType::EType(-2);
if ( gEmailToEstateOwner == FALSE )
{
screenshot_id = childGetValue("screenshot");
}
}
else
{
llwarns << "Unknown LLFloaterReporter type" << llendl;
}
data->mAssetInfo.mCreatorID = gAgentID;
data->mAssetInfo.setName("screenshot_name");
data->mAssetInfo.setDescription("screenshot_descr");
screenshot_id = childGetValue("screenshot");
};
};
llinfos << "*** Uploading: " << llendl;
llinfos << "Type: " << LLAssetType::lookup(data->mAssetInfo.mType) << llendl;
llinfos << "File: " << filename << llendl;
llinfos << "Dest: " << temp_filename << llendl;
llinfos << "Name: " << data->mAssetInfo.getName() << llendl;
llinfos << "Desc: " << data->mAssetInfo.getDescription() << llendl;
LLSD report = LLSD::emptyMap();
report["report-type"] = (U8) mReportType;
report["category"] = childGetValue("category_combo");
report["position"] = mPosition.getValue();
report["check-flags"] = (U8)0; // this is not used
report["screenshot-id"] = screenshot_id;
report["object-id"] = mObjectID;
report["abuser-id"] = mAbuserID;
report["abuse-region-name"] = "";
report["abuse-region-id"] = LLUUID::null;
report["summary"] = summary.str();
report["version-string"] = version_string;
report["details"] = details.str();
return report;
}
gAssetStorage->storeAssetData(temp_filename.c_str(),
data->mAssetInfo.mTransactionID,
data->mAssetInfo.mType,
LLFloaterReporter::uploadDoneCallback,
(void*)data, TRUE);
void LLFloaterReporter::sendReportViaLegacy(const LLSD & report)
{
LLViewerRegion *regionp = gAgent.getRegion();
if (!regionp) return;
LLMessageSystem *msg = gMessageSystem;
msg->newMessageFast(_PREHASH_UserReport);
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
msg->nextBlockFast(_PREHASH_ReportData);
msg->addU8Fast(_PREHASH_ReportType, report["report-type"].asInteger());
msg->addU8(_PREHASH_Category, report["category"].asInteger());
msg->addVector3Fast(_PREHASH_Position, LLVector3(report["position"]));
msg->addU8Fast(_PREHASH_CheckFlags, report["check-flags"].asInteger());
msg->addUUIDFast(_PREHASH_ScreenshotID, report["screenshot-id"].asUUID());
msg->addUUIDFast(_PREHASH_ObjectID, report["object-id"].asUUID());
msg->addUUID("AbuserID", report["abuser-id"].asUUID());
msg->addString("AbuseRegionName", report["abuse-region-name"].asString());
msg->addUUID("AbuseRegionID", report["abuse-region-id"].asUUID());
msg->addStringFast(_PREHASH_Summary, report["summary"].asString().c_str());
msg->addString("VersionString", report["version-string"]);
msg->addStringFast(_PREHASH_Details, report["details"] );
msg->sendReliable(regionp->getHost());
}
class LLUserReportScreenshotResponder : public LLAssetUploadResponder
{
public:
LLUserReportScreenshotResponder(const LLSD & post_data,
const LLUUID & vfile_id,
LLAssetType::EType asset_type):
LLAssetUploadResponder(post_data, vfile_id, asset_type)
{
}
void uploadFailed(const LLSD& content)
{
// *TODO pop up a dialog so the user knows their report screenshot didn't make it
LLUploadDialog::modalUploadFinished();
}
void uploadComplete(const LLSD& content)
{
// we don't care about what the server returns from this post, just clean up the UI
LLUploadDialog::modalUploadFinished();
}
};
class LLUserReportResponder : public LLHTTPClient::Responder
{
public:
LLUserReportResponder(): LLHTTPClient::Responder() {}
void error(U32 status, const std::string& reason)
{
// *TODO do some user messaging here
LLUploadDialog::modalUploadFinished();
}
void result(const LLSD& content)
{
// we don't care about what the server returns
LLUploadDialog::modalUploadFinished();
}
};
void LLFloaterReporter::sendReportViaCaps(std::string url, std::string sshot_url, const LLSD& report)
{
if(childGetValue("screen_check").asBoolean() && !sshot_url.empty())
{
// try to upload screenshot
LLHTTPClient::post(sshot_url, report, new LLUserReportScreenshotResponder(report,
mResourceDatap->mAssetInfo.mUuid,
mResourceDatap->mAssetInfo.mType));
}
else
{
// screenshot not wanted or we don't have screenshot cap
LLHTTPClient::post(url, report, new LLUserReportResponder());
}
}
void LLFloaterReporter::takeScreenshot()
{
const S32 IMAGE_WIDTH = 1024;
const S32 IMAGE_HEIGHT = 768;
LLPointer<LLImageRaw> raw = new LLImageRaw;
if( !gViewerWindow->rawSnapshot(raw, IMAGE_WIDTH, IMAGE_HEIGHT, TRUE, TRUE, FALSE))
{
llwarns << "Unable to take screenshot" << llendl;
return;
}
LLPointer<LLImageJ2C> upload_data = LLViewerImageList::convertToUploadFile(raw);
// create a resource data
mResourceDatap->mInventoryType = LLInventoryType::IT_NONE;
mResourceDatap->mAssetInfo.mTransactionID.generate();
mResourceDatap->mAssetInfo.mUuid = mResourceDatap->mAssetInfo.mTransactionID.makeAssetID(gAgent.getSecureSessionID());
if (BUG_REPORT == mReportType)
{
mResourceDatap->mAssetInfo.mType = LLAssetType::AT_TEXTURE;
mResourceDatap->mPreferredLocation = LLAssetType::EType(-1);
}
else if (COMPLAINT_REPORT == mReportType)
{
mResourceDatap->mAssetInfo.mType = LLAssetType::AT_TEXTURE;
mResourceDatap->mPreferredLocation = LLAssetType::EType(-2);
}
else
{
llwarns << "Unknown LLFloaterReporter type" << llendl;
}
mResourceDatap->mAssetInfo.mCreatorID = gAgentID;
mResourceDatap->mAssetInfo.setName("screenshot_name");
mResourceDatap->mAssetInfo.setDescription("screenshot_descr");
// store in VFS
LLVFile::writeFile(upload_data->getData(),
upload_data->getDataSize(),
gVFS,
mResourceDatap->mAssetInfo.mUuid,
mResourceDatap->mAssetInfo.mType);
// store in the image list so it doesn't try to fetch from the server
LLViewerImage* image_in_list = new LLViewerImage(mResourceDatap->mAssetInfo.mUuid, TRUE);
image_in_list->createGLTexture(0, raw);
gImageList.addImage(image_in_list);
// the texture picker then uses that texture
LLTexturePicker* texture = LLUICtrlFactory::getTexturePickerByName(this, "screenshot");
if (texture)
{
texture->setImageAssetID(mResourceDatap->mAssetInfo.mUuid);
texture->setDefaultImageAssetID(mResourceDatap->mAssetInfo.mUuid);
texture->setCaption("Screenshot");
}
}
void LLFloaterReporter::uploadImage()
{
llinfos << "*** Uploading: " << llendl;
llinfos << "Type: " << LLAssetType::lookup(mResourceDatap->mAssetInfo.mType) << llendl;
llinfos << "UUID: " << mResourceDatap->mAssetInfo.mUuid << llendl;
llinfos << "Name: " << mResourceDatap->mAssetInfo.getName() << llendl;
llinfos << "Desc: " << mResourceDatap->mAssetInfo.getDescription() << llendl;
gAssetStorage->storeAssetData(mResourceDatap->mAssetInfo.mTransactionID,
mResourceDatap->mAssetInfo.mType,
LLFloaterReporter::uploadDoneCallback,
(void*)mResourceDatap, TRUE);
}
// static
void LLFloaterReporter::uploadDoneCallback(const LLUUID &uuid, void *user_data, S32 result) // StoreAssetData callback (fixed)
{
LLUploadDialog::modalUploadFinished();
LLResourceData* data = (LLResourceData*)user_data;
if(result >= 0)
{
EReportType report_type = UNKNOWN_REPORT;
if (data->mPreferredLocation == -1)
{
report_type = BUG_REPORT;
}
else if (data->mPreferredLocation == -2)
{
report_type = COMPLAINT_REPORT;
}
else
{
llwarns << "Unknown report type : " << data->mPreferredLocation << llendl;
}
LLFloaterReporter *self = getReporter(report_type);
if (self)
{
LLTexturePicker* texture = LLUICtrlFactory::getTexturePickerByName(self, "screenshot");
if (texture)
{
texture->setImageAssetID(uuid);
texture->setDefaultImageAssetID(uuid);
texture->setCaption("Screenshot");
}
self->mScreenID = uuid;
llinfos << "Got screen shot " << uuid << llendl;
}
}
else // if(result >= 0)
if(result < 0)
{
LLStringBase<char>::format_map_t args;
args["[REASON]"] = std::string(LLAssetStorage::getErrorString(result));
@ -844,8 +923,31 @@ void LLFloaterReporter::uploadDoneCallback(const LLUUID &uuid, void *user_data,
std::string err_msg("There was a problem uploading a report screenshot");
err_msg += " due to the following reason: " + args["[REASON]"];
llwarns << err_msg << llendl;
return;
}
delete data;
EReportType report_type = UNKNOWN_REPORT;
if (data->mPreferredLocation == -1)
{
report_type = BUG_REPORT;
}
else if (data->mPreferredLocation == -2)
{
report_type = COMPLAINT_REPORT;
}
else
{
llwarns << "Unknown report type : " << data->mPreferredLocation << llendl;
}
LLFloaterReporter *self = getReporter(report_type);
if (self)
{
self->mScreenID = uuid;
llinfos << "Got screen shot " << uuid << llendl;
self->sendReportViaLegacy(self->gatherReport());
}
self->close();
}

View File

@ -21,6 +21,7 @@ class LLViewerObject;
class LLAgent;
class LLToolObjPicker;
class LLMeanCollisionData;
struct LLResourceData;
// these flags are used to label info requests to the server
const U32 BUG_REPORT_REQUEST = 0x01 << 0;
@ -51,7 +52,6 @@ enum EReportType
CS_REQUEST_REPORT = 4
};
class LLFloaterReporter
: public LLFloater
{
@ -87,11 +87,16 @@ public:
static void processRegionInfo(LLMessageSystem* msg);
void setPickedObjectProperties(const char *object_name, const char *owner_name);
void uploadScreenshot();
private:
void takeScreenshot();
void sendReportViaCaps(std::string url);
void uploadImage();
bool validateReport();
void setReporterID();
void sendReport();
LLSD gatherReport();
void sendReportViaLegacy(const LLSD & report);
void sendReportViaCaps(std::string url, std::string sshot_url, const LLSD & report);
void setPosBox(const LLVector3d &pos);
void enableControls(BOOL own_avatar);
void getObjectInfo(const LLUUID& object_id);
@ -108,6 +113,7 @@ private:
BOOL mCopyrightWarningSeen;
std::list<LLMeanCollisionData*> mMCDList;
LLString mDefaultSummary;
LLResourceData* mResourceDatap;
};
#endif

View File

@ -163,18 +163,8 @@ BOOL LLFloaterTOS::postBuild()
gResponsePtr = LLIamHere::build( this );
LLHTTPClient::get( childGetValue( "real_url" ).asString(), gResponsePtr );
};
#else
LLTextEditor *Editor = LLUICtrlFactory::getTextEditorByName(this, "tos_text");
if (Editor)
{
Editor->setHandleEditKeysDirectly( TRUE );
Editor->setEnabled( FALSE );
Editor->setReadOnlyFgColor(LLColor4::white);
Editor->setWordWrap(TRUE);
Editor->setFocus(TRUE);
}
childSetValue("tos_text", LLSD(mMessage));
#endif
return TRUE;
}

View File

@ -22,6 +22,7 @@
// newview
#include "llagent.h" // todo: remove
#include "llassetuploadresponders.h"
#include "llbutton.h"
#include "llcheckboxctrl.h"
#include "llcombobox.h"
@ -38,6 +39,7 @@
#include "llviewerinventory.h"
#include "llviewerobject.h"
#include "llviewerobjectlist.h"
#include "llviewerregion.h"
#include "llviewerstats.h"
#include "llviewerwindow.h" // busycount
#include "viewer.h" // gVFS
@ -1101,13 +1103,31 @@ void LLPreviewGesture::saveIfNeeded()
LLInventoryItem* item = getItem();
if (item)
{
LLLineEditor* descEditor = LLUICtrlFactory::getLineEditorByName(this, "desc");
LLSaveInfo* info = new LLSaveInfo(mItemUUID, mObjectUUID, descEditor->getText(), tid);
const BOOL temp_file = FALSE;
gAssetStorage->storeAssetData(tid, LLAssetType::AT_GESTURE, onSaveComplete, info, temp_file);
std::string agent_url = gAgent.getRegion()->getCapability("UpdateGestureAgentInventory");
std::string task_url = gAgent.getRegion()->getCapability("UpdateGestureTaskInventory");
if (mObjectUUID.isNull() && !agent_url.empty())
{
// Saving into agent inventory
LLSD body;
body["item_id"] = mItemUUID;
LLHTTPClient::post(agent_url, body,
new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_GESTURE));
}
else if (!mObjectUUID.isNull() && !task_url.empty())
{
// Saving into task inventory
LLSD body;
body["task_id"] = mObjectUUID;
body["item_id"] = mItemUUID;
LLHTTPClient::post(task_url, body,
new LLUpdateTaskInventoryResponder(body, asset_id, LLAssetType::AT_GESTURE));
}
else if (gAssetStorage)
{
LLLineEditor* descEditor = LLUICtrlFactory::getLineEditorByName(this, "desc");
LLSaveInfo* info = new LLSaveInfo(mItemUUID, mObjectUUID, descEditor->getText(), tid);
gAssetStorage->storeAssetData(tid, LLAssetType::AT_GESTURE, onSaveComplete, info, FALSE);
}
}
// If this gesture is active, then we need to update the in-memory

View File

@ -13,6 +13,7 @@
#include "llinventory.h"
#include "llagent.h"
#include "llassetuploadresponders.h"
#include "llviewerwindow.h"
#include "llbutton.h"
#include "llinventorymodel.h"
@ -219,6 +220,22 @@ const LLInventoryItem* LLPreviewNotecard::getDragItem()
return NULL;
}
bool LLPreviewNotecard::hasEmbeddedInventory()
{
LLViewerTextEditor* editor = NULL;
editor = LLViewerUICtrlFactory::getViewerTextEditorByName(
this,
"Notecard Editor");
if (!editor) return false;
return editor->hasEmbeddedInventory();
}
void LLPreviewNotecard::refreshFromInventory()
{
lldebugs << "LLPreviewNotecard::refreshFromInventory()" << llendl;
loadAsset();
}
void LLPreviewNotecard::loadAsset()
{
// request the asset.
@ -348,7 +365,7 @@ void LLPreviewNotecard::onLoadComplete(LLVFS *vfs,
LLInventoryItem* item = preview->getItem();
BOOL modifiable = item && gAgent.allowOperation(PERM_MODIFY,
item->getPermissions(), GP_OBJECT_MANIPULATE);
previewEditor->setEnabled(modifiable);
preview->setEnabled(modifiable);
delete[] buffer;
preview->mAssetStatus = PREVIEW_ASSET_LOADED;
}
@ -453,14 +470,43 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem)
LLInventoryItem* item = getItem();
// save it out to database
if (item)
{
LLSaveNotecardInfo* info = new LLSaveNotecardInfo(this, mItemUUID, mObjectUUID,
tid, copyitem);
gAssetStorage->storeAssetData(tid, LLAssetType::AT_NOTECARD,
&onSaveComplete,
(void*)info,
FALSE);
{
std::string agent_url = gAgent.getRegion()->getCapability("UpdateNotecardAgentInventory");
std::string task_url = gAgent.getRegion()->getCapability("UpdateNotecardTaskInventory");
if (mObjectUUID.isNull() && !agent_url.empty())
{
// Saving into agent inventory
mAssetStatus = PREVIEW_ASSET_LOADING;
setEnabled(FALSE);
LLSD body;
body["item_id"] = mItemUUID;
llinfos << "Saving notecard " << mItemUUID
<< " into agent inventory via " << agent_url << llendl;
LLHTTPClient::post(agent_url, body,
new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD));
}
else if (!mObjectUUID.isNull() && !task_url.empty())
{
// Saving into task inventory
mAssetStatus = PREVIEW_ASSET_LOADING;
setEnabled(FALSE);
LLSD body;
body["task_id"] = mObjectUUID;
body["item_id"] = mItemUUID;
llinfos << "Saving notecard " << mItemUUID << " into task "
<< mObjectUUID << " via " << task_url << llendl;
LLHTTPClient::post(task_url, body,
new LLUpdateTaskInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD));
}
else if (gAssetStorage)
{
LLSaveNotecardInfo* info = new LLSaveNotecardInfo(this, mItemUUID, mObjectUUID,
tid, copyitem);
gAssetStorage->storeAssetData(tid, LLAssetType::AT_NOTECARD,
&onSaveComplete,
(void*)info,
FALSE);
}
}
}
return true;

View File

@ -50,6 +50,14 @@ public:
const LLInventoryItem* getDragItem();
// return true if there is any embedded inventory.
bool hasEmbeddedInventory();
// After saving a notecard, the tcp based upload system will
// change the asset, therefore, we need to re-fetch it from the
// asset system. :(
void refreshFromInventory();
protected:
virtual void loadAsset();

View File

@ -11,6 +11,7 @@
#include "llpreviewscript.h"
#include "llassetstorage.h"
#include "llassetuploadresponders.h"
#include "llbutton.h"
#include "llcheckboxctrl.h"
#include "llcombobox.h"
@ -832,6 +833,33 @@ LLPreviewLSL::LLPreviewLSL(const std::string& name, const LLRect& rect,
}
}
// virtual
void LLPreviewLSL::callbackLSLCompileSucceeded()
{
llinfos << "LSL Bytecode saved" << llendl;
mScriptEd->mErrorList->addSimpleItem("Compile successful!");
mScriptEd->mErrorList->addSimpleItem("Save complete.");
closeIfNeeded();
}
// virtual
void LLPreviewLSL::callbackLSLCompileFailed(const LLSD& compile_errors)
{
llinfos << "Compile failed!" << llendl;
const LLFontGL* err_font = gResMgr->getRes(LLFONT_OCRA);
LLScrollListItem* item = NULL;
for(LLSD::array_const_iterator line = compile_errors.beginArray();
line < compile_errors.endArray();
line++)
{
item = new LLScrollListItem();
item->addColumn(line->asString(), err_font);
mScriptEd->mErrorList->addItem(item);
}
mScriptEd->selectFirstError();
closeIfNeeded();
}
void LLPreviewLSL::loadAsset()
{
@ -893,6 +921,17 @@ BOOL LLPreviewLSL::canClose()
return mScriptEd->canClose();
}
void LLPreviewLSL::closeIfNeeded()
{
// Find our window and close it if requested.
getWindow()->decBusyCount();
mPendingUploads--;
if (mPendingUploads <= 0 && mCloseAfterSave)
{
close();
}
}
//override the llpreview open which attempts to load asset, load after xml ui made
void LLPreviewLSL::open() /*Flawfinder: ignore*/
{
@ -914,152 +953,152 @@ void LLPreviewLSL::onSave(void* userdata, BOOL close_after_save)
self->saveIfNeeded();
}
// Save needs to compile the text in the buffer. If the compile
// succeeds, then save both assets out to the database. If the compile
// fails, go ahead and save the text anyway so that the user doesn't
// get too fucked.
void LLPreviewLSL::saveIfNeeded()
{
// llinfos << "LLPreviewLSL::save()" << llendl;
if(!mScriptEd->mEditor->isPristine())
// llinfos << "LLPreviewLSL::saveIfNeeded()" << llendl;
if(mScriptEd->mEditor->isPristine())
{
mPendingUploads = 0;
mScriptEd->mErrorList->deleteAllItems();
mScriptEd->mEditor->makePristine();
return;
}
// We need to update the asset information
LLTransactionID tid;
LLAssetID uuid;
tid.generate();
uuid = tid.makeAssetID(gAgent.getSecureSessionID());
char uuid_string[UUID_STR_LENGTH]; /*Flawfinder: ignore*/
uuid.toString(uuid_string);
char filename[LL_MAX_PATH]; /*Flawfinder: ignore*/
snprintf(filename, LL_MAX_PATH, "%s.lsl", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string).c_str()); /*Flawfinder: ignore*/
FILE* fp = LLFile::fopen(filename, "wb"); /*Flawfinder: ignore*/
if(!fp)
mPendingUploads = 0;
mScriptEd->mErrorList->deleteAllItems();
mScriptEd->mEditor->makePristine();
// save off asset into file
LLTransactionID tid;
tid.generate();
LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString());
std::string filename = llformat("%s.lsl", filepath.c_str());
FILE* fp = LLFile::fopen(filename.c_str(), "wb");
if(!fp)
{
llwarns << "Unable to write to " << filename << llendl;
LLScrollListItem* item = new LLScrollListItem();
item->addColumn("Error writing to local file. Is your hard drive full?", LLFontGL::sSansSerifSmall);
mScriptEd->mErrorList->addItem(item);
return;
}
LLString utf8text = mScriptEd->mEditor->getText();
fputs(utf8text.c_str(), fp);
fclose(fp);
fp = NULL;
LLInventoryItem *inv_item = getItem();
// save it out to asset server
std::string url = gAgent.getRegion()->getCapability("UpdateScriptAgentInventory");
if(inv_item)
{
getWindow()->incBusyCount();
mPendingUploads++;
if (!url.empty())
{
llwarns << "Unable to write to " << filename << llendl;
LLScrollListItem* item = new LLScrollListItem();
item->addColumn("Error writing to local file. Is your hard drive full?", LLFontGL::sSansSerifSmall);
mScriptEd->mErrorList->addItem(item);
return;
uploadAssetViaCaps(url, filename, mItemUUID);
}
else if (gAssetStorage)
{
uploadAssetLegacy(filename, mItemUUID, tid);
}
}
}
LLString utf8text = mScriptEd->mEditor->getText();
//fprintf(fp, "%s|%s\n", LLAssetType::lookup(LLAssetType::AT_LSL_TEXT),
//uuid_string);
//fprintf(fp,"{\n%s}\n", text.c_str());
fputs(utf8text.c_str(), fp);
fclose(fp);
fp = NULL;
void LLPreviewLSL::uploadAssetViaCaps(const std::string& url,
const std::string& filename,
const LLUUID& item_id)
{
llinfos << "Update Agent Inventory via capability" << llendl;
LLSD body;
body["item_id"] = item_id;
LLHTTPClient::post(url, body, new LLUpdateAgentInventoryResponder(body, filename));
}
// also write it out to the vfs for upload
LLVFile file(gVFS, uuid, LLAssetType::AT_LSL_TEXT, LLVFile::APPEND);
S32 size = utf8text.length() + 1;
void LLPreviewLSL::uploadAssetLegacy(const std::string& filename,
const LLUUID& item_id,
const LLTransactionID& tid)
{
LLLineEditor* descEditor = LLUICtrlFactory::getLineEditorByName(this, "desc");
LLScriptSaveInfo* info = new LLScriptSaveInfo(item_id,
descEditor->getText(),
tid);
gAssetStorage->storeAssetData(filename.c_str(), tid,
LLAssetType::AT_LSL_TEXT,
&LLPreviewLSL::onSaveComplete,
info);
file.setMaxSize(size);
file.write((U8*)utf8text.c_str(), size);
LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString());
std::string dst_filename = llformat("%s.lso", filepath.c_str());
std::string err_filename = llformat("%s.out", filepath.c_str());
LLInventoryItem *inv_item = getItem();
LLScrollListItem* item = NULL;
const LLFontGL* err_font = gResMgr->getRes(LLFONT_OCRA);
if(!lscript_compile(filename.c_str(),
dst_filename.c_str(),
err_filename.c_str(),
gAgent.isGodlike()))
{
llinfos << "Compile failed!" << llendl;
//char command[256];
//sprintf(command, "type %s\n", err_filename);
//system(command);
// save it out to database
if(gAssetStorage && inv_item)
// load the error file into the error scrolllist
FILE* fp = LLFile::fopen(err_filename.c_str(), "r");
if(fp)
{
char buffer[MAX_STRING]; /*Flawfinder: ignore*/
LLString line;
while(!feof(fp))
{
fgets(buffer, MAX_STRING, fp);
if(feof(fp))
{
break;
}
else if(!buffer)
{
continue;
}
else
{
line.assign(buffer);
LLString::stripNonprintable(line);
item = new LLScrollListItem();
item->addColumn(line, err_font);
mScriptEd->mErrorList->addItem(item);
}
}
fclose(fp);
mScriptEd->selectFirstError();
}
}
else
{
llinfos << "Compile worked!" << llendl;
if(gAssetStorage)
{
getWindow()->incBusyCount();
mPendingUploads++;
LLScriptSaveInfo* info = NULL;
LLLineEditor* descEditor = LLUICtrlFactory::getLineEditorByName(this, "desc");
info = new LLScriptSaveInfo(mItemUUID,
descEditor->getText(),
tid);
gAssetStorage->storeAssetData(tid, LLAssetType::AT_LSL_TEXT, &LLPreviewLSL::onSaveComplete, info);
LLUUID* this_uuid = new LLUUID(mItemUUID);
gAssetStorage->storeAssetData(dst_filename.c_str(),
tid,
LLAssetType::AT_LSL_BYTECODE,
&LLPreviewLSL::onSaveBytecodeComplete,
(void**)this_uuid);
}
char dst_filename[LL_MAX_PATH]; /*Flawfinder: ignore*/
snprintf(dst_filename, LL_MAX_PATH, "%s.lso", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string).c_str()); /*Flawfinder: ignore*/
char err_filename[LL_MAX_PATH]; /*Flawfinder: ignore*/
snprintf(err_filename, LL_MAX_PATH, "%s.out", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string).c_str()); /*Flawfinder: ignore*/
LLScrollListItem* item = NULL;
const LLFontGL* err_font = gResMgr->getRes(LLFONT_OCRA);
if(!lscript_compile(filename, dst_filename, err_filename, gAgent.isGodlike()))
{
llinfos << "Compile failed!" << llendl;
//char command[256];
//sprintf(command, "type %s\n", err_filename);
//system(command);
// load the error file into the error scrolllist
if(NULL != (fp = LLFile::fopen(err_filename, "r"))) /*Flawfinder: ignore*/
{
char buffer[MAX_STRING]; /*Flawfinder: ignore*/
LLString line;
while(!feof(fp))
{
fgets(buffer, MAX_STRING, fp);
if(feof(fp))
{
break;
}
else if(!buffer)
{
continue;
}
else
{
line.assign(buffer);
LLString::stripNonprintable(line);
item = new LLScrollListItem();
item->addColumn(line, err_font);
mScriptEd->mErrorList->addItem(item);
}
}
fclose(fp);
mScriptEd->selectFirstError();
}
}
else
{
llinfos << "Compile worked!" << llendl;
if(gAssetStorage)
{
// move the compiled file into the vfs for transport
FILE* fp = LLFile::fopen(dst_filename, "rb"); /*Flawfinder: ignore*/
LLVFile file(gVFS, uuid, LLAssetType::AT_LSL_BYTECODE, LLVFile::APPEND);
fseek(fp, 0, SEEK_END);
S32 size = ftell(fp);
fseek(fp, 0, SEEK_SET);
file.setMaxSize(size);
const S32 buf_size = 65536;
U8 copy_buf[buf_size];
while ((size = fread(copy_buf, 1, buf_size, fp)))
{
file.write(copy_buf, size);
}
fclose(fp);
fp = NULL;
getWindow()->incBusyCount();
mPendingUploads++;
LLUUID* this_uuid = new LLUUID(mItemUUID);
gAssetStorage->storeAssetData(tid,
LLAssetType::AT_LSL_BYTECODE,
&LLPreviewLSL::onSaveBytecodeComplete,
(void**)this_uuid);
}
}
// get rid of any temp files left lying around
LLFile::remove(filename);
LLFile::remove(err_filename);
LLFile::remove(dst_filename);
}
// get rid of any temp files left lying around
LLFile::remove(filename.c_str());
LLFile::remove(err_filename.c_str());
LLFile::remove(dst_filename.c_str());
}
@ -1333,6 +1372,35 @@ void LLLiveLSLEditor::loadAsset()
loadAsset(FALSE);
}
// virtual
void LLLiveLSLEditor::callbackLSLCompileSucceeded(const LLUUID& task_id,
const LLUUID& item_id,
bool is_script_running)
{
lldebugs << "LSL Bytecode saved" << llendl;
mScriptEd->mErrorList->addSimpleItem("Compile successful!");
mScriptEd->mErrorList->addSimpleItem("Save complete.");
closeIfNeeded();
}
// virtual
void LLLiveLSLEditor::callbackLSLCompileFailed(const LLSD& compile_errors)
{
lldebugs << "Compile failed!" << llendl;
const LLFontGL* err_font = gResMgr->getRes(LLFONT_OCRA);
LLScrollListItem* item = NULL;
for(LLSD::array_const_iterator line = compile_errors.beginArray();
line < compile_errors.endArray();
line++)
{
item = new LLScrollListItem();
item->addColumn(line->asString(), err_font);
mScriptEd->mErrorList->addItem(item);
}
mScriptEd->selectFirstError();
closeIfNeeded();
}
void LLLiveLSLEditor::loadAsset(BOOL is_new)
{
//llinfos << "LLLiveLSLEditor::loadAsset()" << llendl;
@ -1676,18 +1744,16 @@ void LLLiveLSLEditor::saveIfNeeded()
// set up the save on the local machine.
mScriptEd->mEditor->makePristine();
LLTransactionID tid;
LLAssetID uuid;
tid.generate();
uuid = tid.makeAssetID(gAgent.getSecureSessionID());
mItem->setAssetUUID(uuid);
LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString());
std::string filename = llformat("%s.lsl", filepath.c_str());
mItem->setAssetUUID(asset_id);
mItem->setTransactionID(tid);
// write out the data, and store it in the asset database
char uuid_string[UUID_STR_LENGTH]; /*Flawfinder: ignore*/
uuid.toString(uuid_string);
char filename[LL_MAX_PATH]; /*Flawfinder: ignore*/
snprintf(filename, LL_MAX_PATH, "%s.lsl", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string).c_str()); /*Flawfinder: ignore*/
FILE* fp = LLFile::fopen(filename, "wb"); /*Flawfinder: ignore*/
FILE* fp = LLFile::fopen(filename.c_str(), "wb");
if(!fp)
{
llwarns << "Unable to write to " << filename << llendl;
@ -1699,63 +1765,69 @@ void LLLiveLSLEditor::saveIfNeeded()
LLString utf8text = mScriptEd->mEditor->getText();
fputs(utf8text.c_str(), fp);
fclose(fp);
LLCheckBoxCtrl* runningCheckbox = LLUICtrlFactory::getCheckBoxByName(this, "running");
fp = NULL;
// save it out to database
if(gAssetStorage)
// save it out to asset server
std::string url = gAgent.getRegion()->getCapability("UpdateScriptTaskInventory");
getWindow()->incBusyCount();
mPendingUploads++;
BOOL is_running = LLUICtrlFactory::getCheckBoxByName(this, "running")->get();
if (!url.empty())
{
// write it out to the vfs for upload
LLVFile file(gVFS, uuid, LLAssetType::AT_LSL_TEXT, LLVFile::APPEND);
S32 size = utf8text.length() + 1;
file.setMaxSize(size);
file.write((U8*)utf8text.c_str(), size);
getWindow()->incBusyCount();
mPendingUploads++;
LLLiveLSLSaveData* data = new LLLiveLSLSaveData(mObjectID,
mItem,
runningCheckbox->get());
gAssetStorage->storeAssetData(tid, LLAssetType::AT_LSL_TEXT, &onSaveTextComplete, (void*)data, FALSE);
uploadAssetViaCaps(url, filename, mObjectID,
mItemID, is_running);
}
#if LL_WINDOWS
// This major hack was inserted because sometimes compilation
// would fail because it couldn't open this file... I decided
// to make a loop until open was successful. This seems to be
// a problem specific to ntfs.
fp = NULL;
const U32 MAX_TRIES = 20;
U32 tries = MAX_TRIES;
while((!fp) && --tries)
else if (gAssetStorage)
{
ms_sleep(17);
fp = LLFile::fopen(filename, "r"); /*Flawfinder: ignore*/
if(!fp)
{
llwarns << "Trying to open the source file " << filename
<< " again" << llendl;
}
else
{
fclose(fp);
}
uploadAssetLegacy(filename, object, tid, is_running);
}
fp = NULL;
#endif
}
void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url,
const std::string& filename,
const LLUUID& task_id,
const LLUUID& item_id,
BOOL is_running)
{
llinfos << "Update Task Inventory via capability" << llendl;
LLSD body;
body["task_id"] = task_id;
body["item_id"] = item_id;
body["is_script_running"] = is_running;
LLHTTPClient::post(url, body,
new LLUpdateTaskInventoryResponder(body, filename));
}
void LLLiveLSLEditor::uploadAssetLegacy(const std::string& filename,
LLViewerObject* object,
const LLTransactionID& tid,
BOOL is_running)
{
LLLiveLSLSaveData* data = new LLLiveLSLSaveData(mObjectID,
mItem,
is_running);
gAssetStorage->storeAssetData(filename.c_str(), tid,
LLAssetType::AT_LSL_TEXT,
&onSaveTextComplete,
(void*)data,
FALSE);
LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString());
std::string dst_filename = llformat("%s.lso", filepath.c_str());
std::string err_filename = llformat("%s.out", filepath.c_str());
char dst_filename[LL_MAX_PATH]; /*Flawfinder: ignore*/
snprintf(dst_filename, LL_MAX_PATH, "%s.lso", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string).c_str()); /*Flawfinder: ignore*/
char err_filename[LL_MAX_PATH]; /*Flawfinder: ignore*/
snprintf(err_filename, LL_MAX_PATH, "%s.out", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string).c_str()); /*Flawfinder: ignore*/
LLScrollListItem* item = NULL;
const LLFontGL* err_font = gResMgr->getRes(LLFONT_OCRA);
if(!lscript_compile(filename, dst_filename, err_filename, gAgent.isGodlike()))
FILE *fp;
if(!lscript_compile(filename.c_str(),
dst_filename.c_str(),
err_filename.c_str(),
gAgent.isGodlike()))
{
// load the error file into the error scrolllist
llinfos << "Compile failed!" << llendl;
if(NULL != (fp = LLFile::fopen(err_filename, "r"))) /*Flawfinder: ignore*/
if(NULL != (fp = LLFile::fopen(err_filename.c_str(), "r")))
{
char buffer[MAX_STRING]; /*Flawfinder: ignore*/
LLString line;
@ -1797,33 +1869,14 @@ void LLLiveLSLEditor::saveIfNeeded()
{
llinfos << "LLLiveLSLEditor::saveAsset "
<< mItem->getAssetUUID() << llendl;
// move the compiled file into the vfs for transport
FILE* fp = LLFile::fopen(dst_filename, "rb"); /*Flawfinder: ignore*/
LLVFile file(gVFS, uuid, LLAssetType::AT_LSL_BYTECODE, LLVFile::APPEND);
fseek(fp, 0, SEEK_END);
S32 size = ftell(fp);
fseek(fp, 0, SEEK_SET);
file.setMaxSize(size);
const S32 buf_size = 65536;
U8 copy_buf[buf_size];
while ((size = fread(copy_buf, 1, buf_size, fp)))
{
file.write(copy_buf, size);
}
fclose(fp);
fp = NULL;
getWindow()->incBusyCount();
mPendingUploads++;
LLLiveLSLSaveData* data = NULL;
data = new LLLiveLSLSaveData(mObjectID,
mItem,
runningCheckbox->get());
gAssetStorage->storeAssetData(tid,
is_running);
gAssetStorage->storeAssetData(dst_filename.c_str(),
tid,
LLAssetType::AT_LSL_BYTECODE,
&LLLiveLSLEditor::onSaveBytecodeComplete,
(void*)data);
@ -1832,11 +1885,12 @@ void LLLiveLSLEditor::saveIfNeeded()
}
// get rid of any temp files left lying around
LLFile::remove(filename);
LLFile::remove(err_filename);
LLFile::remove(dst_filename);
LLFile::remove(filename.c_str());
LLFile::remove(err_filename.c_str());
LLFile::remove(dst_filename.c_str());
// If we successfully saved it, then we should be able to check/uncheck the running box!
LLCheckBoxCtrl* runningCheckbox = LLUICtrlFactory::getCheckBoxByName(this, "running");
runningCheckbox->setLabel(ENABLED_RUNNING_CHECKBOX_LABEL);
runningCheckbox->setEnabled(TRUE);
}
@ -1912,13 +1966,10 @@ void LLLiveLSLEditor::onSaveBytecodeComplete(const LLUUID& asset_uuid, void* use
args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status));
gViewerWindow->alertXml("CompileQueueSaveBytecode", args);
}
char uuid_string[UUID_STR_LENGTH]; /*Flawfinder: ignore*/
data->mItem->getAssetUUID().toString(uuid_string);
char dst_filename[LL_MAX_PATH]; /*Flawfinder: ignore*/
snprintf(dst_filename, LL_MAX_PATH, "%s.lso", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string).c_str()); /*Flawfinder: ignore*/
LLFile::remove(dst_filename);
snprintf(dst_filename, LL_MAX_PATH, "%s.lsl", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string).c_str()); /*Flawfinder: ignore*/
LLFile::remove(dst_filename);
std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_uuid.asString());
std::string dst_filename = llformat("%s.lso", filepath.c_str());
LLFile::remove(dst_filename.c_str());
delete data;
}
@ -1927,6 +1978,16 @@ BOOL LLLiveLSLEditor::canClose()
return (mScriptEd->canClose());
}
void LLLiveLSLEditor::closeIfNeeded()
{
getWindow()->decBusyCount();
mPendingUploads--;
if (mPendingUploads <= 0 && mCloseAfterSave)
{
close();
}
}
// static
void LLLiveLSLEditor::onLoad(void* userdata)
{
@ -1970,6 +2031,13 @@ void LLLiveLSLEditor::hide(const LLUUID& script_id, const LLUUID& object_id)
delete instance;
}
}
// static
LLLiveLSLEditor* LLLiveLSLEditor::find(const LLUUID& script_id, const LLUUID& object_id)
{
LLUUID xored_id = script_id ^ object_id;
return sInstances.getIfThere(xored_id);
}
// static
void LLLiveLSLEditor::processScriptRunningReply(LLMessageSystem* msg, void**)

View File

@ -116,15 +116,24 @@ class LLPreviewLSL : public LLPreview
public:
LLPreviewLSL(const std::string& name, const LLRect& rect, const std::string& title,
const LLUUID& item_uuid );
virtual void callbackLSLCompileSucceeded();
virtual void callbackLSLCompileFailed(const LLSD& compile_errors);
/*virtual*/ void open(); /*Flawfinder: ignore*/
protected:
virtual BOOL canClose();
void closeIfNeeded();
virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
virtual void loadAsset();
void saveIfNeeded();
void uploadAssetViaCaps(const std::string& url,
const std::string& filename,
const LLUUID& item_id);
void uploadAssetLegacy(const std::string& filename,
const LLUUID& item_id,
const LLTransactionID& tid);
static void onLoad(void* userdata);
static void onSave(void* userdata, BOOL close_after_save);
@ -158,17 +167,33 @@ public:
static LLLiveLSLEditor* show(const LLUUID& item_id, const LLUUID& object_id);
static void hide(const LLUUID& item_id, const LLUUID& object_id);
static LLLiveLSLEditor* find(const LLUUID& item_id, const LLUUID& object_id);
static void processScriptRunningReply(LLMessageSystem* msg, void**);
virtual void callbackLSLCompileSucceeded(const LLUUID& task_id,
const LLUUID& item_id,
bool is_script_running);
virtual void callbackLSLCompileFailed(const LLSD& compile_errors);
protected:
virtual BOOL canClose();
void closeIfNeeded();
virtual void draw();
virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
virtual void loadAsset();
void loadAsset(BOOL is_new);
void saveIfNeeded();
void uploadAssetViaCaps(const std::string& url,
const std::string& filename,
const LLUUID& task_id,
const LLUUID& item_id,
BOOL is_running);
void uploadAssetLegacy(const std::string& filename,
LLViewerObject* object,
const LLTransactionID& tid,
BOOL is_running);
static void onLoad(void* userdata);
static void onSave(void* userdata, BOOL close_after_save);

View File

@ -833,6 +833,7 @@ BOOL idle_startup()
case USERSERVER_SHAKTI:
case USERSERVER_DURGA:
case USERSERVER_SOMA:
case USERSERVER_VAAK:
case USERSERVER_GANGA:
case USERSERVER_UMA:
{
@ -2557,6 +2558,7 @@ void login_show()
LLPanelLogin::addServer( gUserServerDomainName[USERSERVER_GANGA].mLabel, USERSERVER_GANGA );
LLPanelLogin::addServer( gUserServerDomainName[USERSERVER_UMA].mLabel, USERSERVER_UMA );
LLPanelLogin::addServer( gUserServerDomainName[USERSERVER_SOMA].mLabel, USERSERVER_SOMA );
LLPanelLogin::addServer( gUserServerDomainName[USERSERVER_VAAK].mLabel, USERSERVER_VAAK );
}
// Callback for when login screen is closed. Option 0 = connect, option 1 = quit.

View File

@ -273,6 +273,7 @@ BOOL enable_save_as(void *);
// Edit menu
void handle_dump_group_info(void *);
void handle_dump_capabilities_info(void *);
void handle_dump_focus(void*);
void handle_region_dump_settings(void*);
@ -716,6 +717,8 @@ void init_client_menu(LLMenuGL* menu)
&handle_region_dump_settings, NULL));
sub->append(new LLMenuItemCallGL("Group Info to Debug Console",
&handle_dump_group_info, NULL, NULL));
sub->append(new LLMenuItemCallGL("Capabilities Info to Debug Console",
&handle_dump_capabilities_info, NULL, NULL));
sub->createJumpKeys();
}
@ -2451,6 +2454,14 @@ void handle_dump_group_info(void *)
//llinfos << "insig " << gAgent.mGroupInsigniaID << llendl;
}
void handle_dump_capabilities_info(void *)
{
LLViewerRegion* regionp = gAgent.getRegion();
if (regionp)
{
regionp->logActiveCapabilities();
}
}
void handle_dump_focus(void *)
{
@ -5689,7 +5700,7 @@ void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ty
llinfos << "Desc: " << desc << llendl;
lldebugs << "Folder: " << gInventory.findCategoryUUIDForType(destination_folder_type) << llendl;
lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl;
std::string url = gAgent.getRegion()->getCapability("NewAgentInventory");
std::string url = gAgent.getRegion()->getCapability("NewFileAgentInventory");
if (!url.empty())
{
llinfos << "New Agent Inventory via capability" << llendl;
@ -5703,7 +5714,7 @@ void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ty
std::ostringstream llsdxml;
LLSDSerialize::toXML(body, llsdxml);
lldebugs << "posting body to capability: " << llsdxml.str() << llendl;
LLHTTPClient::post(url, body, new LLNewAgentInventoryResponder(uuid, body));
LLHTTPClient::post(url, body, new LLNewAgentInventoryResponder(body, uuid, asset_type));
}
else
{

View File

@ -46,6 +46,10 @@ LLUserServerData gUserServerDomainName[USERSERVER_COUNT] =
"userserver.ganga.lindenlab.com",
"https://login.ganga.lindenlab.com/cgi-bin/login.cgi",
"http://ganga-secondlife.webdev.lindenlab.com/helpers/" },
{ "Vaak",
"userserver.vaak.lindenlab.com",
"https://login.vaak.lindenlab.com/cgi-bin/login.cgi",
"http://vaak-secondlife.webdev.lindenlab.com/helpers/" },
{ "Uma",
"userserver.uma.lindenlab.com",
"https://login.uma.lindenlab.com/cgi-bin/login.cgi",

View File

@ -23,6 +23,7 @@ enum EUserServerDomain
USERSERVER_SHAKTI,
USERSERVER_SOMA,
USERSERVER_GANGA,
USERSERVER_VAAK,
USERSERVER_UMA,
USERSERVER_LOCAL,
USERSERVER_OTHER, // IP address set via -user or other command line option

View File

@ -2323,41 +2323,45 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)
LLUUID task_id;
msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_TaskID, task_id);
LLViewerObject* object = gObjectList.findObject(task_id);
if(object)
if(!object)
{
msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, object->mInventorySerialNum);
LLFilenameAndTask* ft = new LLFilenameAndTask;
ft->mTaskID = task_id;
msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, MAX_STRING, ft->mFilename);
if(!ft->mFilename[0])
{
lldebugs << "Task has no inventory" << llendl;
// mock up some inventory to make a drop target.
if(object->mInventory)
{
object->mInventory->clear(); // will deref and delete it
}
else
{
object->mInventory = new InventoryObjectList();
}
LLPointer<LLInventoryObject> obj;
obj = new LLInventoryObject(object->mID, LLUUID::null,
LLAssetType::AT_CATEGORY,
"Contents");
object->mInventory->push_front(obj);
object->doInventoryCallback();
delete ft;
return;
}
gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename).c_str(),
ft->mFilename, LL_PATH_CACHE,
object->mRegionp->getHost(),
TRUE,
&LLViewerObject::processTaskInvFile,
(void**)ft,
LLXferManager::HIGH_PRIORITY);
llwarns << "LLViewerObject::processTaskInv object "
<< task_id << " does not exist." << llendl;
return;
}
msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, object->mInventorySerialNum);
LLFilenameAndTask* ft = new LLFilenameAndTask;
ft->mTaskID = task_id;
msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, MAX_STRING, ft->mFilename);
if(!ft->mFilename[0])
{
lldebugs << "Task has no inventory" << llendl;
// mock up some inventory to make a drop target.
if(object->mInventory)
{
object->mInventory->clear(); // will deref and delete it
}
else
{
object->mInventory = new InventoryObjectList();
}
LLPointer<LLInventoryObject> obj;
obj = new LLInventoryObject(object->mID, LLUUID::null,
LLAssetType::AT_CATEGORY,
"Contents");
object->mInventory->push_front(obj);
object->doInventoryCallback();
delete ft;
return;
}
gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename).c_str(),
ft->mFilename, LL_PATH_CACHE,
object->mRegionp->getHost(),
TRUE,
&LLViewerObject::processTaskInvFile,
(void**)ft,
LLXferManager::HIGH_PRIORITY);
}
void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code)
@ -2582,6 +2586,18 @@ LLViewerInventoryItem* LLViewerObject::getInventoryItemByAsset(const LLUUID& ass
return rv;
}
void LLViewerObject::updateViewerInventoryAsset(
const LLViewerInventoryItem* item,
const LLUUID& new_asset)
{
LLPointer<LLViewerInventoryItem> task_item =
new LLViewerInventoryItem(item);
task_item->setAssetUUID(new_asset);
// do the internal logic
doUpdateInventory(task_item, TASK_INVENTORY_ITEM_KEY, false);
}
void LLViewerObject::setPixelAreaAndAngle(LLAgent &agent)
{
if (getVolume())

View File

@ -363,6 +363,11 @@ public:
LLViewerInventoryItem* getInventoryItemByAsset(const LLUUID& asset_id);
S16 getInventorySerial() const { return mInventorySerialNum; }
// These functions does viewer-side only object inventory modifications
void updateViewerInventoryAsset(
const LLViewerInventoryItem* item,
const LLUUID& new_asset);
// This function will make sure that we refresh the inventory.
void dirtyInventory();
BOOL isInventoryDirty() { return mInventoryDirty; }

View File

@ -1260,8 +1260,19 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
LLSD capabilityNames = LLSD::emptyArray();
capabilityNames.append("MapLayer");
capabilityNames.append("MapLayerGod");
capabilityNames.append("NewAgentInventory");
capabilityNames.append("NewFileAgentInventory");
capabilityNames.append("EventQueueGet");
capabilityNames.append("UpdateGestureAgentInventory");
capabilityNames.append("UpdateNotecardAgentInventory");
capabilityNames.append("UpdateScriptAgentInventory");
capabilityNames.append("UpdateGestureTaskInventory");
capabilityNames.append("UpdateNotecardTaskInventory");
capabilityNames.append("UpdateScriptTaskInventory");
capabilityNames.append("SendPostcard");
capabilityNames.append("ViewerStartAuction");
capabilityNames.append("ParcelGodReserveForNewbie");
capabilityNames.append("SendUserReport");
capabilityNames.append("SendUserReportWithScreenshot");
capabilityNames.append("RequestTextureDownload");
LLHTTPClient::post(url, capabilityNames, BaseCapabilitiesComplete::build(this));
}
@ -1304,3 +1315,16 @@ std::string LLViewerRegion::getCapability(const std::string& name) const
return iter->second;
}
void LLViewerRegion::logActiveCapabilities() const
{
CapabilityMap::const_iterator iter;
for (iter = mCapabilities.begin(); iter != mCapabilities.end(); iter++)
{
if (!iter->second.empty())
{
// llinfos << "Active capability is " << iter->first << llendl;
llinfos << iter->first << " URL is " << iter->second << llendl;
}
}
}

View File

@ -169,6 +169,7 @@ public:
void setSeedCapability(const std::string& url);
void setCapability(const std::string& name, const std::string& url);
std::string getCapability(const std::string& name) const;
void logActiveCapabilities() const;
const LLHost &getHost() const { return mHost; }
const U64 &getHandle() const { return mHandle; }

View File

@ -53,6 +53,9 @@ public:
LLEmbeddedItems(const LLViewerTextEditor* editor);
~LLEmbeddedItems();
void clear();
// return true if there are no embedded items.
bool empty();
void bindEmbeddedChars(const LLFontGL* font);
void unbindEmbeddedChars(const LLFontGL* font);
@ -115,6 +118,13 @@ void LLEmbeddedItems::clear()
removeEmbeddedItem(*nextiter);
}
mEmbeddedUsedChars.clear();
mEmbeddedIndexedChars.clear();
}
bool LLEmbeddedItems::empty()
{
removeUnusedChars();
return mEmbeddedUsedChars.empty();
}
// Inserts a new unique entry
@ -1367,10 +1377,11 @@ S32 LLViewerTextEditor::insertEmbeddedItem( S32 pos, LLInventoryItem* item )
bool LLViewerTextEditor::importStream(std::istream& str)
{
LLNotecard nc(MAX_NOTECARD_SIZE);
LLNotecard nc(LLNotecard::MAX_SIZE);
bool success = nc.importStream(str);
if (success)
{
mEmbeddedItemList->clear();
const std::vector<LLPointer<LLInventoryItem> >& items = nc.getItems();
mEmbeddedItemList->addItems(items);
// Actually set the text
@ -1396,6 +1407,11 @@ void LLViewerTextEditor::copyInventory(LLInventoryItem* item)
item);
}
bool LLViewerTextEditor::hasEmbeddedInventory()
{
return (!(mEmbeddedItemList->empty()));
}
////////////////////////////////////////////////////////////////////////////
BOOL LLViewerTextEditor::importBuffer( const LLString& buffer )
@ -1406,7 +1422,7 @@ BOOL LLViewerTextEditor::importBuffer( const LLString& buffer )
BOOL LLViewerTextEditor::exportBuffer( LLString& buffer )
{
LLNotecard nc(MAX_NOTECARD_SIZE);
LLNotecard nc(LLNotecard::MAX_SIZE);
std::vector<LLPointer<LLInventoryItem> > embedded_items;
mEmbeddedItemList->getEmbeddedItemList(embedded_items);

View File

@ -67,7 +67,14 @@ public:
// If this starts a line, you need to prepend a newline.
void copyInventory(LLInventoryItem* item);
// returns true if there is embedded inventory.
// *HACK: This is only useful because the notecard verifier may
// change the asset if there is embedded inventory. This mechanism
// should be changed to get a different asset id from the verifier
// rather than checking if a re-load is necessary. Phoenix 2007-02-27
bool hasEmbeddedInventory();
protected:
// Embedded object operations
virtual llwchar pasteEmbeddedItem(llwchar ext_char);

View File

@ -15,11 +15,13 @@
#include "llquantize.h"
#include "llagent.h"
#include "llassetuploadresponders.h"
#include "llviewerwindow.h"
#include "llfloatercustomize.h"
#include "llinventorymodel.h"
#include "llviewerimagelist.h"
#include "llviewerinventory.h"
#include "llviewerregion.h"
#include "llvoavatar.h"
#include "llwearable.h"
@ -886,11 +888,28 @@ void LLWearable::saveNewAsset()
// save it out to database
if( gAssetStorage )
{
LLWearableSaveData* data = new LLWearableSaveData;
data->mType = mType;
gAssetStorage->storeAssetData(filename, mTransactionID, getAssetType(),
&LLWearable::onSaveNewAssetComplete,
(void*)data);
/*
std::string url = gAgent.getRegion()->getCapability("NewAgentInventory");
if (!url.empty())
{
llinfos << "Update Agent Inventory via capability" << llendl;
LLSD body;
body["folder_id"] = gInventory.findCategoryUUIDForType(getAssetType());
body["asset_type"] = LLAssetType::lookup(getAssetType());
body["inventory_type"] = LLInventoryType::lookup(LLInventoryType::IT_WEARABLE);
body["name"] = getName();
body["description"] = getDescription();
LLHTTPClient::post(url, body, new LLNewAgentInventoryResponder(body, filename));
}
else
{
}
*/
LLWearableSaveData* data = new LLWearableSaveData;
data->mType = mType;
gAssetStorage->storeAssetData(filename, mTransactionID, getAssetType(),
&LLWearable::onSaveNewAssetComplete,
(void*)data);
}
}

View File

@ -324,12 +324,15 @@ class DarwinManifest(ViewerManifest):
volpath = re.search('HFS\s+(.+)', hdi_output).group(1).strip()
# Copy everything in to the mounted .dmg
for s,d in {self.get_dst_prefix():("Second Life " + self.args['grid']).strip()+ ".app",
"lsl_guide.html":"Linden Scripting Language Guide.html",
"releasenotes.txt":"Release Notes.txt",
"installers/darwin/mac_image_hidden":".hidden",
"installers/darwin/mac_image_background.tga":"background.tga",
"installers/darwin/mac_image_DS_Store":".DS_Store"}.items():
# TODO change name of .app once mac_updater can handle it.
for s,d in {
self.get_dst_prefix():"Second Life.app",
"lsl_guide.html":"Linden Scripting Language Guide.html",
"releasenotes.txt":"Release Notes.txt",
"installers/darwin/mac_image_hidden":".hidden",
"installers/darwin/mac_image_background.tga":"background.tga",
"installers/darwin/mac_image_DS_Store":".DS_Store"}.items():
print "Copying to dmg", s, d
self.copy_action(self.src_path_of(s), os.path.join(volpath, d))