michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "DownloadPlatform.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsString.h" michael@0: #include "nsIURI.h" michael@0: #include "nsIFile.h" michael@0: #include "nsDirectoryServiceDefs.h" michael@0: michael@0: #include "mozilla/Preferences.h" michael@0: michael@0: #define PREF_BDM_ADDTORECENTDOCS "browser.download.manager.addToRecentDocs" michael@0: michael@0: #ifdef XP_WIN michael@0: #include michael@0: #include michael@0: #include "nsILocalFileWin.h" michael@0: #endif michael@0: michael@0: #ifdef XP_MACOSX michael@0: #include michael@0: #endif michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: #include "AndroidBridge.h" michael@0: #endif michael@0: michael@0: #ifdef MOZ_WIDGET_GTK michael@0: #include michael@0: #endif michael@0: michael@0: using namespace mozilla; michael@0: michael@0: DownloadPlatform *DownloadPlatform::gDownloadPlatformService = nullptr; michael@0: michael@0: NS_IMPL_ISUPPORTS(DownloadPlatform, mozIDownloadPlatform); michael@0: michael@0: DownloadPlatform* DownloadPlatform::GetDownloadPlatform() michael@0: { michael@0: if (!gDownloadPlatformService) { michael@0: gDownloadPlatformService = new DownloadPlatform(); michael@0: } michael@0: michael@0: NS_ADDREF(gDownloadPlatformService); michael@0: michael@0: #if defined(MOZ_WIDGET_GTK) michael@0: g_type_init(); michael@0: #endif michael@0: michael@0: return gDownloadPlatformService; michael@0: } michael@0: michael@0: #ifdef MOZ_ENABLE_GIO michael@0: static void gio_set_metadata_done(GObject *source_obj, GAsyncResult *res, gpointer user_data) michael@0: { michael@0: GError *err = nullptr; michael@0: g_file_set_attributes_finish(G_FILE(source_obj), res, nullptr, &err); michael@0: if (err) { michael@0: #ifdef DEBUG michael@0: NS_DebugBreak(NS_DEBUG_WARNING, "Set file metadata failed: ", err->message, __FILE__, __LINE__); michael@0: #endif michael@0: g_error_free(err); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: nsresult DownloadPlatform::DownloadDone(nsIURI* aSource, nsIFile* aTarget, michael@0: const nsACString& aContentType, bool aIsPrivate) michael@0: { michael@0: #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK) michael@0: nsAutoString path; michael@0: if (aTarget && NS_SUCCEEDED(aTarget->GetPath(path))) { michael@0: #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) michael@0: // On Windows and Gtk, add the download to the system's "recent documents" michael@0: // list, with a pref to disable. michael@0: { michael@0: bool addToRecentDocs = Preferences::GetBool(PREF_BDM_ADDTORECENTDOCS); michael@0: if (addToRecentDocs && !aIsPrivate) { michael@0: #ifdef XP_WIN michael@0: ::SHAddToRecentDocs(SHARD_PATHW, path.get()); michael@0: #elif defined(MOZ_WIDGET_GTK) michael@0: GtkRecentManager* manager = gtk_recent_manager_get_default(); michael@0: michael@0: gchar* uri = g_filename_to_uri(NS_ConvertUTF16toUTF8(path).get(), michael@0: nullptr, nullptr); michael@0: if (uri) { michael@0: gtk_recent_manager_add_item(manager, uri); michael@0: g_free(uri); michael@0: } michael@0: #endif michael@0: } michael@0: #ifdef MOZ_ENABLE_GIO michael@0: // Use GIO to store the source URI for later display in the file manager. michael@0: GFile* gio_file = g_file_new_for_path(NS_ConvertUTF16toUTF8(path).get()); michael@0: nsCString source_uri; michael@0: aSource->GetSpec(source_uri); michael@0: GFileInfo *file_info = g_file_info_new(); michael@0: g_file_info_set_attribute_string(file_info, "metadata::download-uri", source_uri.get()); michael@0: g_file_set_attributes_async(gio_file, michael@0: file_info, michael@0: G_FILE_QUERY_INFO_NONE, michael@0: G_PRIORITY_DEFAULT, michael@0: nullptr, gio_set_metadata_done, nullptr); michael@0: g_object_unref(file_info); michael@0: g_object_unref(gio_file); michael@0: #endif michael@0: } michael@0: #endif michael@0: #ifdef XP_MACOSX michael@0: // On OS X, make the downloads stack bounce. michael@0: CFStringRef observedObject = ::CFStringCreateWithCString(kCFAllocatorDefault, michael@0: NS_ConvertUTF16toUTF8(path).get(), michael@0: kCFStringEncodingUTF8); michael@0: CFNotificationCenterRef center = ::CFNotificationCenterGetDistributedCenter(); michael@0: ::CFNotificationCenterPostNotification(center, CFSTR("com.apple.DownloadFileFinished"), michael@0: observedObject, nullptr, TRUE); michael@0: ::CFRelease(observedObject); michael@0: #endif michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: if (!aContentType.IsEmpty()) { michael@0: mozilla::widget::android::GeckoAppShell::ScanMedia(path, NS_ConvertUTF8toUTF16(aContentType)); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: #ifdef XP_WIN michael@0: // Adjust file attributes so that by default, new files are indexed by michael@0: // desktop search services. Skip off those that land in the temp folder. michael@0: nsCOMPtr tempDir, fileDir; michael@0: nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tempDir)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: aTarget->GetParent(getter_AddRefs(fileDir)); michael@0: michael@0: bool isTemp = false; michael@0: if (fileDir) { michael@0: fileDir->Equals(tempDir, &isTemp); michael@0: } michael@0: michael@0: nsCOMPtr localFileWin(do_QueryInterface(aTarget)); michael@0: if (!isTemp && localFileWin) { michael@0: localFileWin->SetFileAttributesWin(nsILocalFileWin::WFA_SEARCH_INDEXED); michael@0: } michael@0: #endif michael@0: michael@0: #endif michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult DownloadPlatform::MapUrlToZone(const nsAString& aURL, michael@0: uint32_t* aZone) michael@0: { michael@0: #ifdef XP_WIN michael@0: nsRefPtr inetSecMgr; michael@0: if (FAILED(CoCreateInstance(CLSID_InternetSecurityManager, NULL, michael@0: CLSCTX_ALL, IID_IInternetSecurityManager, michael@0: getter_AddRefs(inetSecMgr)))) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: DWORD zone; michael@0: if (inetSecMgr->MapUrlToZone(PromiseFlatString(aURL).get(), michael@0: &zone, 0) != S_OK) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } else { michael@0: *aZone = zone; michael@0: } michael@0: michael@0: return NS_OK; michael@0: #else michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: #endif michael@0: }