diff --git a/indra/newview/llagentbenefits.cpp b/indra/newview/llagentbenefits.cpp
index 5ca4ecb456eef22a4145757651d7e9b3cd089a92..eef644ccc0f9ea4addd46fb3e24bac29fc011d47 100644
--- a/indra/newview/llagentbenefits.cpp
+++ b/indra/newview/llagentbenefits.cpp
@@ -129,3 +129,24 @@ S32 LLAgentBenefits::getTextureUploadCost() const
 {
 	return m_texture_upload_cost;
 }
+
+bool LLAgentBenefits::findUploadCost(LLAssetType::EType& asset_type, S32& cost)
+{
+	bool succ = false;
+	if (asset_type == LLAssetType::AT_TEXTURE)
+	{
+		cost = getTextureUploadCost();
+		succ = true;
+	}
+	else if (asset_type == LLAssetType::AT_SOUND)
+	{
+		cost = getSoundUploadCost();
+		succ = true;
+	}
+	else if (asset_type == LLAssetType::AT_ANIMATION)
+	{
+		cost = getAnimationUploadCost();
+		succ = true;
+	}
+	return succ;
+}
diff --git a/indra/newview/llagentbenefits.h b/indra/newview/llagentbenefits.h
index b21048e38bb0353a74177844365705331b63a26f..7ed6e169ce058cb2918218a37160949678d438ef 100644
--- a/indra/newview/llagentbenefits.h
+++ b/indra/newview/llagentbenefits.h
@@ -28,6 +28,7 @@
 
 #include "llsingleton.h"
 #include "llsd.h"
+#include "llassettype.h"
 
 class LLAgentBenefits: public LLSingleton<LLAgentBenefits>
 {
@@ -45,6 +46,8 @@ class LLAgentBenefits: public LLSingleton<LLAgentBenefits>
 	S32 getGroupMembershipLimit() const;
 	S32 getSoundUploadCost() const;
 	S32 getTextureUploadCost() const;
+
+	bool findUploadCost(LLAssetType::EType& asset_type, S32& cost);
 	
 private:
 	S32 m_animated_object_limit;
diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp
index 2a79eee80e98addc8c0f566051586a209ffd2f1e..de35f9911c0a520c0cc7e0029cbf81916463decf 100644
--- a/indra/newview/llviewerassetupload.cpp
+++ b/indra/newview/llviewerassetupload.cpp
@@ -306,6 +306,31 @@ std::string LLResourceUploadInfo::getDisplayName() const
     return (mName.empty()) ? mAssetId.asString() : mName;
 };
 
+// static
+bool LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(const std::string& exten, LLAssetType::EType& asset_type, U32& codec)
+{
+	bool succ = false;
+
+    codec = LLImageBase::getCodecFromExtension(exten);
+	if (codec != IMG_CODEC_INVALID)
+	{
+		asset_type = LLAssetType::AT_TEXTURE; 
+		succ = true;
+	}
+	else if (exten == "wav")
+	{
+		asset_type = LLAssetType::AT_SOUND; 
+		succ = true;
+	}
+	else if (exten == "anim")
+	{
+		asset_type = LLAssetType::AT_ANIMATION; 
+		succ = true;
+	}
+
+	return succ;
+}
+
 //=========================================================================
 LLNewFileResourceUploadInfo::LLNewFileResourceUploadInfo(
     std::string fileName,
@@ -343,9 +368,11 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile()
     std::string filename = gDirUtilp->getTempFilename();
 
     std::string exten = gDirUtilp->getExtension(getFileName());
-    U32 codec = LLImageBase::getCodecFromExtension(exten);
 
     LLAssetType::EType assetType = LLAssetType::AT_NONE;
+	U32 codec = IMG_CODEC_INVALID;
+	bool found_type = findAssetTypeAndCodecOfExtension(exten, assetType, codec);
+
     std::string errorMessage;
     std::string errorLabel;
 
@@ -362,10 +389,16 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile()
         errorLabel = "NoFileExtension";
         error = true;
     }
