widget/windows/JumpListItem.cpp

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "JumpListItem.h"
michael@0 7
michael@0 8 #include <shellapi.h>
michael@0 9 #include <propvarutil.h>
michael@0 10 #include <propkey.h>
michael@0 11
michael@0 12 #include "nsIFile.h"
michael@0 13 #include "nsNetUtil.h"
michael@0 14 #include "nsCRT.h"
michael@0 15 #include "nsNetCID.h"
michael@0 16 #include "nsCExternalHandlerService.h"
michael@0 17 #include "nsCycleCollectionParticipant.h"
michael@0 18 #include "mozilla/Preferences.h"
michael@0 19 #include "JumpListBuilder.h"
michael@0 20 #include "WinUtils.h"
michael@0 21
michael@0 22 namespace mozilla {
michael@0 23 namespace widget {
michael@0 24
michael@0 25 // ISUPPORTS Impl's
michael@0 26 NS_IMPL_ISUPPORTS(JumpListItem,
michael@0 27 nsIJumpListItem)
michael@0 28
michael@0 29 NS_IMPL_ISUPPORTS_INHERITED(JumpListSeparator,
michael@0 30 JumpListItem,
michael@0 31 nsIJumpListSeparator)
michael@0 32
michael@0 33 NS_IMPL_ISUPPORTS_INHERITED(JumpListLink,
michael@0 34 JumpListItem,
michael@0 35 nsIJumpListLink)
michael@0 36
michael@0 37 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JumpListShortcut)
michael@0 38 NS_INTERFACE_MAP_ENTRY(nsIJumpListShortcut)
michael@0 39 NS_INTERFACE_MAP_END_INHERITING(JumpListItem)
michael@0 40
michael@0 41 NS_IMPL_CYCLE_COLLECTION(JumpListShortcut, mHandlerApp)
michael@0 42
michael@0 43 NS_IMPL_CYCLE_COLLECTING_ADDREF(JumpListShortcut)
michael@0 44 NS_IMPL_CYCLE_COLLECTING_RELEASE(JumpListShortcut)
michael@0 45
michael@0 46 /* attribute short type; */
michael@0 47 NS_IMETHODIMP JumpListItem::GetType(int16_t *aType)
michael@0 48 {
michael@0 49 NS_ENSURE_ARG_POINTER(aType);
michael@0 50
michael@0 51 *aType = mItemType;
michael@0 52
michael@0 53 return NS_OK;
michael@0 54 }
michael@0 55
michael@0 56 /* boolean equals(nsIJumpListItem item); */
michael@0 57 NS_IMETHODIMP JumpListItem::Equals(nsIJumpListItem *aItem, bool *aResult)
michael@0 58 {
michael@0 59 NS_ENSURE_ARG_POINTER(aItem);
michael@0 60
michael@0 61 *aResult = false;
michael@0 62
michael@0 63 int16_t theType = nsIJumpListItem::JUMPLIST_ITEM_EMPTY;
michael@0 64 if (NS_FAILED(aItem->GetType(&theType)))
michael@0 65 return NS_OK;
michael@0 66
michael@0 67 // Make sure the types match.
michael@0 68 if (Type() != theType)
michael@0 69 return NS_OK;
michael@0 70
michael@0 71 *aResult = true;
michael@0 72
michael@0 73 return NS_OK;
michael@0 74 }
michael@0 75
michael@0 76 /* link impl. */
michael@0 77
michael@0 78 /* attribute nsIURI uri; */
michael@0 79 NS_IMETHODIMP JumpListLink::GetUri(nsIURI **aURI)
michael@0 80 {
michael@0 81 NS_IF_ADDREF(*aURI = mURI);
michael@0 82
michael@0 83 return NS_OK;
michael@0 84 }
michael@0 85
michael@0 86 NS_IMETHODIMP JumpListLink::SetUri(nsIURI *aURI)
michael@0 87 {
michael@0 88 mURI = aURI;
michael@0 89
michael@0 90 return NS_OK;
michael@0 91 }
michael@0 92
michael@0 93 /* attribute AString uriTitle; */
michael@0 94 NS_IMETHODIMP JumpListLink::SetUriTitle(const nsAString &aUriTitle)
michael@0 95 {
michael@0 96 mUriTitle.Assign(aUriTitle);
michael@0 97
michael@0 98 return NS_OK;
michael@0 99 }
michael@0 100
michael@0 101 NS_IMETHODIMP JumpListLink::GetUriTitle(nsAString& aUriTitle)
michael@0 102 {
michael@0 103 aUriTitle.Assign(mUriTitle);
michael@0 104
michael@0 105 return NS_OK;
michael@0 106 }
michael@0 107
michael@0 108 /* readonly attribute long uriHash; */
michael@0 109 NS_IMETHODIMP JumpListLink::GetUriHash(nsACString& aUriHash)
michael@0 110 {
michael@0 111 if (!mURI)
michael@0 112 return NS_ERROR_NOT_AVAILABLE;
michael@0 113
michael@0 114 return mozilla::widget::FaviconHelper::HashURI(mCryptoHash, mURI, aUriHash);
michael@0 115 }
michael@0 116
michael@0 117 /* boolean compareHash(in nsIURI uri); */
michael@0 118 NS_IMETHODIMP JumpListLink::CompareHash(nsIURI *aUri, bool *aResult)
michael@0 119 {
michael@0 120 nsresult rv;
michael@0 121
michael@0 122 if (!mURI) {
michael@0 123 *aResult = !aUri;
michael@0 124 return NS_OK;
michael@0 125 }
michael@0 126
michael@0 127 NS_ENSURE_ARG_POINTER(aUri);
michael@0 128
michael@0 129 nsAutoCString hash1, hash2;
michael@0 130
michael@0 131 rv = mozilla::widget::FaviconHelper::HashURI(mCryptoHash, mURI, hash1);
michael@0 132 NS_ENSURE_SUCCESS(rv, rv);
michael@0 133 rv = mozilla::widget::FaviconHelper::HashURI(mCryptoHash, aUri, hash2);
michael@0 134 NS_ENSURE_SUCCESS(rv, rv);
michael@0 135
michael@0 136 *aResult = hash1.Equals(hash2);
michael@0 137
michael@0 138 return NS_OK;
michael@0 139 }
michael@0 140
michael@0 141 /* boolean equals(nsIJumpListItem item); */
michael@0 142 NS_IMETHODIMP JumpListLink::Equals(nsIJumpListItem *aItem, bool *aResult)
michael@0 143 {
michael@0 144 NS_ENSURE_ARG_POINTER(aItem);
michael@0 145
michael@0 146 nsresult rv;
michael@0 147
michael@0 148 *aResult = false;
michael@0 149
michael@0 150 int16_t theType = nsIJumpListItem::JUMPLIST_ITEM_EMPTY;
michael@0 151 if (NS_FAILED(aItem->GetType(&theType)))
michael@0 152 return NS_OK;
michael@0 153
michael@0 154 // Make sure the types match.
michael@0 155 if (Type() != theType)
michael@0 156 return NS_OK;
michael@0 157
michael@0 158 nsCOMPtr<nsIJumpListLink> link = do_QueryInterface(aItem, &rv);
michael@0 159 if (NS_FAILED(rv))
michael@0 160 return rv;
michael@0 161
michael@0 162 // Check the titles
michael@0 163 nsAutoString title;
michael@0 164 link->GetUriTitle(title);
michael@0 165 if (!mUriTitle.Equals(title))
michael@0 166 return NS_OK;
michael@0 167
michael@0 168 // Call the internal object's equals() method to check.
michael@0 169 nsCOMPtr<nsIURI> theUri;
michael@0 170 bool equals = false;
michael@0 171 if (NS_SUCCEEDED(link->GetUri(getter_AddRefs(theUri)))) {
michael@0 172 if (!theUri) {
michael@0 173 if (!mURI)
michael@0 174 *aResult = true;
michael@0 175 return NS_OK;
michael@0 176 }
michael@0 177 if (NS_SUCCEEDED(theUri->Equals(mURI, &equals)) && equals) {
michael@0 178 *aResult = true;
michael@0 179 }
michael@0 180 }
michael@0 181
michael@0 182 return NS_OK;
michael@0 183 }
michael@0 184
michael@0 185 /* shortcut impl. */
michael@0 186
michael@0 187 /* attribute nsILocalHandlerApp app; */
michael@0 188 NS_IMETHODIMP JumpListShortcut::GetApp(nsILocalHandlerApp **aApp)
michael@0 189 {
michael@0 190 NS_IF_ADDREF(*aApp = mHandlerApp);
michael@0 191
michael@0 192 return NS_OK;
michael@0 193 }
michael@0 194
michael@0 195 NS_IMETHODIMP JumpListShortcut::SetApp(nsILocalHandlerApp *aApp)
michael@0 196 {
michael@0 197 mHandlerApp = aApp;
michael@0 198
michael@0 199 // Confirm the app is present on the system
michael@0 200 if (!ExecutableExists(mHandlerApp))
michael@0 201 return NS_ERROR_FILE_NOT_FOUND;
michael@0 202
michael@0 203 return NS_OK;
michael@0 204 }
michael@0 205
michael@0 206 /* attribute long iconIndex; */
michael@0 207 NS_IMETHODIMP JumpListShortcut::GetIconIndex(int32_t *aIconIndex)
michael@0 208 {
michael@0 209 NS_ENSURE_ARG_POINTER(aIconIndex);
michael@0 210
michael@0 211 *aIconIndex = mIconIndex;
michael@0 212 return NS_OK;
michael@0 213 }
michael@0 214
michael@0 215 NS_IMETHODIMP JumpListShortcut::SetIconIndex(int32_t aIconIndex)
michael@0 216 {
michael@0 217 mIconIndex = aIconIndex;
michael@0 218 return NS_OK;
michael@0 219 }
michael@0 220
michael@0 221 /* attribute long iconURI; */
michael@0 222 NS_IMETHODIMP JumpListShortcut::GetFaviconPageUri(nsIURI **aFaviconPageURI)
michael@0 223 {
michael@0 224 NS_IF_ADDREF(*aFaviconPageURI = mFaviconPageURI);
michael@0 225
michael@0 226 return NS_OK;
michael@0 227 }
michael@0 228
michael@0 229 NS_IMETHODIMP JumpListShortcut::SetFaviconPageUri(nsIURI *aFaviconPageURI)
michael@0 230 {
michael@0 231 mFaviconPageURI = aFaviconPageURI;
michael@0 232 return NS_OK;
michael@0 233 }
michael@0 234
michael@0 235 /* boolean equals(nsIJumpListItem item); */
michael@0 236 NS_IMETHODIMP JumpListShortcut::Equals(nsIJumpListItem *aItem, bool *aResult)
michael@0 237 {
michael@0 238 NS_ENSURE_ARG_POINTER(aItem);
michael@0 239
michael@0 240 nsresult rv;
michael@0 241
michael@0 242 *aResult = false;
michael@0 243
michael@0 244 int16_t theType = nsIJumpListItem::JUMPLIST_ITEM_EMPTY;
michael@0 245 if (NS_FAILED(aItem->GetType(&theType)))
michael@0 246 return NS_OK;
michael@0 247
michael@0 248 // Make sure the types match.
michael@0 249 if (Type() != theType)
michael@0 250 return NS_OK;
michael@0 251
michael@0 252 nsCOMPtr<nsIJumpListShortcut> shortcut = do_QueryInterface(aItem, &rv);
michael@0 253 if (NS_FAILED(rv))
michael@0 254 return rv;
michael@0 255
michael@0 256 // Check the icon index
michael@0 257 //int32_t idx;
michael@0 258 //shortcut->GetIconIndex(&idx);
michael@0 259 //if (mIconIndex != idx)
michael@0 260 // return NS_OK;
michael@0 261 // No need to check the icon page URI either
michael@0 262
michael@0 263 // Call the internal object's equals() method to check.
michael@0 264 nsCOMPtr<nsILocalHandlerApp> theApp;
michael@0 265 bool equals = false;
michael@0 266 if (NS_SUCCEEDED(shortcut->GetApp(getter_AddRefs(theApp)))) {
michael@0 267 if (!theApp) {
michael@0 268 if (!mHandlerApp)
michael@0 269 *aResult = true;
michael@0 270 return NS_OK;
michael@0 271 }
michael@0 272 if (NS_SUCCEEDED(theApp->Equals(mHandlerApp, &equals)) && equals) {
michael@0 273 *aResult = true;
michael@0 274 }
michael@0 275 }
michael@0 276
michael@0 277 return NS_OK;
michael@0 278 }
michael@0 279
michael@0 280 /* internal helpers */
michael@0 281
michael@0 282 // (static) Creates a ShellLink that encapsulate a separator.
michael@0 283 nsresult JumpListSeparator::GetSeparator(nsRefPtr<IShellLinkW>& aShellLink)
michael@0 284 {
michael@0 285 HRESULT hr;
michael@0 286 IShellLinkW* psl;
michael@0 287
michael@0 288 // Create a IShellLink.
michael@0 289 hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
michael@0 290 IID_IShellLinkW, (LPVOID*)&psl);
michael@0 291 if (FAILED(hr))
michael@0 292 return NS_ERROR_UNEXPECTED;
michael@0 293
michael@0 294 IPropertyStore* pPropStore = nullptr;
michael@0 295 hr = psl->QueryInterface(IID_IPropertyStore, (LPVOID*)&pPropStore);
michael@0 296 if (FAILED(hr))
michael@0 297 return NS_ERROR_UNEXPECTED;
michael@0 298
michael@0 299 PROPVARIANT pv;
michael@0 300 InitPropVariantFromBoolean(TRUE, &pv);
michael@0 301
michael@0 302 pPropStore->SetValue(PKEY_AppUserModel_IsDestListSeparator, pv);
michael@0 303 pPropStore->Commit();
michael@0 304 pPropStore->Release();
michael@0 305
michael@0 306 PropVariantClear(&pv);
michael@0 307
michael@0 308 aShellLink = dont_AddRef(psl);
michael@0 309
michael@0 310 return NS_OK;
michael@0 311 }
michael@0 312
michael@0 313 // (static) Creates a ShellLink that encapsulate a shortcut to local apps.
michael@0 314 nsresult JumpListShortcut::GetShellLink(nsCOMPtr<nsIJumpListItem>& item,
michael@0 315 nsRefPtr<IShellLinkW>& aShellLink,
michael@0 316 nsCOMPtr<nsIThread> &aIOThread)
michael@0 317 {
michael@0 318 HRESULT hr;
michael@0 319 IShellLinkW* psl;
michael@0 320 nsresult rv;
michael@0 321
michael@0 322 // Shell links:
michael@0 323 // http://msdn.microsoft.com/en-us/library/bb776891(VS.85).aspx
michael@0 324 // http://msdn.microsoft.com/en-us/library/bb774950(VS.85).aspx
michael@0 325
michael@0 326 int16_t type;
michael@0 327 if (NS_FAILED(item->GetType(&type)))
michael@0 328 return NS_ERROR_INVALID_ARG;
michael@0 329
michael@0 330 if (type != nsIJumpListItem::JUMPLIST_ITEM_SHORTCUT)
michael@0 331 return NS_ERROR_INVALID_ARG;
michael@0 332
michael@0 333 nsCOMPtr<nsIJumpListShortcut> shortcut = do_QueryInterface(item, &rv);
michael@0 334 NS_ENSURE_SUCCESS(rv, rv);
michael@0 335
michael@0 336 nsCOMPtr<nsILocalHandlerApp> handlerApp;
michael@0 337 rv = shortcut->GetApp(getter_AddRefs(handlerApp));
michael@0 338 NS_ENSURE_SUCCESS(rv, rv);
michael@0 339
michael@0 340 // Create a IShellLink
michael@0 341 hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
michael@0 342 IID_IShellLinkW, (LPVOID*)&psl);
michael@0 343 if (FAILED(hr))
michael@0 344 return NS_ERROR_UNEXPECTED;
michael@0 345
michael@0 346 // Retrieve the app path, title, description and optional command line args.
michael@0 347 nsAutoString appPath, appTitle, appDescription, appArgs;
michael@0 348 int32_t appIconIndex = 0;
michael@0 349
michael@0 350 // Path
michael@0 351 nsCOMPtr<nsIFile> executable;
michael@0 352 handlerApp->GetExecutable(getter_AddRefs(executable));
michael@0 353
michael@0 354 rv = executable->GetPath(appPath);
michael@0 355 NS_ENSURE_SUCCESS(rv, rv);
michael@0 356
michael@0 357 // Command line parameters
michael@0 358 uint32_t count = 0;
michael@0 359 handlerApp->GetParameterCount(&count);
michael@0 360 for (uint32_t idx = 0; idx < count; idx++) {
michael@0 361 if (idx > 0)
michael@0 362 appArgs.Append(NS_LITERAL_STRING(" "));
michael@0 363 nsAutoString param;
michael@0 364 rv = handlerApp->GetParameter(idx, param);
michael@0 365 if (NS_FAILED(rv))
michael@0 366 return rv;
michael@0 367 appArgs.Append(param);
michael@0 368 }
michael@0 369
michael@0 370 handlerApp->GetName(appTitle);
michael@0 371 handlerApp->GetDetailedDescription(appDescription);
michael@0 372
michael@0 373 bool useUriIcon = false; // if we want to use the URI icon
michael@0 374 bool usedUriIcon = false; // if we did use the URI icon
michael@0 375 shortcut->GetIconIndex(&appIconIndex);
michael@0 376
michael@0 377 nsCOMPtr<nsIURI> iconUri;
michael@0 378 rv = shortcut->GetFaviconPageUri(getter_AddRefs(iconUri));
michael@0 379 if (NS_SUCCEEDED(rv) && iconUri) {
michael@0 380 useUriIcon = true;
michael@0 381 }
michael@0 382
michael@0 383 // Store the title of the app
michael@0 384 if (appTitle.Length() > 0) {
michael@0 385 IPropertyStore* pPropStore = nullptr;
michael@0 386 hr = psl->QueryInterface(IID_IPropertyStore, (LPVOID*)&pPropStore);
michael@0 387 if (FAILED(hr))
michael@0 388 return NS_ERROR_UNEXPECTED;
michael@0 389
michael@0 390 PROPVARIANT pv;
michael@0 391 InitPropVariantFromString(appTitle.get(), &pv);
michael@0 392
michael@0 393 pPropStore->SetValue(PKEY_Title, pv);
michael@0 394 pPropStore->Commit();
michael@0 395 pPropStore->Release();
michael@0 396
michael@0 397 PropVariantClear(&pv);
michael@0 398 }
michael@0 399
michael@0 400 // Store the rest of the params
michael@0 401 psl->SetPath(appPath.get());
michael@0 402 psl->SetDescription(appDescription.get());
michael@0 403 psl->SetArguments(appArgs.get());
michael@0 404
michael@0 405 if (useUriIcon) {
michael@0 406 nsString icoFilePath;
michael@0 407 rv = mozilla::widget::FaviconHelper::ObtainCachedIconFile(iconUri,
michael@0 408 icoFilePath,
michael@0 409 aIOThread,
michael@0 410 false);
michael@0 411 if (NS_SUCCEEDED(rv)) {
michael@0 412 // Always use the first icon in the ICO file
michael@0 413 // our encoded icon only has 1 resource
michael@0 414 psl->SetIconLocation(icoFilePath.get(), 0);
michael@0 415 usedUriIcon = true;
michael@0 416 }
michael@0 417 }
michael@0 418
michael@0 419 // We didn't use an ICO via URI so fall back to the app icon
michael@0 420 if (!usedUriIcon) {
michael@0 421 psl->SetIconLocation(appPath.get(), appIconIndex);
michael@0 422 }
michael@0 423
michael@0 424 aShellLink = dont_AddRef(psl);
michael@0 425
michael@0 426 return NS_OK;
michael@0 427 }
michael@0 428
michael@0 429 // If successful fills in the aSame parameter
michael@0 430 // aSame will be true if the path is in our icon cache
michael@0 431 static nsresult IsPathInOurIconCache(nsCOMPtr<nsIJumpListShortcut>& aShortcut,
michael@0 432 wchar_t *aPath, bool *aSame)
michael@0 433 {
michael@0 434 NS_ENSURE_ARG_POINTER(aPath);
michael@0 435 NS_ENSURE_ARG_POINTER(aSame);
michael@0 436
michael@0 437 *aSame = false;
michael@0 438
michael@0 439 // Construct the path of our jump list cache
michael@0 440 nsCOMPtr<nsIFile> jumpListCache;
michael@0 441 nsresult rv = NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(jumpListCache));
michael@0 442 NS_ENSURE_SUCCESS(rv, rv);
michael@0 443 rv = jumpListCache->AppendNative(nsDependentCString(FaviconHelper::kJumpListCacheDir));
michael@0 444 NS_ENSURE_SUCCESS(rv, rv);
michael@0 445 nsAutoString jumpListCachePath;
michael@0 446 rv = jumpListCache->GetPath(jumpListCachePath);
michael@0 447 NS_ENSURE_SUCCESS(rv, rv);
michael@0 448
michael@0 449 // Construct the parent path of the passed in path
michael@0 450 nsCOMPtr<nsIFile> passedInFile = do_CreateInstance("@mozilla.org/file/local;1");
michael@0 451 NS_ENSURE_TRUE(passedInFile, NS_ERROR_FAILURE);
michael@0 452 nsAutoString passedInPath(aPath);
michael@0 453 rv = passedInFile->InitWithPath(passedInPath);
michael@0 454 nsCOMPtr<nsIFile> passedInParentFile;
michael@0 455 passedInFile->GetParent(getter_AddRefs(passedInParentFile));
michael@0 456 nsAutoString passedInParentPath;
michael@0 457 rv = jumpListCache->GetPath(passedInParentPath);
michael@0 458 NS_ENSURE_SUCCESS(rv, rv);
michael@0 459
michael@0 460 *aSame = jumpListCachePath.Equals(passedInParentPath);
michael@0 461 return NS_OK;
michael@0 462 }
michael@0 463
michael@0 464 // (static) For a given IShellLink, create and return a populated nsIJumpListShortcut.
michael@0 465 nsresult JumpListShortcut::GetJumpListShortcut(IShellLinkW *pLink, nsCOMPtr<nsIJumpListShortcut>& aShortcut)
michael@0 466 {
michael@0 467 NS_ENSURE_ARG_POINTER(pLink);
michael@0 468
michael@0 469 nsresult rv;
michael@0 470 HRESULT hres;
michael@0 471
michael@0 472 nsCOMPtr<nsILocalHandlerApp> handlerApp =
michael@0 473 do_CreateInstance(NS_LOCALHANDLERAPP_CONTRACTID, &rv);
michael@0 474 NS_ENSURE_SUCCESS(rv, rv);
michael@0 475
michael@0 476 wchar_t buf[MAX_PATH];
michael@0 477
michael@0 478 // Path
michael@0 479 hres = pLink->GetPath(buf, MAX_PATH, nullptr, SLGP_UNCPRIORITY);
michael@0 480 if (FAILED(hres))
michael@0 481 return NS_ERROR_INVALID_ARG;
michael@0 482
michael@0 483 nsCOMPtr<nsIFile> file;
michael@0 484 nsDependentString filepath(buf);
michael@0 485 rv = NS_NewLocalFile(filepath, false, getter_AddRefs(file));
michael@0 486 NS_ENSURE_SUCCESS(rv, rv);
michael@0 487
michael@0 488 rv = handlerApp->SetExecutable(file);
michael@0 489 NS_ENSURE_SUCCESS(rv, rv);
michael@0 490
michael@0 491 // Parameters
michael@0 492 hres = pLink->GetArguments(buf, MAX_PATH);
michael@0 493 if (SUCCEEDED(hres)) {
michael@0 494 LPWSTR *arglist;
michael@0 495 int32_t numArgs;
michael@0 496 int32_t idx;
michael@0 497
michael@0 498 arglist = ::CommandLineToArgvW(buf, &numArgs);
michael@0 499 if(arglist) {
michael@0 500 for (idx = 0; idx < numArgs; idx++) {
michael@0 501 // szArglist[i] is null terminated
michael@0 502 nsDependentString arg(arglist[idx]);
michael@0 503 handlerApp->AppendParameter(arg);
michael@0 504 }
michael@0 505 ::LocalFree(arglist);
michael@0 506 }
michael@0 507 }
michael@0 508
michael@0 509 rv = aShortcut->SetApp(handlerApp);
michael@0 510 NS_ENSURE_SUCCESS(rv, rv);
michael@0 511
michael@0 512 // Icon index or file location
michael@0 513 int iconIdx = 0;
michael@0 514 hres = pLink->GetIconLocation(buf, MAX_PATH, &iconIdx);
michael@0 515 if (SUCCEEDED(hres)) {
michael@0 516 // XXX How do we handle converting local files to images here? Do we need to?
michael@0 517 aShortcut->SetIconIndex(iconIdx);
michael@0 518
michael@0 519 // Obtain the local profile directory and construct the output icon file path
michael@0 520 // We only set the Icon Uri if we're sure it was from our icon cache.
michael@0 521 bool isInOurCache;
michael@0 522 if (NS_SUCCEEDED(IsPathInOurIconCache(aShortcut, buf, &isInOurCache)) &&
michael@0 523 isInOurCache) {
michael@0 524 nsCOMPtr<nsIURI> iconUri;
michael@0 525 nsAutoString path(buf);
michael@0 526 rv = NS_NewURI(getter_AddRefs(iconUri), path);
michael@0 527 if (NS_SUCCEEDED(rv)) {
michael@0 528 aShortcut->SetFaviconPageUri(iconUri);
michael@0 529 }
michael@0 530 }
michael@0 531 }
michael@0 532
michael@0 533 // Do we need the title and description? Probably not since handler app doesn't compare
michael@0 534 // these in equals.
michael@0 535
michael@0 536 return NS_OK;
michael@0 537 }
michael@0 538
michael@0 539 // (static) ShellItems are used to encapsulate links to things. We currently only support URI links,
michael@0 540 // but more support could be added, such as local file and directory links.
michael@0 541 nsresult JumpListLink::GetShellItem(nsCOMPtr<nsIJumpListItem>& item, nsRefPtr<IShellItem2>& aShellItem)
michael@0 542 {
michael@0 543 IShellItem2 *psi = nullptr;
michael@0 544 nsresult rv;
michael@0 545
michael@0 546 int16_t type;
michael@0 547 if (NS_FAILED(item->GetType(&type)))
michael@0 548 return NS_ERROR_INVALID_ARG;
michael@0 549
michael@0 550 if (type != nsIJumpListItem::JUMPLIST_ITEM_LINK)
michael@0 551 return NS_ERROR_INVALID_ARG;
michael@0 552
michael@0 553 nsCOMPtr<nsIJumpListLink> link = do_QueryInterface(item, &rv);
michael@0 554 NS_ENSURE_SUCCESS(rv, rv);
michael@0 555
michael@0 556 nsCOMPtr<nsIURI> uri;
michael@0 557 rv = link->GetUri(getter_AddRefs(uri));
michael@0 558 NS_ENSURE_SUCCESS(rv, rv);
michael@0 559
michael@0 560 nsAutoCString spec;
michael@0 561 rv = uri->GetSpec(spec);
michael@0 562 NS_ENSURE_SUCCESS(rv, rv);
michael@0 563
michael@0 564 // Create the IShellItem
michael@0 565 if (FAILED(WinUtils::SHCreateItemFromParsingName(
michael@0 566 NS_ConvertASCIItoUTF16(spec).get(),
michael@0 567 nullptr, IID_PPV_ARGS(&psi)))) {
michael@0 568 return NS_ERROR_INVALID_ARG;
michael@0 569 }
michael@0 570
michael@0 571 // Set the title
michael@0 572 nsAutoString linkTitle;
michael@0 573 link->GetUriTitle(linkTitle);
michael@0 574
michael@0 575 IPropertyStore* pPropStore = nullptr;
michael@0 576 HRESULT hres = psi->GetPropertyStore(GPS_DEFAULT, IID_IPropertyStore, (void**)&pPropStore);
michael@0 577 if (FAILED(hres))
michael@0 578 return NS_ERROR_UNEXPECTED;
michael@0 579
michael@0 580 PROPVARIANT pv;
michael@0 581 InitPropVariantFromString(linkTitle.get(), &pv);
michael@0 582
michael@0 583 // May fail due to shell item access permissions.
michael@0 584 pPropStore->SetValue(PKEY_ItemName, pv);
michael@0 585 pPropStore->Commit();
michael@0 586 pPropStore->Release();
michael@0 587
michael@0 588 PropVariantClear(&pv);
michael@0 589
michael@0 590 aShellItem = dont_AddRef(psi);
michael@0 591
michael@0 592 return NS_OK;
michael@0 593 }
michael@0 594
michael@0 595 // (static) For a given IShellItem, create and return a populated nsIJumpListLink.
michael@0 596 nsresult JumpListLink::GetJumpListLink(IShellItem *pItem, nsCOMPtr<nsIJumpListLink>& aLink)
michael@0 597 {
michael@0 598 NS_ENSURE_ARG_POINTER(pItem);
michael@0 599
michael@0 600 // We assume for now these are URI links, but through properties we could
michael@0 601 // query and create other types.
michael@0 602 nsresult rv;
michael@0 603 LPWSTR lpstrName = nullptr;
michael@0 604
michael@0 605 if (SUCCEEDED(pItem->GetDisplayName(SIGDN_URL, &lpstrName))) {
michael@0 606 nsCOMPtr<nsIURI> uri;
michael@0 607 nsAutoString spec(lpstrName);
michael@0 608
michael@0 609 rv = NS_NewURI(getter_AddRefs(uri), NS_ConvertUTF16toUTF8(spec));
michael@0 610 if (NS_FAILED(rv))
michael@0 611 return NS_ERROR_INVALID_ARG;
michael@0 612
michael@0 613 aLink->SetUri(uri);
michael@0 614
michael@0 615 ::CoTaskMemFree(lpstrName);
michael@0 616 }
michael@0 617
michael@0 618 return NS_OK;
michael@0 619 }
michael@0 620
michael@0 621 // Confirm the app is on the system
michael@0 622 bool JumpListShortcut::ExecutableExists(nsCOMPtr<nsILocalHandlerApp>& handlerApp)
michael@0 623 {
michael@0 624 nsresult rv;
michael@0 625
michael@0 626 if (!handlerApp)
michael@0 627 return false;
michael@0 628
michael@0 629 nsCOMPtr<nsIFile> executable;
michael@0 630 rv = handlerApp->GetExecutable(getter_AddRefs(executable));
michael@0 631 if (NS_SUCCEEDED(rv) && executable) {
michael@0 632 bool exists;
michael@0 633 executable->Exists(&exists);
michael@0 634 return exists;
michael@0 635 }
michael@0 636 return false;
michael@0 637 }
michael@0 638
michael@0 639 } // namespace widget
michael@0 640 } // namespace mozilla
michael@0 641

mercurial