/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/AlertNotification.h" #include "imgIContainer.h" #include "imgINotificationObserver.h" #include "imgIRequest.h" #include "imgLoader.h" #include "nsAlertsUtils.h" #include "nsAppDirectoryServiceDefs.h" #include "nsComponentManagerUtils.h" #include "nsContentUtils.h" #include "nsDirectoryServiceUtils.h" #include "nsNetUtil.h" #include "nsServiceManagerUtils.h" #include "mozilla/BasePrincipal.h" namespace mozilla { NS_IMPL_ISUPPORTS(AlertNotification, nsIAlertNotification) NS_IMETHODIMP AlertNotification::Init(const nsAString& aName, const nsAString& aImageURL, const nsAString& aTitle, const nsAString& aText, bool aTextClickable, const nsAString& aCookie, const nsAString& aDir, const nsAString& aLang, const nsAString& aData, nsIPrincipal* aPrincipal, bool aInPrivateBrowsing, bool aRequireInteraction, bool aSilent, const nsTArray& aVibrate) { if (!mId.IsEmpty()) { return NS_ERROR_ALREADY_INITIALIZED; } mName = aName; mImageURL = aImageURL; mTitle = aTitle; mText = aText; mTextClickable = aTextClickable; mCookie = aCookie; mDir = aDir; mLang = aLang; mData = aData; mPrincipal = aPrincipal; mInPrivateBrowsing = aInPrivateBrowsing; mRequireInteraction = aRequireInteraction; mSilent = aSilent; mVibrate = aVibrate.Clone(); return InitId(); } NS_IMETHODIMP AlertNotification::InitWithObject(nsIAlertNotification* aAlertNotification) { MOZ_TRY(aAlertNotification->GetName(mName)); MOZ_TRY(aAlertNotification->GetImageURL(mImageURL)); MOZ_TRY(aAlertNotification->GetImage(getter_AddRefs(mImage))); MOZ_TRY(aAlertNotification->GetTitle(mTitle)); MOZ_TRY(aAlertNotification->GetText(mText)); MOZ_TRY(aAlertNotification->GetTextClickable(&mTextClickable)); MOZ_TRY(aAlertNotification->GetCookie(mCookie)); MOZ_TRY(aAlertNotification->GetDir(mDir)); MOZ_TRY(aAlertNotification->GetLang(mLang)); MOZ_TRY(aAlertNotification->GetData(mData)); MOZ_TRY(aAlertNotification->GetPrincipal(getter_AddRefs(mPrincipal))); MOZ_TRY(aAlertNotification->GetInPrivateBrowsing(&mInPrivateBrowsing)); MOZ_TRY(aAlertNotification->GetRequireInteraction(&mRequireInteraction)); MOZ_TRY(aAlertNotification->GetSilent(&mSilent)); if (NS_FAILED(aAlertNotification->GetVibrate(mVibrate))) { mVibrate.Clear(); }; nsTArray> actions; if (NS_SUCCEEDED(aAlertNotification->GetActions(actions))) { for (auto& action : actions) { if (RefPtr copied = AlertAction::Copy(*action).unwrapOr(nullptr)) { mActions.AppendElement(copied); } } }; return InitId(); } nsresult AlertNotification::InitId() { nsAutoString id; // Multiple profiles might overwrite each other's toast messages when a // common name is used for a given origin. We prevent this by including // the profile directory as part of the toast hash. nsCOMPtr profDir; MOZ_TRY(NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(profDir))); MOZ_TRY(profDir->Normalize()); MOZ_TRY(profDir->GetPath(id)); if (mPrincipal && mPrincipal->GetIsContentPrincipal()) { // Notification originated from a web notification. nsAutoCString origin; MOZ_TRY(mPrincipal->GetOrigin(origin)); id += NS_ConvertUTF8toUTF16(origin); } else { id += u"chrome"; } if (mName.IsEmpty()) { // No associated name, append a UUID to prevent reuse of the same tag. nsIDToCString uuidString(nsID::GenerateUUID()); size_t len = strlen(uuidString.get()); MOZ_ASSERT(len == NSID_LENGTH - 1); nsAutoString uuid; CopyASCIItoUTF16(nsDependentCSubstring(uuidString.get(), len), uuid); id += u"#notag:"_ns; id += uuid; } else { id += u"#tag:"_ns; id += mName; } // Windows notification tags are limited to 16 characters, or 64 characters // after the Creators Update; therefore we hash the tag to fit the minimum // range. HashNumber hash = HashString(id); mId.AppendPrintf("%010u", hash); return NS_OK; } NS_IMETHODIMP AlertNotification::GetId(nsAString& aId) { if (mId.IsEmpty()) { return NS_ERROR_NOT_INITIALIZED; } aId = mId; return NS_OK; } NS_IMETHODIMP AlertNotification::SetActions( const nsTArray>& aActions) { mActions = aActions.Clone(); return NS_OK; } NS_IMETHODIMP AlertNotification::GetName(nsAString& aName) { if (mPrincipal && mPrincipal->GetIsContentPrincipal()) { // mName is no longer unique, but there has been a long assumption // throughout the codebase that GetName will be unique. So we return mId for // GetName for web triggered notifications to keep uniqueness without // accidentially causing subtle breakage in other modules. aName = mId; } else { // System callers has always been expected to provide unique names // themselves, so it's fine to return mName as is. aName = mName; } return NS_OK; } NS_IMETHODIMP AlertNotification::GetImageURL(nsAString& aImageURL) { aImageURL = mImageURL; return NS_OK; } NS_IMETHODIMP AlertNotification::SetImage(imgIContainer* aImage) { mImage = aImage; return NS_OK; } NS_IMETHODIMP AlertNotification::GetImage(imgIContainer** aImage) { nsCOMPtr image = mImage; image.forget(aImage); return NS_OK; } NS_IMETHODIMP AlertNotification::GetTitle(nsAString& aTitle) { aTitle = mTitle; return NS_OK; } NS_IMETHODIMP AlertNotification::GetText(nsAString& aText) { aText = mText; return NS_OK; } NS_IMETHODIMP AlertNotification::GetTextClickable(bool* aTextClickable) { *aTextClickable = mTextClickable; return NS_OK; } NS_IMETHODIMP AlertNotification::GetCookie(nsAString& aCookie) { aCookie = mCookie; return NS_OK; } NS_IMETHODIMP AlertNotification::GetDir(nsAString& aDir) { aDir = mDir; return NS_OK; } NS_IMETHODIMP AlertNotification::GetLang(nsAString& aLang) { aLang = mLang; return NS_OK; } NS_IMETHODIMP AlertNotification::GetRequireInteraction(bool* aRequireInteraction) { *aRequireInteraction = mRequireInteraction; return NS_OK; } NS_IMETHODIMP AlertNotification::GetData(nsAString& aData) { aData = mData; return NS_OK; } NS_IMETHODIMP AlertNotification::GetPrincipal(nsIPrincipal** aPrincipal) { NS_IF_ADDREF(*aPrincipal = mPrincipal); return NS_OK; } NS_IMETHODIMP AlertNotification::GetURI(nsIURI** aURI) { if (!nsAlertsUtils::IsActionablePrincipal(mPrincipal)) { *aURI = nullptr; return NS_OK; } auto* basePrin = BasePrincipal::Cast(mPrincipal); return basePrin->GetURI(aURI); } NS_IMETHODIMP AlertNotification::GetInPrivateBrowsing(bool* aInPrivateBrowsing) { *aInPrivateBrowsing = mInPrivateBrowsing; return NS_OK; } NS_IMETHODIMP AlertNotification::GetActionable(bool* aActionable) { *aActionable = nsAlertsUtils::IsActionablePrincipal(mPrincipal); return NS_OK; } NS_IMETHODIMP AlertNotification::GetSilent(bool* aSilent) { *aSilent = mSilent; return NS_OK; } NS_IMETHODIMP AlertNotification::GetVibrate(nsTArray& aVibrate) { aVibrate = mVibrate.Clone(); return NS_OK; } NS_IMETHODIMP AlertNotification::GetActions(nsTArray>& aActions) { aActions = mActions.Clone(); return NS_OK; } NS_IMETHODIMP AlertNotification::GetSource(nsAString& aSource) { nsAlertsUtils::GetSourceHostPort(mPrincipal, aSource); return NS_OK; } NS_IMETHODIMP AlertNotification::GetOrigin(nsACString& aOrigin) { return nsAlertsUtils::GetOrigin(mPrincipal, aOrigin); } NS_IMETHODIMP AlertNotification::GetOpaqueRelaunchData(nsAString& aOpaqueRelaunchData) { aOpaqueRelaunchData = mOpaqueRelaunchData; return NS_OK; } NS_IMETHODIMP AlertNotification::SetOpaqueRelaunchData(const nsAString& aOpaqueRelaunchData) { mOpaqueRelaunchData = aOpaqueRelaunchData; return NS_OK; } NS_IMETHODIMP AlertNotification::GetAction(const nsAString& aName, nsIAlertAction** aAlertAction) { NS_ENSURE_ARG_POINTER(aAlertAction); for (const auto& action : mActions) { nsString name; MOZ_TRY(action->GetAction(name)); if (name.Equals(aName)) { RefPtr match = action; match.forget(aAlertAction); return NS_OK; } } *aAlertAction = nullptr; return NS_OK; } NS_IMPL_ISUPPORTS(AlertAction, nsIAlertAction) AlertAction::AlertAction(const nsAString& aAction, const nsAString& aTitle) : mAction(aAction), mTitle(aTitle) {} Result, nsresult> AlertAction::Copy( nsIAlertAction& aAction) { nsAutoString action; nsAutoString title; MOZ_TRY(aAction.GetAction(action)); MOZ_TRY(aAction.GetTitle(title)); return do_AddRef(new AlertAction(action, title)); } NS_IMETHODIMP AlertAction::GetAction(nsAString& aAction) { aAction = mAction; return NS_OK; } NS_IMETHODIMP AlertAction::GetTitle(nsAString& aTitle) { aTitle = mTitle; return NS_OK; } NS_IMETHODIMP AlertAction::GetIconURL(nsAString& aTitle) { aTitle.Truncate(); return NS_OK; } NS_IMETHODIMP AlertAction::GetWindowsSystemActivationType(bool* aType) { *aType = false; return NS_OK; } NS_IMETHODIMP AlertAction::GetOpaqueRelaunchData(nsAString& aData) { aData.Truncate(); return NS_OK; } } // namespace mozilla