-    else if (codec != IMG_CODEC_INVALID)
+    else if (!found_type)
+    {
+        // Unknown extension
+        errorMessage = llformat(LLTrans::getString("UnknownFileExtension").c_str(), exten.c_str());
+        errorLabel = "ErrorMessage";
+        error = TRUE;;
+    }
+    else if (assetType == LLAssetType::AT_TEXTURE)
     {
         // It's an image file, the upload procedure is the same for all
-        assetType = LLAssetType::AT_TEXTURE;
         if (!LLViewerTextureList::createUploadFile(getFileName(), filename, codec))
         {
             errorMessage = llformat("Problem with file %s:\n\n%s\n",
@@ -374,9 +407,8 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile()
             error = true;
         }
     }
-    else if (exten == "wav")
+    else if (assetType == LLAssetType::AT_SOUND)
     {
-        assetType = LLAssetType::AT_SOUND;  // tag it as audio
         S32 encodeResult = 0;
 
         LL_INFOS() << "Attempting to encode wav as an ogg file" << LL_ENDL;
@@ -406,18 +438,10 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile()
         errorLabel = "DoNotSupportBulkAnimationUpload";
         error = true;
     }
-    else if (exten == "anim")
+    else if (assetType == LLAssetType::AT_ANIMATION)
     {
-        assetType = LLAssetType::AT_ANIMATION;
         filename = getFileName();
     }
-    else
-    {
-        // Unknown extension
-        errorMessage = llformat(LLTrans::getString("UnknownFileExtension").c_str(), exten.c_str());
-        errorLabel = "ErrorMessage";
-        error = TRUE;;
-    }
 
     if (error)
     {
diff --git a/indra/newview/llviewerassetupload.h b/indra/newview/llviewerassetupload.h
index 0ba16dce1db59ae6ae7ec645615d9e13daee028a..8ef25ad6fd47b4c763b6929cadb36c5908865580 100644
--- a/indra/newview/llviewerassetupload.h
+++ b/indra/newview/llviewerassetupload.h
@@ -87,6 +87,8 @@ class LLResourceUploadInfo
     LLUUID              getItemId() const { return mItemId; }
     LLAssetID           getAssetId() const { return mAssetId; }
 
+	static bool			findAssetTypeAndCodecOfExtension(const std::string& exten, LLAssetType::EType& asset_type, U32& codec);
+
 protected:
     LLResourceUploadInfo(
         std::string name,
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index b1606958e152a68e64d4d595e49d818df22218a7..90fbbcc8d2141df0c9735f5e4e63defd8f39aa6a 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -404,24 +404,19 @@ const void upload_single_file(const std::vector<std::string>& filenames, LLFileP
 	return;
 }
 
-
-const void upload_bulk(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter type)
+void do_bulk_upload(std::vector<std::string> filenames, const LLSD& notification, const LLSD& response)
 {
-	// TODO:
-	// Check user balance for entire cost
-	// Charge user entire cost
-	// Loop, uploading
-	// If an upload fails, refund the user for that one
-	//
-	// Also fix single upload to charge first, then refund
+	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+	if (option != 0)
+	{
+		// Cancel upload
+		return;
+	}
 
-	// FIXME PREMIUM - upload_cost should be per-file, depends on asset type
-	S32 expected_upload_cost = LLAgentBenefits::instance().getTextureUploadCost();
 	for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter)
 	{
 		std::string filename = (*in_iter);
-		if (!check_file_extension(filename, type)) continue;
-		
+			
 		std::string name = gDirUtilp->getBaseFileName(filename, true);
 		std::string asset_name = name;
 		LLStringUtil::replaceNonstandardASCII(asset_name, '?');
@@ -429,17 +424,80 @@ const void upload_bulk(const std::vector<std::string>& filenames, LLFilePicker::
 		LLStringUtil::stripNonprintable(asset_name);
 		LLStringUtil::trim(asset_name);
 
-		LLResourceUploadInfo::ptr_t uploadInfo(new LLNewFileResourceUploadInfo(
-			filename,
-			asset_name,
-			asset_name, 0,
-			LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
-			LLFloaterPerms::getNextOwnerPerms("Uploads"),
-			LLFloaterPerms::getGroupPerms("Uploads"),
-			LLFloaterPerms::getEveryonePerms("Uploads"),
-			expected_upload_cost));
+		std::string ext = gDirUtilp->getExtension(filename);
+		LLAssetType::EType asset_type;
+		U32 codec;
+		S32 expected_upload_cost;
+		if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) &&
+			LLAgentBenefits::instance().findUploadCost(asset_type, expected_upload_cost))
+		{
+			LLResourceUploadInfo::ptr_t uploadInfo(new LLNewFileResourceUploadInfo(
+													   filename,
+													   asset_name,
+													   asset_name, 0,
+													   LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
+													   LLFloaterPerms::getNextOwnerPerms("Uploads"),
+													   LLFloaterPerms::getGroupPerms("Uploads"),
+													   LLFloaterPerms::getEveryonePerms("Uploads"),
+													   expected_upload_cost));
+			
+			upload_new_resource(uploadInfo, NULL, NULL);
+		}
+	}
+}
 
-		upload_new_resource(uploadInfo, NULL, NULL);
+bool get_bulk_upload_expected_cost(const std::vector<std::string>& filenames, S32& total_cost)
+{
+	bool succ = true;
+	total_cost = 0;
+	for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter)
+	{
+		std::string filename = (*in_iter);
+		std::string ext = gDirUtilp->getExtension(filename);
+
+		LLAssetType::EType asset_type;
+		U32 codec;
+		S32 cost;
+
+		if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec) &&
+			LLAgentBenefits::instance().findUploadCost(asset_type, cost))
+		{
+			total_cost += cost;
+		}
+	}
+	
+	return succ;
+}
+
+const void upload_bulk(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter type)
+{
+	// TODO:
+	// Check user balance for entire cost
+	// Charge user entire cost
+	// Loop, uploading
+	// If an upload fails, refund the user for that one
+	//
+	// Also fix single upload to charge first, then refund
+
+	// FIXME PREMIUM what about known types that can't be bulk uploaded
+	// (bvh)? These will fail in the item by item upload but won't be
+	// mentioned in the notification.
+	std::vector<std::string> filtered_filenames;
+	for (std::vector<std::string>::const_iterator in_iter = filenames.begin(); in_iter != filenames.end(); ++in_iter)
+	{
+		const std::string& filename = *in_iter;
+		if (check_file_extension(filename, type))
+		{
+			filtered_filenames.push_back(filename);
+		}
+	}
+	S32 expected_upload_cost;
+	if (get_bulk_upload_expected_cost(filtered_filenames, expected_upload_cost))
+	{
+		LLSD args;
+		args["COST"] = expected_upload_cost;
+		args["COUNT"] = (S32) filtered_filenames.size();
+		LLNotificationsUtil::add("BulkUploadCostConfirmation",  args, LLSD(), boost::bind(do_bulk_upload, filtered_filenames, _1, _2));
 	}
 }
 
