aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llviewermenufile.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:56 -0500
committerJacek Antonelli2008-08-15 23:44:56 -0500
commitc07901e29ed545bbb02e3bddf148fe1104b94e9f (patch)
treef1ada64ce834acd7d92a425efb96c4b86bcf16b1 /linden/indra/newview/llviewermenufile.cpp
parentSecond Life viewer sources 1.15.0.2 (diff)
downloadmeta-impy-c07901e29ed545bbb02e3bddf148fe1104b94e9f.zip
meta-impy-c07901e29ed545bbb02e3bddf148fe1104b94e9f.tar.gz
meta-impy-c07901e29ed545bbb02e3bddf148fe1104b94e9f.tar.bz2
meta-impy-c07901e29ed545bbb02e3bddf148fe1104b94e9f.tar.xz
Second Life viewer sources 1.15.1.3
Diffstat (limited to 'linden/indra/newview/llviewermenufile.cpp')
-rw-r--r--linden/indra/newview/llviewermenufile.cpp1022
1 files changed, 1022 insertions, 0 deletions
diff --git a/linden/indra/newview/llviewermenufile.cpp b/linden/indra/newview/llviewermenufile.cpp
new file mode 100644
index 0000000..6954b1c
--- /dev/null
+++ b/linden/indra/newview/llviewermenufile.cpp
@@ -0,0 +1,1022 @@
1/**
2 * @file llviewermenufile.cpp
3 * @brief "File" menu in the main menu bar.
4 *
5 * Copyright (c) 2002-2007, Linden Research, Inc.
6 *
7 * Second Life Viewer Source Code
8 * The source code in this file ("Source Code") is provided by Linden Lab
9 * to you under the terms of the GNU General Public License, version 2.0
10 * ("GPL"), unless you have obtained a separate licensing agreement
11 * ("Other License"), formally executed by you and Linden Lab. Terms of
12 * the GPL can be found in doc/GPL-license.txt in this distribution, or
13 * online at http://secondlife.com/developers/opensource/gplv2
14 *
15 * There are special exceptions to the terms and conditions of the GPL as
16 * it is applied to this Source Code. View the full text of the exception
17 * in the file doc/FLOSS-exception.txt in this software distribution, or
18 * online at http://secondlife.com/developers/opensource/flossexception
19 *
20 * By copying, modifying or distributing this software, you acknowledge
21 * that you have read and understood your obligations described above,
22 * and agree to abide by those obligations.
23 *
24 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
25 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
26 * COMPLETENESS OR PERFORMANCE.
27 */
28
29#include "llviewerprecompiledheaders.h"
30
31#include "llviewermenufile.h"
32
33// project includes
34#include "llagent.h"
35#include "llfilepicker.h"
36#include "llfloateranimpreview.h"
37#include "llfloaterbuycurrency.h"
38#include "llfloaterimagepreview.h"
39#include "llfloaterimport.h"
40#include "llfloaternamedesc.h"
41#include "llfloatersnapshot.h"
42#include "llinventorymodel.h" // gInventory
43#include "llresourcedata.h"
44#include "llstatusbar.h"
45#include "llviewercontrol.h" // gSavedSettings
46#include "llviewerimagelist.h"
47#include "llvieweruictrlfactory.h"
48#include "llviewermenu.h" // gMenuHolder
49#include "llviewerregion.h"
50#include "llviewerstats.h"
51#include "llviewerwindow.h"
52#include "viewer.h" // app_request_quit()
53
54// linden libraries
55#include "llassetuploadresponders.h"
56#include "lleconomy.h"
57#include "llhttpclient.h"
58#include "llmemberlistener.h"
59#include "llsdserialize.h"
60#include "llstring.h"
61#include "lltransactiontypes.h"
62#include "lluuid.h"
63#include "vorbisencode.h"
64
65// system libraries
66#include <boost/tokenizer.hpp>
67
68typedef LLMemberListener<LLView> view_listener_t;
69
70
71class LLFileEnableSaveAs : public view_listener_t
72{
73 bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
74 {
75 bool new_value = gFloaterView->getFrontmost() && gFloaterView->getFrontmost()->canSaveAs();
76 gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
77 return true;
78 }
79};
80
81class LLFileEnableUpload : public view_listener_t
82{
83 bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
84 {
85 bool new_value = gStatusBar && gGlobalEconomy && (gStatusBar->getBalance() >= gGlobalEconomy->getPriceUpload());
86 gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
87 return true;
88 }
89};
90
91/**
92 char* upload_pick(void* data)
93
94 If applicable, brings up a file chooser in which the user selects a file
95 to upload for a particular task. If the file is valid for the given action,
96 returns the string to the full path filename, else returns NULL.
97 Data is the load filter for the type of file as defined in LLFilePicker.
98**/
99const char* upload_pick(void* data)
100{
101 if( gAgent.cameraMouselook() )
102 {
103 gAgent.changeCameraToDefault();
104 // This doesn't seem necessary. JC
105 // display();
106 }
107
108 LLFilePicker::ELoadFilter type;
109 if(data)
110 {
111 type = (LLFilePicker::ELoadFilter)((intptr_t)data);
112 }
113 else
114 {
115 type = LLFilePicker::FFLOAD_ALL;
116 }
117
118 LLFilePicker& picker = LLFilePicker::instance();
119 if (!picker.getOpenFile(type))
120 {
121 llinfos << "Couldn't import objects from file" << llendl;
122 return NULL;
123 }
124
125 const char* filename = picker.getFirstFile();
126 const char* ext = strrchr(filename, '.');
127
128 //strincmp doesn't like NULL pointers
129 if (ext == NULL)
130 {
131 const char* short_name = strrchr(filename,
132 *gDirUtilp->getDirDelimiter().c_str());
133
134 // No extension
135 LLStringBase<char>::format_map_t args;
136 args["[FILE]"] = LLString(short_name + 1);
137 gViewerWindow->alertXml("NoFileExtension", args);
138 return NULL;
139 }
140 else
141 {
142 //so there is an extension
143 //loop over the valid extensions and compare to see
144 //if the extension is valid
145
146 //now grab the set of valid file extensions
147 const char* valids = build_extensions_string(type);
148 std::string valid_extensions = std::string(valids);
149
150 BOOL ext_valid = FALSE;
151
152 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
153 boost::char_separator<char> sep(" ");
154 tokenizer tokens(valid_extensions, sep);
155 tokenizer::iterator token_iter;
156
157 //now loop over all valid file extensions
158 //and compare them to the extension of the file
159 //to be uploaded
160 for( token_iter = tokens.begin();
161 token_iter != tokens.end() && ext_valid != TRUE;
162 ++token_iter)
163 {
164 const char* cur_token = token_iter->c_str();
165
166 if (0 == strnicmp(cur_token, ext, strlen(cur_token)) || /* Flawfinder: ignore */
167 0 == strnicmp(cur_token, "*.*", strlen(cur_token))) /* Flawfinder: ignore */
168 {
169 //valid extension
170 //or the acceptable extension is any
171 ext_valid = TRUE;
172 }
173 }//end for (loop over all tokens)
174
175 if (ext_valid == FALSE)
176 {
177 //should only get here if the extension exists
178 //but is invalid
179 LLStringBase<char>::format_map_t args;
180 args["[EXTENSION]"] = ext;
181 args["[VALIDS]"] = valids;
182 gViewerWindow->alertXml("InvalidFileExtension", args);
183 return NULL;
184 }
185 }//end else (non-null extension)
186
187 //valid file extension
188
189 //now we check to see
190 //if the file is actually a valid image/sound/etc.
191 if (type == LLFilePicker::FFLOAD_WAV)
192 {
193 // pre-qualify wavs to make sure the format is acceptable
194 char error_msg[MAX_STRING]; /* Flawfinder: ignore */
195 if (check_for_invalid_wav_formats(filename,error_msg))
196 {
197 llinfos << error_msg << ": " << filename << llendl;
198 LLStringBase<char>::format_map_t args;
199 args["[FILE]"] = filename;
200 gViewerWindow->alertXml( error_msg, args );
201 return NULL;
202 }
203 }//end if a wave/sound file
204
205
206 return filename;
207}
208
209void handle_upload_object(void* data)
210{
211 const char* filename = upload_pick(data);
212 if (filename)
213 {
214 // start the import
215 LLFloaterImport* floaterp = new LLFloaterImport(filename);
216 gUICtrlFactory->buildFloater(floaterp, "floater_import.xml");
217 }
218}
219
220class LLFileUploadImage : public view_listener_t
221{
222 bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
223 {
224 const char* filename = upload_pick((void *)(S32)LLFilePicker::FFLOAD_IMAGE);
225 if (filename)
226 {
227 LLFloaterImagePreview* floaterp = new LLFloaterImagePreview(filename);
228 gUICtrlFactory->buildFloater(floaterp, "floater_image_preview.xml");
229 }
230 return TRUE;
231 }
232};
233
234class LLFileUploadSound : public view_listener_t
235{
236 bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
237 {
238 const char* filename = upload_pick((void*)((S32)LLFilePicker::FFLOAD_WAV));
239 if (filename)
240 {
241 LLFloaterNameDesc* floaterp = new LLFloaterNameDesc(filename);
242 gUICtrlFactory->buildFloater(floaterp, "floater_sound_preview.xml");
243 }
244 return true;
245 }
246};
247
248class LLFileUploadAnim : public view_listener_t
249{
250 bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
251 {
252 const char* filename = upload_pick((void*)((S32)LLFilePicker::FFLOAD_ANIM));
253 if (filename)
254 {
255 LLFloaterAnimPreview* floaterp = new LLFloaterAnimPreview(filename);
256 gUICtrlFactory->buildFloater(floaterp, "floater_animation_preview.xml");
257 }
258 return true;
259 }
260};
261
262class LLFileUploadBulk : public view_listener_t
263{
264 bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
265 {
266 if( gAgent.cameraMouselook() )
267 {
268 gAgent.changeCameraToDefault();
269 }
270
271 // TODO:
272 // Iterate over all files
273 // Check extensions for uploadability, cost
274 // Check user balance for entire cost
275 // Charge user entire cost
276 // Loop, uploading
277 // If an upload fails, refund the user for that one
278 //
279 // Also fix single upload to charge first, then refund
280
281 LLFilePicker& picker = LLFilePicker::instance();
282 if (picker.getMultipleOpenFiles())
283 {
284 const char* filename = picker.getFirstFile();
285 const char* name = picker.getDirname();
286
287 LLString asset_name = name;
288 LLString::replaceNonstandardASCII( asset_name, '?' );
289 LLString::replaceChar(asset_name, '|', '?');
290 LLString::stripNonprintable(asset_name);
291 LLString::trim(asset_name);
292
293 char* asset_name_str = (char*)asset_name.c_str();
294 char* end_p = strrchr(asset_name_str, '.'); // strip extension if exists
295 if( !end_p )
296 {
297 end_p = asset_name_str + strlen( asset_name_str ); /* Flawfinder: ignore */
298 }
299
300 S32 len = llmin( (S32) (DB_INV_ITEM_NAME_STR_LEN), (S32) (end_p - asset_name_str) );
301
302 asset_name = asset_name.substr( 0, len );
303
304 upload_new_resource(filename, asset_name, asset_name, 0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE); // file
305 }
306 else
307 {
308 llinfos << "Couldn't import objects from file" << llendl;
309 }
310 return true;
311 }
312};
313
314void upload_error(const char* error_message, const char* label, const std::string filename, const LLStringBase<char>::format_map_t args)
315{
316 llwarns << error_message << llendl;
317 gViewerWindow->alertXml(label, args);
318 if(remove(filename.c_str()) == -1)
319 {
320 lldebugs << "unable to remove temp file" << llendl;
321 }
322 LLFilePicker::instance().reset();
323}
324
325class LLFileEnableCloseWindow : public view_listener_t
326{
327 bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
328 {
329 bool new_value = gFloaterView->getFocusedFloater() != NULL || gSnapshotFloaterView->getFocusedFloater() != NULL;
330 // horrendously opaque, this code
331 gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
332 return true;
333 }
334};
335
336class LLFileCloseWindow : public view_listener_t
337{
338 bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
339 {
340 LLFloater::closeFocusedFloater();
341
342 return true;
343 }
344};
345
346class LLFileCloseAllWindows : public view_listener_t
347{
348 bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
349 {
350 bool app_quitting = false;
351 gFloaterView->closeAllChildren(app_quitting);
352
353 return true;
354 }
355};
356
357class LLFileSaveTexture : public view_listener_t
358{
359 bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
360 {
361 LLFloater* top = gFloaterView->getFrontmost();
362 if (top)
363 {
364 top->saveAs();
365 }
366 return true;
367 }
368};
369
370class LLFileTakeSnapshot : public view_listener_t
371{
372 bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
373 {
374 LLFloaterSnapshot::show(NULL);
375 return true;
376 }
377};
378
379class LLFileTakeSnapshotToDisk : public view_listener_t
380{
381 bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
382 {
383 LLPointer<LLImageRaw> raw = new LLImageRaw;
384
385 S32 width = gViewerWindow->getWindowDisplayWidth();
386 S32 height = gViewerWindow->getWindowDisplayHeight();
387
388 if (gSavedSettings.getBOOL("HighResSnapshot"))
389 {
390 width *= 2;
391 height *= 2;
392 }
393
394 if (gViewerWindow->rawSnapshot(raw,
395 width,
396 height,
397 TRUE,
398 gSavedSettings.getBOOL("RenderUIInSnapshot"),
399 FALSE))
400 {
401 if (!gQuietSnapshot)
402 {
403 gViewerWindow->playSnapshotAnimAndSound();
404 }
405 LLImageBase::setSizeOverride(TRUE);
406 gViewerWindow->saveImageNumbered(raw);
407 LLImageBase::setSizeOverride(FALSE);
408 }
409 return true;
410 }
411};
412
413class LLFileSaveMovie : public view_listener_t
414{
415 bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
416 {
417 LLViewerWindow::saveMovieNumbered(NULL);
418 return true;
419 }
420};
421
422class LLFileSetWindowSize : public view_listener_t
423{
424 bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
425 {
426 LLString size = userdata.asString();
427 S32 width, height;
428 sscanf(size.c_str(), "%d,%d", &width, &height);
429 LLViewerWindow::movieSize(width, height);
430 return true;
431 }
432};
433
434class LLFileQuit : public view_listener_t
435{
436 bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
437 {
438 app_request_quit();
439 return true;
440 }
441};
442
443void handle_upload(void* data)
444{
445 const char* filename = upload_pick(data);
446 if (filename)
447 {
448 LLFloaterNameDesc* floaterp = new LLFloaterNameDesc(filename);
449 gUICtrlFactory->buildFloater(floaterp, "floater_name_description.xml");
450 }
451}
452
453void handle_compress_image(void*)
454{
455 LLFilePicker& picker = LLFilePicker::instance();
456 if (picker.getOpenFile(LLFilePicker::FFLOAD_IMAGE))
457 {
458 std::string infile(picker.getFirstFile());
459 std::string outfile = infile + ".j2c";
460
461 llinfos << "Input: " << infile << llendl;
462 llinfos << "Output: " << outfile << llendl;
463
464 BOOL success;
465
466 success = LLViewerImageList::createUploadFile(infile, outfile, IMG_CODEC_TGA);
467
468 if (success)
469 {
470 llinfos << "Compression complete" << llendl;
471 }
472 else
473 {
474 llinfos << "Compression failed: " << LLImageBase::getLastError() << llendl;
475 }
476 }
477}
478
479void upload_new_resource(const LLString& src_filename, std::string name,
480 std::string desc, S32 compression_info,
481 LLAssetType::EType destination_folder_type,
482 LLInventoryType::EType inv_type,
483 U32 next_owner_perm,
484 const LLString& display_name,
485 LLAssetStorage::LLStoreAssetCallback callback,
486 void *userdata)
487{
488 // Generate the temporary UUID.
489 LLString filename = gDirUtilp->getTempFilename();
490 LLTransactionID tid;
491 LLAssetID uuid;
492
493 LLStringBase<char>::format_map_t args;
494
495 LLString ext = src_filename.substr(src_filename.find_last_of('.'));
496 LLAssetType::EType asset_type = LLAssetType::AT_NONE;
497 char error_message[MAX_STRING]; /* Flawfinder: ignore */
498 error_message[0] = '\0';
499 LLString temp_str;
500
501 BOOL error = FALSE;
502
503 if (ext.empty())
504 {
505 LLString::size_type offset = filename.find_last_of(gDirUtilp->getDirDelimiter());
506 if (offset != LLString::npos)
507 offset++;
508 LLString short_name = filename.substr(offset);
509
510 // No extension
511 snprintf(error_message, /* Flawfinder: ignore */
512 MAX_STRING,
513 "No file extension for the file: '%s'\nPlease make sure the file has a correct file extension",
514 short_name.c_str());
515 args["[FILE]"] = short_name;
516 upload_error(error_message, "NofileExtension", filename, args);
517 return;
518 }
519 else if( LLString::compareInsensitive(ext.c_str(),".bmp") == 0 )
520 {
521 asset_type = LLAssetType::AT_TEXTURE;
522 if (!LLViewerImageList::createUploadFile(src_filename,
523 filename,
524 IMG_CODEC_BMP ))
525 {
526 snprintf(error_message, MAX_STRING, "Problem with file %s:\n\n%s\n", /* Flawfinder: ignore */
527 src_filename.c_str(), LLImageBase::getLastError().c_str());
528 args["[FILE]"] = src_filename;
529 args["[ERROR]"] = LLImageBase::getLastError();
530 upload_error(error_message, "ProblemWithFile", filename, args);
531 return;
532 }
533 }
534 else if( LLString::compareInsensitive(ext.c_str(),".tga") == 0 )
535 {
536 asset_type = LLAssetType::AT_TEXTURE;
537 if (!LLViewerImageList::createUploadFile(src_filename,
538 filename,
539 IMG_CODEC_TGA ))
540 {
541 snprintf(error_message, MAX_STRING, "Problem with file %s:\n\n%s\n", /* Flawfinder: ignore */
542 src_filename.c_str(), LLImageBase::getLastError().c_str());
543 args["[FILE]"] = src_filename;
544 args["[ERROR]"] = LLImageBase::getLastError();
545 upload_error(error_message, "ProblemWithFile", filename, args);
546 return;
547 }
548 }
549 else if( LLString::compareInsensitive(ext.c_str(),".jpg") == 0 || LLString::compareInsensitive(ext.c_str(),".jpeg") == 0)
550 {
551 asset_type = LLAssetType::AT_TEXTURE;
552 if (!LLViewerImageList::createUploadFile(src_filename,
553 filename,
554 IMG_CODEC_JPEG ))
555 {
556 snprintf(error_message, MAX_STRING, "Problem with file %s:\n\n%s\n", /* Flawfinder: ignore */
557 src_filename.c_str(), LLImageBase::getLastError().c_str());
558 args["[FILE]"] = src_filename;
559 args["[ERROR]"] = LLImageBase::getLastError();
560 upload_error(error_message, "ProblemWithFile", filename, args);
561 return;
562 }
563 }
564 else if(LLString::compareInsensitive(ext.c_str(),".wav") == 0)
565 {
566 asset_type = LLAssetType::AT_SOUND; // tag it as audio
567 S32 encode_result = 0;
568
569 S32 bitrate = 128;
570
571 if (compression_info)
572 {
573 bitrate = compression_info;
574 }
575 llinfos << "Attempting to encode wav as an ogg file at " << bitrate << "kbps" << llendl;
576
577 encode_result = encode_vorbis_file_at(src_filename.c_str(), filename.c_str(), bitrate*1000);
578
579 if (LLVORBISENC_NOERR != encode_result)
580 {
581 switch(encode_result)
582 {
583 case LLVORBISENC_DEST_OPEN_ERR:
584 snprintf(error_message, MAX_STRING, "Couldn't open temporary compressed sound file for writing: %s\n", filename.c_str()); /* Flawfinder: ignore */
585 args["[FILE]"] = filename;
586 upload_error(error_message, "CannotOpenTemporarySoundFile", filename, args);
587 break;
588
589 default:
590 snprintf(error_message, MAX_STRING, "Unknown vorbis encode failure on: %s\n", src_filename.c_str()); /* Flawfinder: ignore */
591 args["[FILE]"] = src_filename;
592 upload_error(error_message, "UnknownVorbisEncodeFailure", filename, args);
593 break;
594 }
595 return;
596 }
597 }
598 else if(LLString::compareInsensitive(ext.c_str(),".tmp") == 0)
599 {
600 // This is a generic .lin resource file
601 asset_type = LLAssetType::AT_OBJECT;
602 FILE* in = LLFile::fopen(src_filename.c_str(), "rb"); /* Flawfinder: ignore */
603 if (in)
604 {
605 // read in the file header
606 char buf[16384]; /* Flawfinder: ignore */
607 S32 read; /* Flawfinder: ignore */
608 S32 version;
609 if (fscanf(in, "LindenResource\nversion %d\n", &version))
610 {
611 if (2 == version)
612 {
613 // *NOTE: This buffer size is hard coded into scanf() below.
614 char label[MAX_STRING]; /* Flawfinder: ignore */
615 char value[MAX_STRING]; /* Flawfinder: ignore */
616 S32 tokens_read;
617 while (fgets(buf, 1024, in))
618 {
619 label[0] = '\0';
620 value[0] = '\0';
621 tokens_read = sscanf( /* Flawfinder: ignore */
622 buf,
623 "%254s %254s\n",
624 label, value);
625
626 llinfos << "got: " << label << " = " << value
627 << llendl;
628
629 if (EOF == tokens_read)
630 {
631 fclose(in);
632 snprintf(error_message, MAX_STRING, "corrupt resource file: %s", src_filename.c_str()); /* Flawfinder: ignore */
633 args["[FILE]"] = src_filename;
634 upload_error(error_message, "CorruptResourceFile", filename, args);
635 return;
636 }
637
638 if (2 == tokens_read)
639 {
640 if (! strcmp("type", label))
641 {
642 asset_type = (LLAssetType::EType)(atoi(value));
643 }
644 }
645 else
646 {
647 if (! strcmp("_DATA_", label))
648 {
649 // below is the data section
650 break;
651 }
652 }
653 // other values are currently discarded
654 }
655
656 }
657 else
658 {
659 fclose(in);
660 snprintf(error_message, MAX_STRING, "unknown linden resource file version in file: %s", src_filename.c_str()); /* Flawfinder: ignore */
661 args["[FILE]"] = src_filename;
662 upload_error(error_message, "UnknownResourceFileVersion", filename, args);
663 return;
664 }
665 }
666 else
667 {
668 // this is an original binary formatted .lin file
669 // start over at the beginning of the file
670 fseek(in, 0, SEEK_SET);
671
672 const S32 MAX_ASSET_DESCRIPTION_LENGTH = 256;
673 const S32 MAX_ASSET_NAME_LENGTH = 64;
674 S32 header_size = 34 + MAX_ASSET_DESCRIPTION_LENGTH + MAX_ASSET_NAME_LENGTH;
675 S16 type_num;
676
677 // read in and throw out most of the header except for the type
678 fread(buf, header_size, 1, in);
679 memcpy(&type_num, buf + 16, sizeof(S16)); /* Flawfinder: ignore */
680 asset_type = (LLAssetType::EType)type_num;
681 }
682
683 // copy the file's data segment into another file for uploading
684 FILE* out = LLFile::fopen(filename.c_str(), "wb"); /* Flawfinder: ignore */
685 if (out)
686 {
687 while((read = fread(buf, 1, 16384, in))) /* Flawfinder: ignore */
688 {
689 fwrite(buf, 1, read, out); /* Flawfinder: ignore */
690 }
691 fclose(out);
692 }
693 else
694 {
695 fclose(in);
696 snprintf(error_message, MAX_STRING, "Unable to create output file: %s", filename.c_str()); /* Flawfinder: ignore */
697 args["[FILE]"] = filename;
698 upload_error(error_message, "UnableToCreateOutputFile", filename, args);
699 return;
700 }
701
702 fclose(in);
703 }
704 else
705 {
706 llinfos << "Couldn't open .lin file " << src_filename << llendl;
707 }
708 }
709 else if (LLString::compareInsensitive(ext.c_str(),".bvh") == 0)
710 {
711 snprintf(error_message, MAX_STRING, "We do not currently support bulk upload of animation files\n"); /* Flawfinder: ignore */
712 upload_error(error_message, "DoNotSupportBulkAnimationUpload", filename, args);
713 return;
714 }
715 else
716 {
717 // Unknown extension
718 snprintf(error_message, MAX_STRING, "Unknown file extension %s\nExpected .wav, .tga, .bmp, .jpg, .jpeg, or .bvh", ext.c_str()); /* Flawfinder: ignore */
719 error = TRUE;;
720 }
721
722 // gen a new transaction ID for this asset
723 tid.generate();
724
725 if (!error)
726 {
727 uuid = tid.makeAssetID(gAgent.getSecureSessionID());
728 // copy this file into the vfs for upload
729 S32 file_size;
730 apr_file_t* fp = ll_apr_file_open(filename, LL_APR_RB, &file_size);
731 if (fp)
732 {
733 LLVFile file(gVFS, uuid, asset_type, LLVFile::WRITE);
734
735 file.setMaxSize(file_size);
736
737 const S32 buf_size = 65536;
738 U8 copy_buf[buf_size];
739 while ((file_size = ll_apr_file_read(fp, copy_buf, buf_size)))
740 {
741 file.write(copy_buf, file_size);
742 }
743 apr_file_close(fp);
744 }
745 else
746 {
747 snprintf(error_message, MAX_STRING, "Unable to access output file: %s", filename.c_str()); /* Flawfinder: ignore */
748 error = TRUE;
749 }
750 }
751
752 if (!error)
753 {
754 LLString t_disp_name = display_name;
755 if (t_disp_name.empty())
756 {
757 t_disp_name = src_filename;
758 }
759 upload_new_resource(tid, asset_type, name, desc, compression_info, // tid
760 destination_folder_type, inv_type, next_owner_perm,
761 display_name, callback, userdata);
762 }
763 else
764 {
765 llwarns << error_message << llendl;
766 LLStringBase<char>::format_map_t args;
767 args["[ERROR_MESSAGE]"] = error_message;
768 gViewerWindow->alertXml("ErrorMessage", args);
769 if(LLFile::remove(filename.c_str()) == -1)
770 {
771 lldebugs << "unable to remove temp file" << llendl;
772 }
773 LLFilePicker::instance().reset();
774 }
775}
776
777void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result) // StoreAssetData callback (fixed)
778{
779 LLResourceData* data = (LLResourceData*)user_data;
780 //LLAssetType::EType pref_loc = data->mPreferredLocation;
781 BOOL is_balance_sufficient = TRUE;
782 if(result >= 0)
783 {
784 LLAssetType::EType dest_loc = (data->mPreferredLocation == LLAssetType::AT_NONE) ? data->mAssetInfo.mType : data->mPreferredLocation;
785
786 if (LLAssetType::AT_SOUND == data->mAssetInfo.mType ||
787 LLAssetType::AT_TEXTURE == data->mAssetInfo.mType ||
788 LLAssetType::AT_ANIMATION == data->mAssetInfo.mType)
789 {
790 // Charge the user for the upload.
791 LLViewerRegion* region = gAgent.getRegion();
792 S32 upload_cost = gGlobalEconomy->getPriceUpload();
793
794 if(!(can_afford_transaction(upload_cost)))
795 {
796 LLFloaterBuyCurrency::buyCurrency(
797 llformat("Uploading %s costs",
798 data->mAssetInfo.getName().c_str()),
799 upload_cost);
800 is_balance_sufficient = FALSE;
801 }
802 else if(region)
803 {
804 // Charge user for upload
805 gStatusBar->debitBalance(upload_cost);
806
807 LLMessageSystem* msg = gMessageSystem;
808 msg->newMessageFast(_PREHASH_MoneyTransferRequest);
809 msg->nextBlockFast(_PREHASH_AgentData);
810 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
811 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
812 msg->nextBlockFast(_PREHASH_MoneyData);
813 msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID());
814 msg->addUUIDFast(_PREHASH_DestID, LLUUID::null);
815 msg->addU8("Flags", 0);
816 msg->addS32Fast(_PREHASH_Amount, upload_cost);
817 msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY);
818 msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY);
819 msg->addS32Fast(_PREHASH_TransactionType, TRANS_UPLOAD_CHARGE);
820 msg->addStringFast(_PREHASH_Description, NULL);
821 msg->sendReliable(region->getHost());
822 }
823 }
824
825 if(is_balance_sufficient)
826 {
827 // Actually add the upload to inventory
828 llinfos << "Adding " << uuid << " to inventory." << llendl;
829 LLUUID folder_id(gInventory.findCategoryUUIDForType(dest_loc));
830 if(folder_id.notNull())
831 {
832 U32 next_owner_perm = data->mNextOwnerPerm;
833 if(PERM_NONE == next_owner_perm)
834 {
835 next_owner_perm = PERM_MOVE | PERM_TRANSFER;
836 }
837 create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
838 folder_id, data->mAssetInfo.mTransactionID, data->mAssetInfo.getName(),
839 data->mAssetInfo.getDescription(), data->mAssetInfo.mType,
840 data->mInventoryType, NOT_WEARABLE, next_owner_perm,
841 LLPointer<LLInventoryCallback>(NULL));
842 }
843 else
844 {
845 llwarns << "Can't find a folder to put it in" << llendl;
846 }
847 }
848 }
849 else // if(result >= 0)
850 {
851 LLStringBase<char>::format_map_t args;
852 args["[FILE]"] = LLInventoryType::lookupHumanReadable(data->mInventoryType);
853 args["[REASON]"] = LLString(LLAssetStorage::getErrorString(result));
854 gViewerWindow->alertXml("CannotUploadReason", args);
855 }
856
857 LLUploadDialog::modalUploadFinished();
858 delete data;
859
860 // *NOTE: This is a pretty big hack. What this does is check the
861 // file picker if there are any more pending uploads. If so,
862 // upload that file.
863 const char* next_file = LLFilePicker::instance().getNextFile();
864 if(is_balance_sufficient && next_file)
865 {
866 const char* name = LLFilePicker::instance().getDirname();
867
868 LLString asset_name = name;
869 LLString::replaceNonstandardASCII( asset_name, '?' );
870 LLString::replaceChar(asset_name, '|', '?');
871 LLString::stripNonprintable(asset_name);
872 LLString::trim(asset_name);
873
874 char* asset_name_str = (char*)asset_name.c_str();
875 char* end_p = strrchr(asset_name_str, '.'); // strip extension if exists
876 if( !end_p )
877 {
878 end_p = asset_name_str + strlen( asset_name_str ); /* Flawfinder: ignore */
879 }
880
881 S32 len = llmin( (S32) (DB_INV_ITEM_NAME_STR_LEN), (S32) (end_p - asset_name_str) );
882
883 asset_name = asset_name.substr( 0, len );
884
885 upload_new_resource(next_file, asset_name, asset_name, // file
886 0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE);
887 }
888}
889
890void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_type,
891 std::string name,
892 std::string desc, S32 compression_info,
893 LLAssetType::EType destination_folder_type,
894 LLInventoryType::EType inv_type,
895 U32 next_owner_perm,
896 const LLString& display_name,
897 LLAssetStorage::LLStoreAssetCallback callback,
898 void *userdata)
899{
900 LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID());
901
902 if( LLAssetType::AT_SOUND == asset_type )
903 {
904 gViewerStats->incStat(LLViewerStats::ST_UPLOAD_SOUND_COUNT );
905 }
906 else
907 if( LLAssetType::AT_TEXTURE == asset_type )
908 {
909 gViewerStats->incStat(LLViewerStats::ST_UPLOAD_TEXTURE_COUNT );
910 }
911 else
912 if( LLAssetType::AT_ANIMATION == asset_type)
913 {
914 gViewerStats->incStat(LLViewerStats::ST_UPLOAD_ANIM_COUNT );
915 }
916
917 if(LLInventoryType::IT_NONE == inv_type)
918 {
919 inv_type = LLInventoryType::defaultForAssetType(asset_type);
920 }
921 LLString::stripNonprintable(name);
922 LLString::stripNonprintable(desc);
923 if(name.empty())
924 {
925 name = "(No Name)";
926 }
927 if(desc.empty())
928 {
929 desc = "(No Description)";
930 }
931
932 // At this point, we're ready for the upload.
933 LLString upload_message = "Uploading...\n\n";
934 upload_message.append(display_name);
935 LLUploadDialog::modalUploadDialog(upload_message);
936
937 llinfos << "*** Uploading: " << llendl;
938 llinfos << "Type: " << LLAssetType::lookup(asset_type) << llendl;
939 llinfos << "UUID: " << uuid << llendl;
940 llinfos << "Name: " << name << llendl;
941 llinfos << "Desc: " << desc << llendl;
942 lldebugs << "Folder: " << gInventory.findCategoryUUIDForType((destination_folder_type == LLAssetType::AT_NONE) ? asset_type : destination_folder_type) << llendl;
943 lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl;
944 std::string url = gAgent.getRegion()->getCapability("NewFileAgentInventory");
945 if (!url.empty())
946 {
947 llinfos << "New Agent Inventory via capability" << llendl;
948 LLSD body;
949 body["folder_id"] = gInventory.findCategoryUUIDForType((destination_folder_type == LLAssetType::AT_NONE) ? asset_type : destination_folder_type);
950 body["asset_type"] = LLAssetType::lookup(asset_type);
951 body["inventory_type"] = LLInventoryType::lookup(inv_type);
952 body["name"] = name;
953 body["description"] = desc;
954
955 std::ostringstream llsdxml;
956 LLSDSerialize::toXML(body, llsdxml);
957 lldebugs << "posting body to capability: " << llsdxml.str() << llendl;
958 LLHTTPClient::post(url, body, new LLNewAgentInventoryResponder(body, uuid, asset_type));
959 }
960 else
961 {
962 llinfos << "NewAgentInventory capability not found, new agent inventory via asset system." << llendl;
963 // check for adequate funds
964 // TODO: do this check on the sim
965 if (LLAssetType::AT_SOUND == asset_type ||
966 LLAssetType::AT_TEXTURE == asset_type ||
967 LLAssetType::AT_ANIMATION == asset_type)
968 {
969 S32 upload_cost = gGlobalEconomy->getPriceUpload();
970 S32 balance = gStatusBar->getBalance();
971 if (balance < upload_cost)
972 {
973 // insufficient funds, bail on this upload
974 LLFloaterBuyCurrency::buyCurrency("Uploading costs", upload_cost);
975 return;
976 }
977 }
978
979 LLResourceData* data = new LLResourceData;
980 data->mAssetInfo.mTransactionID = tid;
981 data->mAssetInfo.mUuid = uuid;
982 data->mAssetInfo.mType = asset_type;
983 data->mAssetInfo.mCreatorID = gAgentID;
984 data->mInventoryType = inv_type;
985 data->mNextOwnerPerm = next_owner_perm;
986 data->mUserData = userdata;
987 data->mAssetInfo.setName(name);
988 data->mAssetInfo.setDescription(desc);
989 data->mPreferredLocation = destination_folder_type;
990
991 LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback;
992 if (callback)
993 {
994 asset_callback = callback;
995 }
996 gAssetStorage->storeAssetData(data->mAssetInfo.mTransactionID, data->mAssetInfo.mType,
997 asset_callback,
998 (void*)data,
999 FALSE);
1000 }
1001}
1002
1003
1004void init_menu_file()
1005{
1006 (new LLFileUploadImage())->registerListener(gMenuHolder, "File.UploadImage");
1007 (new LLFileUploadSound())->registerListener(gMenuHolder, "File.UploadSound");
1008 (new LLFileUploadAnim())->registerListener(gMenuHolder, "File.UploadAnim");
1009 (new LLFileUploadBulk())->registerListener(gMenuHolder, "File.UploadBulk");
1010 (new LLFileCloseWindow())->registerListener(gMenuHolder, "File.CloseWindow");
1011 (new LLFileCloseAllWindows())->registerListener(gMenuHolder, "File.CloseAllWindows");
1012 (new LLFileEnableCloseWindow())->registerListener(gMenuHolder, "File.EnableCloseWindow");
1013 (new LLFileSaveTexture())->registerListener(gMenuHolder, "File.SaveTexture");
1014 (new LLFileTakeSnapshot())->registerListener(gMenuHolder, "File.TakeSnapshot");
1015 (new LLFileTakeSnapshotToDisk())->registerListener(gMenuHolder, "File.TakeSnapshotToDisk");
1016 (new LLFileSaveMovie())->registerListener(gMenuHolder, "File.SaveMovie");
1017 (new LLFileSetWindowSize())->registerListener(gMenuHolder, "File.SetWindowSize");
1018 (new LLFileQuit())->registerListener(gMenuHolder, "File.Quit");
1019
1020 (new LLFileEnableUpload())->registerListener(gMenuHolder, "File.EnableUpload");
1021 (new LLFileEnableSaveAs())->registerListener(gMenuHolder, "File.EnableSaveAs");
1022}