diff --git a/indra/newview/skins/default/xui/en/menu_inventory_add.xml b/indra/newview/skins/default/xui/en/menu_inventory_add.xml
index 29724b0270e5446e1f6a789c160a2ad152fa9c23..05dd8f827dc958db38c251c3d1847b3710302593 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory_add.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory_add.xml
@@ -56,7 +56,7 @@
                 function="File.VisibleUploadModel"/>
                 </menu_item_call>
                 <menu_item_call
-                 label="Bulk (L$[COST] per file)..."
+                 label="Bulk..."
                  layout="topleft"
                  name="Bulk Upload">
                     <menu_item_call.on_click
@@ -253,4 +253,4 @@
                      parameter="eyes" />
                 </menu_item_call>
             </menu>
-</menu>
\ No newline at end of file
+</menu>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 165986448fee80b8d32e2e1000a25508389c2c64..9b27e8b03dc4e6a6c3c5742a2da73966a526ee58 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -1347,7 +1347,7 @@
             function="File.VisibleUploadModel"/>
             </menu_item_call>
 	   <menu_item_call
-             label="Bulk (L$[COST] per file)..."
+             label="Bulk..."
              layout="topleft"
              name="Bulk Upload">
                 <menu_item_call.on_visible
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index e0fc6bb9a584cc27be78ad9c4723f5ce7c385c89..2df0b1cbf4f6fd3ed72cef475a005f04725490ad 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -8403,6 +8403,17 @@ Your voice has been muted by moderator.
          yestext="OK"/>
     </notification>
   
+   <notification
+    icon="alertmodal.tga"
+    name="BulkUploadCostConfirmation"
+    type="alertmodal">
+This will upload [COUNT] items at a total cost of L$[COST]. Do you wish to continue with the upload?
+    <usetemplate
+     name="okcancelbuttons"
+     notext="Cancel"
+     yestext="Upload"/>
+  </notification>
+
    <notification
     icon="alertmodal.tga"
     name="UploadCostConfirmation"
diff --git a/indra/newview/skins/default/xui/it/menu_inventory_add.xml b/indra/newview/skins/default/xui/it/menu_inventory_add.xml
index 62da61cd6b5efd0890e3b425ee1ac65339ccbeca..e31f0ebb6987a24bc1812c0274ebcf1568a95dca 100644
--- a/indra/newview/skins/default/xui/it/menu_inventory_add.xml
+++ b/indra/newview/skins/default/xui/it/menu_inventory_add.xml
@@ -6,7 +6,7 @@
 		<menu_item_call label="Animazione ([COST]L$)..." name="Upload Animation"/>
 		<menu_item_call label="Modella..." name="Upload Model"/>
 		<menu_item_call label="Procedura guidata modellazione..." name="Upload Model Wizard"/>
-		<menu_item_call label="In blocco ([COST]L$ per file)..." name="Bulk Upload"/>
+		<menu_item_call label="In blocco..." name="Bulk Upload"/>
 		<menu_item_call label="Definisci diritti di caricamento predefiniti" name="perm prefs"/>
 	</menu>
 	<menu_item_call label="Nuova cartella" name="New Folder"/>
diff --git a/indra/newview/skins/default/xui/it/menu_viewer.xml b/indra/newview/skins/default/xui/it/menu_viewer.xml
index ae82a89d28d98086e2ea3fbc9a494629389757cf..795a23ca9bca7616a44f5cd1dc25c3b54b095df6 100644
--- a/indra/newview/skins/default/xui/it/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/it/menu_viewer.xml
@@ -168,7 +168,7 @@
 			<menu_item_call label="Suono ([COST] L$)..." name="Upload Sound"/>
 			<menu_item_call label="Animazione ([COST] L$)..." name="Upload Animation"/>
 			<menu_item_call label="Modella..." name="Upload Model"/>
-			<menu_item_call label="In blocco ([COST] L$ per file)..." name="Bulk Upload"/>
+			<menu_item_call label="In blocco..." name="Bulk Upload"/>
 		</menu>
 		<menu_item_call label="Annulla" name="Undo"/>
 		<menu_item_call label="Ripeti" name="Redo"/>
diff --git a/indra/newview/skins/default/xui/pl/menu_viewer.xml b/indra/newview/skins/default/xui/pl/menu_viewer.xml
index e6ad1faee654dd928f00d4150dd7d1c51444c704..2dfafff7f5aca848e41b80c0c48aeb64ed6fd7cb 100644
--- a/indra/newview/skins/default/xui/pl/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/pl/menu_viewer.xml
@@ -159,7 +159,7 @@
 			<menu_item_call label="Dźwięk ([COST]L$)..." name="Upload Sound" />
 			<menu_item_call label="AnimacjÄ™ ([COST]L$)..." name="Upload Animation" />
 			<menu_item_call label="Model meszowy..." name="Upload Model" />
-			<menu_item_call label="Zbiór wielu plików ([COST]L$ per file)..." name="Bulk Upload" />
+			<menu_item_call label="Zbiór wielu plików..." name="Bulk Upload" />
 		</menu>
 		<menu_item_call label="Cofnij" name="Undo" />
 		<menu_item_call label="Ponów" name="Redo" />	  
diff --git a/indra/newview/skins/default/xui/pt/menu_inventory_add.xml b/indra/newview/skins/default/xui/pt/menu_inventory_add.xml
index 7a7ebc50af162a884dc818c508dc2c9c2bc0747c..92621e8493404aa37b73f97c5b6b9f3a35a71b5c 100644
--- a/indra/newview/skins/default/xui/pt/menu_inventory_add.xml
+++ b/indra/newview/skins/default/xui/pt/menu_inventory_add.xml
@@ -6,7 +6,7 @@
 		<menu_item_call label="Animação (L$[COST])..." name="Upload Animation"/>
 		<menu_item_call label="Modelar..." name="Upload Model"/>
 		<menu_item_call label="Assistente de modelagem..." name="Upload Model Wizard"/>
-		<menu_item_call label="Volume (L$[COST] per file)..." name="Bulk Upload"/>
+		<menu_item_call label="Volume..." name="Bulk Upload"/>
 		<menu_item_call label="Autorizações de upload padrão" name="perm prefs"/>
 	</menu>
 	<menu_item_call label="Nova pasta" name="New Folder"/>