sbBaseDevice.cpp
Go to the documentation of this file.
1 /* vim: set sw=2 :miv */
2 /*
3  *=BEGIN SONGBIRD GPL
4  *
5  * This file is part of the Songbird web player.
6  *
7  * Copyright(c) 2005-2011 POTI, Inc.
8  * http://www.songbirdnest.com
9  *
10  * This file may be licensed under the terms of of the
11  * GNU General Public License Version 2 (the ``GPL'').
12  *
13  * Software distributed under the License is distributed
14  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
15  * express or implied. See the GPL for the specific language
16  * governing rights and limitations.
17  *
18  * You should have received a copy of the GPL along with this
19  * program. If not, go to http://www.gnu.org/licenses/gpl.html
20  * or write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22  *
23  *=END SONGBIRD GPL
24  */
25 
26 #include "sbBaseDevice.h"
27 
28 #include <algorithm>
29 #include <cstddef>
30 #include <set>
31 
32 #include <prtime.h>
33 
34 #include <nsIDOMParser.h>
35 #include <nsIFileURL.h>
36 #include <nsIMutableArray.h>
37 #include <nsIPropertyBag2.h>
38 #include <nsITimer.h>
39 #include <nsIURI.h>
40 #include <nsIVariant.h>
41 #include <nsIPrefService.h>
42 #include <nsIPrefBranch.h>
43 #include <nsIProxyObjectManager.h>
44 
45 #include <nsAppDirectoryServiceDefs.h>
46 #include <nsArrayUtils.h>
47 #include <nsAutoLock.h>
48 #include <nsAutoPtr.h>
49 #include <nsComponentManagerUtils.h>
50 #include <nsCRT.h>
51 #include <nsDirectoryServiceUtils.h>
52 #include <nsMemory.h>
53 #include <nsNetUtil.h>
54 #include <nsServiceManagerUtils.h>
55 #include <nsThreadUtils.h>
56 #include <nsIDOMDocument.h>
57 #include <nsIDOMElement.h>
58 #include <nsIDOMNodeList.h>
59 #include <nsIDOMWindow.h>
60 #include <nsIPromptService.h>
61 #include <nsIScriptSecurityManager.h>
62 #include <nsISupportsPrimitives.h>
63 #include <nsIWritablePropertyBag.h>
64 #include <nsIWritablePropertyBag2.h>
65 #include <nsIXMLHttpRequest.h>
66 
67 #include <sbIDeviceContent.h>
68 #include <sbIDeviceCapabilities.h>
69 #include <sbIDeviceInfoRegistrar.h>
70 #include <sbIDeviceLibraryMediaSyncSettings.h>
71 #include <sbIDeviceLibrarySyncDiff.h>
72 #include <sbIDeviceLibrarySyncSettings.h>
73 #include <sbIDeviceEvent.h>
74 #include <sbIDeviceHelper.h>
75 #include <sbIDeviceManager.h>
76 #include <sbIDeviceProperties.h>
77 #include <sbIDownloadDevice.h>
78 #include <sbIJobCancelable.h>
79 #include <sbILibrary.h>
80 #include <sbILibraryDiffingService.h>
81 #include <sbILibraryUtils.h>
82 #include <sbILocalDatabaseSmartMediaList.h>
83 #include <sbIMediacoreManager.h>
84 #include <sbIMediacorePlaybackControl.h>
85 #include <sbIMediacoreSequencer.h>
86 #include <sbIMediacoreStatus.h>
87 #include <sbIMediaFileManager.h>
88 #include <sbIMediaInspector.h>
89 #include <sbIMediaItem.h>
90 #include <sbIMediaItemController.h>
91 #include <sbIMediaItemDownloader.h>
92 #include <sbIMediaItemDownloadJob.h>
93 #include <sbIMediaItemDownloadService.h>
94 #include <sbIMediaList.h>
95 #include <sbIOrderableMediaList.h>
96 #include <sbIPrompter.h>
97 #include <sbIPropertyManager.h>
98 #include <sbIPropertyUnitConverter.h>
99 #include <nsISupportsPrimitives.h>
100 #include <sbITranscodeManager.h>
101 #include <sbITranscodeAlbumArt.h>
102 #include <sbITranscodingConfigurator.h>
103 
104 #include <sbArray.h>
105 #include <sbArrayUtils.h>
106 #include <sbDeviceLibrary.h>
107 #include <sbDeviceStatus.h>
108 #include <sbFileUtils.h>
109 #include <sbJobUtils.h>
110 #include <sbLibraryUtils.h>
111 #include <sbLocalDatabaseCID.h>
113 #include <sbMemoryUtils.h>
114 #include <sbPrefBranch.h>
115 #include <sbPropertiesCID.h>
116 #include <sbPropertyBagUtils.h>
119 #include <sbStandardProperties.h>
120 #include <sbStringBundle.h>
121 #include <sbStringUtils.h>
122 #include <sbTranscodeUtils.h>
123 #include <sbURIUtils.h>
124 #include <sbVariantUtils.h>
125 #include <sbWatchFolderUtils.h>
126 
129 #include "sbDeviceStatusHelper.h"
132 #include "sbDeviceTranscoding.h"
133 #include "sbDeviceImages.h"
134 #include "sbDeviceUtils.h"
135 #include "sbDeviceXMLCapabilities.h"
136 #include "sbDeviceXMLInfo.h"
138 
139 /*
140  * To log this module, set the following environment variable:
141  * NSPR_LOG_MODULES=sbBaseDevice:5
142  */
143 #undef LOG
144 #undef TRACE
145 #ifdef PR_LOGGING
146 PRLogModuleInfo* gBaseDeviceLog = nsnull;
147 #define LOG(args) PR_LOG(gBaseDeviceLog, PR_LOG_WARN, args)
148 #define TRACE(args) PR_LOG(gBaseDeviceLog, PR_LOG_DEBUG, args)
149 #ifdef __GNUC__
150 #define __FUNCTION__ __PRETTY_FUNCTION__
151 #endif /* __GNUC__ */
152 #else
153 #define LOG(args) do{ } while(0)
154 #define TRACE(args) do { } while(0)
155 #endif
156 
157 // preference names
158 #define PREF_DEVICE_PREFERENCES_BRANCH "songbird.device."
159 #define PREF_DEVICE_LIBRARY_BASE "library."
160 #define PREF_WARNING "warning."
161 #define PREF_ORGANIZE_PREFIX "media_management.library."
162 #define PREF_ORGANIZE_ENABLED "media_management.library.enabled"
163 #define PREF_ORGANIZE_DIR_FORMAT "media_management.library.format.dir"
164 #define PREF_ORGANIZE_FILE_FORMAT "media_management.library.format.file"
165 #define SB_PROPERTY_UILIMITTYPE "http://songbirdnest.com/data/1.0#uiLimitType"
166 #define RANDOM_LISTNAME "device.error.not_enough_freespace.random_playlist_name"
167 
168 // default preferences
169 #define PREF_ORGANIZE_DIR_FORMAT_DEFAULT \
170  SB_PROPERTY_ARTISTNAME "," FILE_PATH_SEPARATOR "," SB_PROPERTY_ALBUMNAME
171 
172 #define BATCH_TIMEOUT 200 /* number of milliseconds to wait for batching */
173 #define BYTES_PER_10MB (10 * 1000 * 1000)
174 
175 // List of supported device content folders.
177 {
182 };
183 
184 static nsresult
185 GetPropertyBag(sbIDevice * aDevice, nsIPropertyBag2 ** aProperties)
186 {
187  TRACE(("%s", __FUNCTION__));
188  NS_ENSURE_ARG_POINTER(aDevice);
189  NS_ENSURE_ARG_POINTER(aProperties);
190 
191  nsCOMPtr<sbIDeviceProperties> deviceProperties;
192  nsresult rv = aDevice->GetProperties(getter_AddRefs(deviceProperties));
193  NS_ENSURE_SUCCESS(rv, rv);
194 
195  rv = deviceProperties->GetProperties(aProperties);
196  NS_ENSURE_SUCCESS(rv, rv);
197 
198  return NS_OK;
199 }
200 
201 
202 static nsresult
204  nsIWritablePropertyBag ** aProperties)
205 {
206  NS_ENSURE_ARG_POINTER(aDevice);
207  NS_ENSURE_ARG_POINTER(aProperties);
208 
209  nsresult rv;
210 
211  // Get the device properties.
212  nsCOMPtr<nsIPropertyBag2> roDeviceProperties;
213  rv = GetPropertyBag(aDevice, getter_AddRefs(roDeviceProperties));
214  NS_ENSURE_SUCCESS(rv, rv);
215 
216  return CallQueryInterface(roDeviceProperties, aProperties);
217 }
218 
220 {
221 public:
223  : mDevice(aDevice)
224  {}
226  NS_DECL_SBIMEDIALISTENUMERATIONLISTENER
227 private:
228  sbBaseDevice* mDevice;
229 };
230 
233 
234 NS_IMETHODIMP MediaListListenerAttachingEnumerator::OnEnumerationBegin(sbIMediaList*,
235  PRUint16 *_retval)
236 {
237  NS_ENSURE_ARG_POINTER(_retval);
239  return NS_OK;
240 }
241 
242 NS_IMETHODIMP MediaListListenerAttachingEnumerator::OnEnumeratedItem(sbIMediaList*,
243  sbIMediaItem* aItem,
244  PRUint16 *_retval)
245 {
246  NS_ENSURE_ARG_POINTER(aItem);
247  NS_ENSURE_ARG_POINTER(_retval);
248  NS_ENSURE_TRUE(mDevice, NS_ERROR_NOT_INITIALIZED);
249 
250  nsresult rv;
251 
252  nsCOMPtr<sbIMediaList> list(do_QueryInterface(aItem, &rv));
253  NS_ENSURE_SUCCESS(rv, rv);
254 
255  rv = mDevice->ListenToList(list);
256  NS_ENSURE_SUCCESS(rv, rv);
257 
259 
260  return NS_OK;
261 }
262 
263 NS_IMETHODIMP MediaListListenerAttachingEnumerator::OnEnumerationEnd(sbIMediaList*,
264  nsresult)
265 {
266  return NS_OK;
267 }
268 
270 {
271 public:
272  explicit ShowMediaListEnumerator(PRBool aHideMediaLists);
274  NS_DECL_SBIMEDIALISTENUMERATIONLISTENER
275 private:
276  PRBool mHideMediaLists;
277  nsString mHideMediaListsStringValue;
278 };
279 
282 
283 
284 ShowMediaListEnumerator::ShowMediaListEnumerator(PRBool aHideMediaLists)
285 : mHideMediaLists(aHideMediaLists)
286 {
287  mHideMediaListsStringValue = (mHideMediaLists == PR_TRUE) ?
288  NS_LITERAL_STRING("1") :
289  NS_LITERAL_STRING("0");
290 }
291 
292 NS_IMETHODIMP ShowMediaListEnumerator::OnEnumerationBegin(sbIMediaList*,
293  PRUint16 *_retval)
294 {
295  NS_ENSURE_ARG_POINTER(_retval);
297  return NS_OK;
298 }
299 
300 NS_IMETHODIMP ShowMediaListEnumerator::OnEnumeratedItem(sbIMediaList*,
301  sbIMediaItem* aItem,
302  PRUint16 *_retval)
303 {
304  NS_ENSURE_ARG_POINTER(aItem);
305  NS_ENSURE_ARG_POINTER(_retval);
306 
307  nsresult rv = aItem->SetProperty(NS_LITERAL_STRING(SB_PROPERTY_HIDDEN),
308  mHideMediaListsStringValue);
309  NS_ENSURE_SUCCESS(rv, rv);
310 
312 
313  return NS_OK;
314 }
315 
316 NS_IMETHODIMP ShowMediaListEnumerator::OnEnumerationEnd(sbIMediaList*,
317  nsresult)
318 {
319  return NS_OK;
320 }
321 
324  sbIMediaItem * aItem,
325  sbIMediaList * aList,
326  PRUint32 aIndex,
327  PRUint32 aOtherIndex,
328  nsISupports * aData)
329 {
330  TransferRequest * request;
331  NS_NEWXPCOM(request, TransferRequest);
332  if (request) {
333  request->SetType(aType);
334  request->item = aItem;
335  request->list = aList;
336  request->index = aIndex;
337  request->otherIndex = aOtherIndex;
338  request->data = aData;
339 
340  nsresult rv;
341  nsCOMPtr<sbIMediaItem> localItem = do_QueryInterface(aItem, &rv);
342 
343  if (NS_SUCCEEDED(rv) && aType != TransferRequest::REQUEST_UPDATE) {
344  nsString contentType;
345  localItem->GetContentType(contentType);
346 
347  if (contentType.EqualsLiteral("audio")) {
349  }
350  else if (contentType.EqualsLiteral("video")) {
352  }
353  else if (contentType.EqualsLiteral("image")) {
355  }
356  else {
358  }
359  }
360 
361  // Delete, write, and read requests that aren't playlists are countable
362  switch (aType) {
366  // These requests are countable unless they involve playlists
367  if (!request->IsPlaylist()) {
368  request->SetIsCountable(true);
369  }
370  default:
371  break;
372  }
373  }
374  return request;
375 }
376 
378 {
379  if (!list)
380  return PR_FALSE;
381  // Is this a playlist
382  nsCOMPtr<sbILibrary> libTest = do_QueryInterface(list);
383  return libTest ? PR_FALSE : PR_TRUE;
384 }
385 
387  transcodeProfile(nsnull),
388  contentSrcSet(PR_FALSE),
389  destinationMediaPresent(PR_FALSE),
390  destinationCompatibility(COMPAT_SUPPORTED),
391  transcoded(PR_FALSE)
392 {
393 }
394 
396 {
397  NS_IF_RELEASE(transcodeProfile);
398 }
399 
404  mPreferenceLock(nsnull),
405  mMusicLimitPercent(100),
406  mDeviceTranscoding(nsnull),
407  mDeviceImages(nsnull),
410  mSyncType(0),
412  mConnected(PR_FALSE),
413  mVolumeLock(nsnull)
414 {
415  mStatus = new sbDeviceStatusHelper(this);
416  NS_ENSURE_TRUE(mStatus, /* void */ );
417 
418 #ifdef PR_LOGGING
419  if (!gBaseDeviceLog) {
420  gBaseDeviceLog = PR_NewLogModule( "sbBaseDevice" );
421  }
422 #endif /* PR_LOGGING */
423 
424  #if defined(__GNUC__) && !defined(DEBUG)
425  PRBool __attribute__((unused)) success;
426  #else
427  PRBool success;
428  #endif
429 
430  mStateLock = nsAutoLock::NewLock(__FILE__ "::mStateLock");
431  NS_ASSERTION(mStateLock, "Failed to allocate state lock");
432 
433  mPreviousStateLock = nsAutoLock::NewLock(__FILE__ "::mPreviousStateLock");
434  NS_ASSERTION(mPreviousStateLock, "Failed to allocate state lock");
435 
436  mPreferenceLock = nsAutoLock::NewLock(__FILE__ "::mPreferenceLock");
437  NS_ASSERTION(mPreferenceLock, "Failed to allocate preference lock");
438 
439  mConnectLock = PR_NewRWLock(PR_RWLOCK_RANK_NONE,
440  __FILE__"::mConnectLock");
441  NS_ASSERTION(mConnectLock, "Failed to allocate connection lock");
442 
443  // Create the volume lock.
444  mVolumeLock = nsAutoLock::NewLock("sbBaseDevice::mVolumeLock");
445  NS_ASSERTION(mVolumeLock, "Failed to allocate volume lock");
446 
447  // Initialize the track source table.
448  success = mTrackSourceTable.Init();
449  NS_ASSERTION(success, "Failed to initialize track source table");
450 
451  // Initialize the volume tables.
452  success = mVolumeGUIDTable.Init();
453  NS_ASSERTION(success, "Failed to initialize volume GUID table");
454 
455  success = mVolumeLibraryGUIDTable.Init();
456  NS_ASSERTION(success, "Failed to initialize volume library GUID table");
457 
458  // the typical case is 1 library per device
459  success = mOrganizeLibraryPrefs.Init(1);
460  NS_ASSERTION(success, "Failed to initialize organize prefs hashtable");
461 
462  success = mMediaListListeners.Init();
463  NS_ASSERTION(success, "Failed to initialize list listener hashtable");
464 
465 
466 }
467 
468 /* virtual */
470 {
471  if (mVolumeLock)
472  nsAutoLock::DestroyLock(mVolumeLock);
473  mVolumeLock = nsnull;
474 
475  mVolumeList.Clear();
476  mTrackSourceTable.Clear();
477  mVolumeGUIDTable.Clear();
478  mVolumeLibraryGUIDTable.Clear();
479 
480  if (mPreferenceLock)
481  nsAutoLock::DestroyLock(mPreferenceLock);
482 
483  if (mStateLock)
484  nsAutoLock::DestroyLock(mStateLock);
485 
486  if (mPreviousStateLock)
487  nsAutoLock::DestroyLock(mPreviousStateLock);
488 
489  if (mConnectLock)
490  PR_DestroyRWLock(mConnectLock);
491  mConnectLock = nsnull;
492 
493  if (mDeviceTranscoding) {
494  delete mDeviceTranscoding;
495  }
496 
497  if (mDeviceImages) {
498  delete mDeviceImages;
499  }
500 
501  if (mLibraryListener) {
502  mLibraryListener->Destroy();
503  }
504 }
505 
506 NS_IMETHODIMP sbBaseDevice::Connect()
507 {
508  return NS_OK;
509 }
510 
512 {
513  // Cancel any pending deferred setup device timer.
515  mDeferredSetupDeviceTimer->Cancel();
516  mDeferredSetupDeviceTimer = nsnull;
517  }
518 
519  // Tell the thread to shutdown. The thread will then invoke the device
520  // specific disconnect logic on the main thread. If we disconnect more than
521  // once this will error, but that is OK, it's exepected to return an error
522  nsresult rv = mRequestThreadQueue->Stop();
523  if (rv == NS_ERROR_NOT_AVAILABLE) {
524  NS_WARNING("Attempting to disconnect twice");
525  }
526  else {
527  NS_ENSURE_SUCCESS(rv, rv);
528  }
529 
530  return NS_OK;
531 }
532 
533 NS_IMETHODIMP sbBaseDevice::SubmitRequest(PRUint32 aRequestType,
534  nsIPropertyBag2 *aRequestParameters)
535 {
536  nsRefPtr<TransferRequest> transferRequest;
537  nsresult rv = CreateTransferRequest(aRequestType,
538  aRequestParameters,
539  getter_AddRefs(transferRequest));
540  NS_ENSURE_SUCCESS(rv, rv);
541 
542  rv = mRequestThreadQueue->PushRequest(transferRequest);
543  NS_ENSURE_SUCCESS(rv, rv);
544 
545  return NS_OK;
546 
547 }
548 
550 {
551  nsresult rv;
552 
553  nsCOMPtr<sbIDeviceContent> content;
554  rv = GetContent(getter_AddRefs(content));
555  NS_ENSURE_SUCCESS(rv, rv);
556 
557  nsCOMPtr<nsIArray> libraries;
558  rv = content->GetLibraries(getter_AddRefs(libraries));
559  NS_ENSURE_SUCCESS(rv, rv);
560 
561  PRUint32 libraryCount;
562  rv = libraries->GetLength(&libraryCount);
563  NS_ENSURE_SUCCESS(rv, rv);
564 
565  for (PRUint32 index = 0; index < libraryCount; ++index) {
566  nsCOMPtr<sbIDeviceLibrary> deviceLib =
567  do_QueryElementAt(libraries, index, &rv);
568  NS_ENSURE_SUCCESS(rv, rv);
569 
570  rv = deviceLib->Sync();
571  NS_ENSURE_SUCCESS(rv, rv);
572  }
573 
574  return NS_OK;
575 }
576 
577 nsresult sbBaseDevice::PushRequest(const PRUint32 aType,
578  sbIMediaItem* aItem,
579  sbIMediaList* aList,
580  PRUint32 aIndex,
581  PRUint32 aOtherIndex,
582  nsISupports * aData)
583 {
584  NS_ENSURE_TRUE(aType != 0, NS_ERROR_INVALID_ARG);
585 
586  nsresult rv;
587 
588  nsRefPtr<TransferRequest> req = TransferRequest::New(aType,
589  aItem,
590  aList,
591  aIndex,
592  aOtherIndex,
593  aData);
594  NS_ENSURE_TRUE(req, NS_ERROR_OUT_OF_MEMORY);
595 
596  rv = mRequestThreadQueue->PushRequest(req);
597  NS_ENSURE_SUCCESS(rv, rv);
598 
599  return NS_OK;
600 }
601 
603 {
604  return mRequestThreadQueue->BatchBegin();
605 }
606 
608 {
609  return mRequestThreadQueue->BatchEnd();
610 }
611 
612 nsresult
614  (TransferRequest* aRequest,
615  sbITemporaryFileFactory** aTemporaryFileFactory)
616 {
617  // Validate arguments.
618  NS_ENSURE_ARG_POINTER(aRequest);
619  NS_ENSURE_ARG_POINTER(aTemporaryFileFactory);
620 
621  // Function variables.
622  nsresult rv;
623 
624  // Get the request temporary file factory, creating one if necessary.
625  nsCOMPtr<sbITemporaryFileFactory>
626  temporaryFileFactory = aRequest->temporaryFileFactory;
627  if (!temporaryFileFactory) {
628  temporaryFileFactory = do_CreateInstance(SB_TEMPORARYFILEFACTORY_CONTRACTID,
629  &rv);
630  NS_ENSURE_SUCCESS(rv, rv);
631  aRequest->temporaryFileFactory = temporaryFileFactory;
632  }
633 
634  // Return results.
635  temporaryFileFactory.forget(aTemporaryFileFactory);
636 
637  return NS_OK;
638 }
639 
643 static nsresult DispatchDownloadError(sbBaseDevice * aDevice,
644  nsAString const & aMessage,
645  sbIMediaItem * aItem)
646 {
647  nsresult rv;
648 
649  NS_ASSERTION(aDevice, "aDevice null in DispatchDownloadError");
650 
651  // Create the error info.
652  sbPropertyBagHelper errorInfo;
653  errorInfo["message"] = nsString(aMessage);
654  NS_ENSURE_SUCCESS(errorInfo.rv(), errorInfo.rv());
655  errorInfo["item"] = aItem;
656  NS_ENSURE_SUCCESS(errorInfo.rv(), errorInfo.rv());
657 
658  // Dispatch the error event.
659  rv = aDevice->CreateAndDispatchEvent(
661  sbNewVariant(errorInfo.GetBag()));
662  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to dispatch download error");
663 
664  return NS_OK;
665 }
666 
671 {
672 public:
675  TransferRequest * aRequest,
676  PRUint32 aBatchCount,
677  sbBaseDevice * aDevice) :
679  aOperation,
680  aRequest,
681  aBatchCount),
682  mDevice(aDevice),
683  mDownloadJob(nsnull),
684  mItem(aRequest->item)
685  {
686 
687  }
689  {
690  nsresult rv;
691 
692  if (mDevice && mItem) {
693  nsString errorMessage;
694  nsCOMPtr<nsIStringEnumerator> errorEnumerator;
695  if (mDownloadJob) {
696  PRUint32 errors;
697  rv = mDownloadJob->GetErrorCount(&errors);
698  if (NS_SUCCEEDED(rv) && errors) {
699  rv = mDownloadJob->GetErrorMessages(getter_AddRefs(errorEnumerator));
700  if (NS_SUCCEEDED(rv)) {
701  PRBool more;
702  rv = errorEnumerator->HasMore(&more);
703  if (NS_SUCCEEDED(rv) && more) {
704  nsString message;
705  errorEnumerator->GetNext(message);
706  if (!errorMessage.IsEmpty()) {
707  errorMessage.Append(NS_LITERAL_STRING("\n"));
708  }
709  errorMessage.Append(message);
710  }
711  }
712  }
713  }
714  // Return a generic error message if there is nothing specific
715  if (errorMessage.IsEmpty()) {
717  errorMessage = bundle.Get("device.error.download",
718  "Download of media failed.");
719  }
720  DispatchDownloadError(mDevice,
721  errorMessage,
722  mItem);
723  // If we're dispatch the error then we don't want the parent auto class
724  // to dispatch an error
726  }
727  }
729  {
730  mDownloadJob = aDownloadJob;
731  }
732  void forget()
733  {
734  mDevice = nsnull;
735  // We're forgetting so we need prevent the base class from dispatching an
736  // error
738  }
739  void SetResult(nsresult aResult)
740  {
742  // If this is a success result we don't need to perform an error dispatch
743  if (NS_SUCCEEDED(aResult)) {
744  mDevice = nsnull;
745  }
746  }
747 private:
748  // Non-owning reference, this can't outlive the device
749  sbBaseDevice * mDevice;
750  // We hold a reference, just to be safe, as this is an auto class and the
751  // compiler might destroy the nsCOMPtr that holds this before our class.
752  nsCOMPtr<sbIMediaItemDownloadJob> mDownloadJob;
753  // Non-owning reference, we rely on the request to keep the item alive.
754  sbIMediaItem * mItem;
755 };
756 
757 nsresult
759  PRUint32 aBatchCount,
760  sbDeviceStatusHelper* aDeviceStatusHelper)
761 {
762  // Validate arguments.
763  NS_ENSURE_ARG_POINTER(aRequest);
764  NS_ENSURE_ARG_POINTER(aDeviceStatusHelper);
765 
766  // Function variables.
767  nsresult rv;
768 
769  sbDownloadAutoComplete autoComplete(
770  aDeviceStatusHelper,
772  aRequest,
773  aBatchCount,
774  this);
775 
776  // Get the request volume info.
777  nsRefPtr<sbBaseDeviceVolume> volume;
778  nsCOMPtr<sbIDeviceLibrary> deviceLibrary;
779 
780  rv = GetVolumeForItem(aRequest->item, getter_AddRefs(volume));
781  NS_ENSURE_SUCCESS(rv, rv);
782  rv = volume->GetDeviceLibrary(getter_AddRefs(deviceLibrary));
783  NS_ENSURE_SUCCESS(rv, rv);
784 
785  // Get the download service.
786  nsCOMPtr<sbIMediaItemDownloadService> downloadService =
787  do_GetService("@songbirdnest.com/Songbird/MediaItemDownloadService;1",
788  &rv);
789  NS_ENSURE_SUCCESS(rv, rv);
790 
791  // Get a downloader for the request item. If none is returned, the request
792  // item either doesn't need to be downloaded or cannot be downloaded.
793  nsCOMPtr<sbIMediaItemDownloader> downloader;
794  rv = downloadService->GetDownloader(aRequest->item,
795  deviceLibrary,
796  getter_AddRefs(downloader));
797  NS_ENSURE_SUCCESS(rv, rv);
798  if (!downloader) {
799  // Don't error, if item doesn't need to be downloaded
800  autoComplete.forget();
801  return NS_OK;
802  }
803  // Update status and set to auto-complete.
804  aDeviceStatusHelper->ChangeState(STATE_DOWNLOADING);
805 
806  // Create a download job.
807  // TODO: Add a writable temporaryFileFactory attribute to
808  // sbIMediaItemDownloadJob and set it to the request
809  // temporaryFileFactory.
810  nsCOMPtr<sbIMediaItemDownloadJob> downloadJob;
811  rv = downloader->CreateDownloadJob(aRequest->item,
812  deviceLibrary,
813  getter_AddRefs(downloadJob));
814  NS_ENSURE_SUCCESS(rv, rv);
815 
816  autoComplete.SetDownloadJob(downloadJob);
817 
818  // Set the download job temporary file factory.
819  nsCOMPtr<sbITemporaryFileFactory> temporaryFileFactory;
820  rv = GetRequestTemporaryFileFactory(aRequest,
821  getter_AddRefs(temporaryFileFactory));
822  NS_ENSURE_SUCCESS(rv, rv);
823  rv = downloadJob->SetTemporaryFileFactory(temporaryFileFactory);
824  NS_ENSURE_SUCCESS(rv, rv);
825 
826  // Get the download job progress.
827  nsCOMPtr<sbIJobProgress>
828  downloadJobProgress = do_MainThreadQueryInterface(downloadJob, &rv);
829  NS_ENSURE_SUCCESS(rv, rv);
830 
831  // Set up to auto-cancel the job.
832  nsCOMPtr<sbIJobCancelable> cancel = do_QueryInterface(downloadJobProgress);
833  sbAutoJobCancel autoCancel(cancel);
834 
835  PRMonitor * stopWaitMonitor = mRequestThreadQueue->GetStopWaitMonitor();
836 
837  // Add a device job progress listener.
838  nsRefPtr<sbDeviceProgressListener> listener;
839  rv = sbDeviceProgressListener::New(getter_AddRefs(listener),
840  stopWaitMonitor,
841  aDeviceStatusHelper);
842  NS_ENSURE_SUCCESS(rv, rv);
843  rv = downloadJobProgress->AddJobProgressListener(listener);
844  NS_ENSURE_SUCCESS(rv, rv);
845 
846  // Start the download job.
847  rv = downloadJob->Start();
848  NS_ENSURE_SUCCESS(rv, rv);
849 
850  // Wait for the download job to complete.
851  PRBool isComplete = PR_FALSE;
852  while (!isComplete) {
853  // Operate within the request wait monitor.
854  nsAutoMonitor monitor(stopWaitMonitor);
855 
856  // Check for abort.
857  if (IsRequestAborted()) {
858  return NS_ERROR_ABORT;
859  }
860 
861  // Check if the job is complete.
862  isComplete = listener->IsComplete();
863 
864  // If not complete, wait for completion. If requests are cancelled, the
865  // request wait monitor will be notified.
866  if (!isComplete)
867  monitor.Wait();
868  }
869 
870  // Forget auto-cancel.
871  autoCancel.forget();
872 
873  // Check for download errors.
874  nsCOMPtr<nsIStringEnumerator> errorMessages;
875  rv = downloadJob->GetErrorMessages(getter_AddRefs(errorMessages));
876  NS_ENSURE_SUCCESS(rv, rv);
877  if (errorMessages) {
878  PRBool hasMore;
879  rv = errorMessages->HasMore(&hasMore);
880  NS_ENSURE_SUCCESS(rv, rv);
881  if (hasMore) {
882  // Release the enumerator just ot be safe since the auto class will
883  // be enumerating
884  errorMessages = nsnull;
885  autoComplete.SetResult(NS_ERROR_FAILURE);
886  return NS_ERROR_FAILURE;
887  }
888  }
889 
890  // Get the downloaded file.
891  rv = downloadJob->GetDownloadedFile(getter_AddRefs(aRequest->downloadedFile));
892  NS_ENSURE_SUCCESS(rv, rv);
893 
894  // Set the downloaded media item properties.
895  nsCOMPtr<sbIPropertyArray> properties;
896  rv = downloadJob->GetProperties(getter_AddRefs(properties));
897  NS_ENSURE_SUCCESS(rv, rv);
898  {
899  sbDeviceListenerIgnore ignore(this, aRequest->item);
900  rv = aRequest->item->SetProperties(properties);
901  NS_ENSURE_SUCCESS(rv, rv);
902  }
903 
904  // Update the request item origin and content source.
905  nsCOMPtr<nsIURI> downloadedFileURI;
906  rv = sbNewFileURI(aRequest->downloadedFile,
907  getter_AddRefs(downloadedFileURI));
908  NS_ENSURE_SUCCESS(rv, rv);
909  rv = UpdateOriginAndContentSrc(aRequest, downloadedFileURI);
910  NS_ENSURE_SUCCESS(rv, rv);
911 
912  // Operation completed without error.
913  autoComplete.SetResult(NS_OK);
914 
915  return NS_OK;
916 }
917 
919  const nsAString & aPrefName,
920  nsIVariant **_retval)
921 {
922  NS_ENSURE_ARG_POINTER(aPrefBranch);
923  NS_ENSURE_ARG_POINTER(_retval);
924  NS_ENSURE_FALSE(aPrefName.IsEmpty(), NS_ERROR_INVALID_ARG);
925  nsresult rv;
926 
927  NS_ConvertUTF16toUTF8 prefNameUTF8(aPrefName);
928 
929  // get tht type of the pref
930  PRInt32 prefType;
931  rv = aPrefBranch->GetPrefType(prefNameUTF8.get(), &prefType);
932  NS_ENSURE_SUCCESS(rv, rv);
933 
934  // create a writable variant
935  nsCOMPtr<nsIWritableVariant> writableVariant =
936  do_CreateInstance("@songbirdnest.com/Songbird/Variant;1", &rv);
937  NS_ENSURE_SUCCESS(rv, rv);
938 
939  // get the value of our pref
940  switch (prefType) {
941  case nsIPrefBranch::PREF_INVALID: {
942  rv = writableVariant->SetAsEmpty();
943  NS_ENSURE_SUCCESS(rv, rv);
944  break;
945  }
946  case nsIPrefBranch::PREF_STRING: {
947  char* _value = NULL;
948  rv = aPrefBranch->GetCharPref(prefNameUTF8.get(), &_value);
949  NS_ENSURE_SUCCESS(rv, rv);
950 
951  nsCString value;
952  value.Adopt(_value);
953 
954  // set the value of the variant to the value of the pref
955  rv = writableVariant->SetAsACString(value);
956  NS_ENSURE_SUCCESS(rv, rv);
957  break;
958  }
959  case nsIPrefBranch::PREF_INT: {
960  PRInt32 value;
961  rv = aPrefBranch->GetIntPref(prefNameUTF8.get(), &value);
962  NS_ENSURE_SUCCESS(rv, rv);
963 
964  rv = writableVariant->SetAsInt32(value);
965  NS_ENSURE_SUCCESS(rv, rv);
966  break;
967  }
968  case nsIPrefBranch::PREF_BOOL: {
969  PRBool value;
970  rv = aPrefBranch->GetBoolPref(prefNameUTF8.get(), &value);
971  NS_ENSURE_SUCCESS(rv, rv);
972 
973  rv = writableVariant->SetAsBool(value);
974  NS_ENSURE_SUCCESS(rv, rv);
975  break;
976  }
977  }
978 
979  return CallQueryInterface(writableVariant, _retval);
980 }
981 
982 /* nsIVariant getPreference (in AString aPrefName); */
983 NS_IMETHODIMP sbBaseDevice::GetPreference(const nsAString & aPrefName, nsIVariant **_retval)
984 {
985  NS_ENSURE_ARG_POINTER(_retval);
986  NS_ENSURE_FALSE(aPrefName.IsEmpty(), NS_ERROR_INVALID_ARG);
987  nsresult rv;
988 
989  // special case device capabilities preferences
990  if (aPrefName.Equals(NS_LITERAL_STRING("capabilities"))) {
991  return GetCapabilitiesPreference(_retval);
992  }
993 
994  // get the pref branch for this device
995  nsCOMPtr<nsIPrefBranch> prefBranch;
996  rv = GetPrefBranch(getter_AddRefs(prefBranch));
997  NS_ENSURE_SUCCESS(rv, rv);
998 
999  return GetPreferenceInternal(prefBranch, aPrefName, _retval);
1000 }
1001 
1002 /* void setPreference (in AString aPrefName, in nsIVariant aPrefValue); */
1003 NS_IMETHODIMP sbBaseDevice::SetPreference(const nsAString & aPrefName, nsIVariant *aPrefValue)
1004 {
1005  NS_ENSURE_ARG_POINTER(aPrefValue);
1006  NS_ENSURE_FALSE(aPrefName.IsEmpty(), NS_ERROR_INVALID_ARG);
1007  nsresult rv;
1008 
1009  // get the pref branch for this device
1010  nsCOMPtr<nsIPrefBranch> prefBranch;
1011  rv = GetPrefBranch(getter_AddRefs(prefBranch));
1012  NS_ENSURE_SUCCESS(rv, rv);
1013 
1014  return SetPreferenceInternal(prefBranch, aPrefName, aPrefValue);
1015 }
1016 
1018  const nsAString & aPrefName,
1019  nsIVariant *aPrefValue)
1020 {
1021  NS_ENSURE_ARG_POINTER(aPrefValue);
1022  NS_ENSURE_FALSE(aPrefName.IsEmpty(), NS_ERROR_INVALID_ARG);
1023  nsresult rv;
1024 
1025  PRBool hasChanged = PR_FALSE;
1026  rv = SetPreferenceInternal(aPrefBranch, aPrefName, aPrefValue, &hasChanged);
1027  NS_ENSURE_SUCCESS(rv, rv);
1028 
1029  if (hasChanged) {
1030  // apply the preference
1031  ApplyPreference(aPrefName, aPrefValue);
1032 
1033  // fire the pref change event
1034  nsCOMPtr<sbIDeviceManager2> devMgr =
1035  do_GetService("@songbirdnest.com/Songbird/DeviceManager;2", &rv);
1036  NS_ENSURE_SUCCESS(rv, rv);
1037 
1039  sbNewVariant(aPrefName),
1040  PR_FALSE);
1041  NS_ENSURE_SUCCESS(rv, rv);
1042  }
1043 
1044  return NS_OK;
1045 }
1046 
1048  const nsAString& aPrefName,
1049  nsIVariant* aPrefValue,
1050  PRBool* aHasChanged)
1051 {
1052  // get the pref branch for this device
1053  nsCOMPtr<nsIPrefBranch> prefBranch;
1054  nsresult rv = GetPrefBranch(getter_AddRefs(prefBranch));
1055  NS_ENSURE_SUCCESS(rv, rv);
1056 
1057  return SetPreferenceInternal(prefBranch, aPrefName, aPrefValue, aHasChanged);
1058 }
1059 
1061  const nsAString& aPrefName,
1062  nsIVariant* aPrefValue,
1063  PRBool* aHasChanged)
1064 {
1065  NS_ENSURE_ARG_POINTER(aPrefValue);
1066  NS_ENSURE_FALSE(aPrefName.IsEmpty(), NS_ERROR_INVALID_ARG);
1067  nsresult rv;
1068 
1069  NS_ConvertUTF16toUTF8 prefNameUTF8(aPrefName);
1070 
1071  // figure out what sort of variant we have
1072  PRUint16 dataType;
1073  rv = aPrefValue->GetDataType(&dataType);
1074  NS_ENSURE_SUCCESS(rv, rv);
1075 
1076  // figure out what sort of data we used to have
1077  PRInt32 prefType;
1078  rv = aPrefBranch->GetPrefType(prefNameUTF8.get(), &prefType);
1079  NS_ENSURE_SUCCESS(rv, rv);
1080 
1081  PRBool hasChanged = PR_FALSE;
1082 
1083  switch (dataType) {
1084  case nsIDataType::VTYPE_INT8:
1085  case nsIDataType::VTYPE_INT16:
1086  case nsIDataType::VTYPE_INT32:
1087  case nsIDataType::VTYPE_INT64:
1088  case nsIDataType::VTYPE_UINT8:
1089  case nsIDataType::VTYPE_UINT16:
1090  case nsIDataType::VTYPE_UINT32:
1091  case nsIDataType::VTYPE_UINT64:
1092  case nsIDataType::VTYPE_FLOAT:
1093  case nsIDataType::VTYPE_DOUBLE:
1094  {
1095  // some sort of number
1096  PRInt32 oldValue, value;
1097  rv = aPrefValue->GetAsInt32(&value);
1098  NS_ENSURE_SUCCESS(rv, rv);
1099 
1100  if (prefType != nsIPrefBranch::PREF_INT) {
1101  hasChanged = PR_TRUE;
1102  } else {
1103  rv = aPrefBranch->GetIntPref(prefNameUTF8.get(), &oldValue);
1104  if (NS_SUCCEEDED(rv) && oldValue != value) {
1105  hasChanged = PR_TRUE;
1106  }
1107  }
1108 
1109  rv = aPrefBranch->SetIntPref(prefNameUTF8.get(), value);
1110  NS_ENSURE_SUCCESS(rv, rv);
1111 
1112  break;
1113  }
1114 
1115  case nsIDataType::VTYPE_BOOL:
1116  {
1117  // a bool pref
1118  PRBool oldValue, value;
1119  rv = aPrefValue->GetAsBool(&value);
1120  NS_ENSURE_SUCCESS(rv, rv);
1121 
1122  if (prefType != nsIPrefBranch::PREF_BOOL) {
1123  hasChanged = PR_TRUE;
1124  } else {
1125  rv = aPrefBranch->GetBoolPref(prefNameUTF8.get(), &oldValue);
1126  if (NS_SUCCEEDED(rv) && oldValue != value) {
1127  hasChanged = PR_TRUE;
1128  }
1129  }
1130 
1131  rv = aPrefBranch->SetBoolPref(prefNameUTF8.get(), value);
1132  NS_ENSURE_SUCCESS(rv, rv);
1133 
1134  break;
1135  }
1136 
1137  case nsIDataType::VTYPE_VOID:
1138  case nsIDataType::VTYPE_EMPTY:
1139  {
1140  // unset the pref
1141  if (prefType != nsIPrefBranch::PREF_INVALID) {
1142  rv = aPrefBranch->ClearUserPref(prefNameUTF8.get());
1143  NS_ENSURE_SUCCESS(rv, rv);
1144  hasChanged = PR_TRUE;
1145  }
1146 
1147  break;
1148  }
1149 
1150  default:
1151  {
1152  // assume a string
1153  nsCString value;
1154  rv = aPrefValue->GetAsACString(value);
1155  NS_ENSURE_SUCCESS(rv, rv);
1156 
1157  if (prefType != nsIPrefBranch::PREF_STRING) {
1158  hasChanged = PR_TRUE;
1159  } else {
1160  char* oldValue;
1161  rv = aPrefBranch->GetCharPref(prefNameUTF8.get(), &oldValue);
1162  if (NS_SUCCEEDED(rv)) {
1163  if (!(value.Equals(oldValue))) {
1164  hasChanged = PR_TRUE;
1165  }
1166  NS_Free(oldValue);
1167  }
1168  }
1169 
1170  rv = aPrefBranch->SetCharPref(prefNameUTF8.get(), value.get());
1171  NS_ENSURE_SUCCESS(rv, rv);
1172 
1173  break;
1174  }
1175  }
1176 
1177  // return has changed status
1178  if (aHasChanged)
1179  *aHasChanged = hasChanged;
1180 
1181  return NS_OK;
1182 }
1183 
1184 nsresult sbBaseDevice::HasPreference(nsAString& aPrefName,
1185  PRBool* aHasPreference)
1186 {
1187  // Validate arguments.
1188  NS_ENSURE_ARG_POINTER(aHasPreference);
1189 
1190  // Function variables.
1191  nsresult rv;
1192 
1193  // Try getting the preference.
1194  nsCOMPtr<nsIVariant> prefValue;
1195  rv = GetPreference(aPrefName, getter_AddRefs(prefValue));
1196  NS_ENSURE_SUCCESS(rv, rv);
1197  if (!prefValue) {
1198  *aHasPreference = PR_FALSE;
1199  return NS_OK;
1200  }
1201 
1202  // Preference does not exist if it's empty or void.
1203  PRUint16 dataType;
1204  rv = prefValue->GetDataType(&dataType);
1205  NS_ENSURE_SUCCESS(rv, rv);
1206  if ((dataType == nsIDataType::VTYPE_EMPTY) ||
1207  (dataType == nsIDataType::VTYPE_VOID)) {
1208  *aHasPreference = PR_FALSE;
1209  return NS_OK;
1210  }
1211 
1212  // Preference exists.
1213  *aHasPreference = PR_TRUE;
1214 
1215  return NS_OK;
1216 }
1217 
1218 /* readonly attribute boolean isDirectTranscoding; */
1219 NS_IMETHODIMP sbBaseDevice::GetIsDirectTranscoding(PRBool *aIsDirect)
1220 {
1221  *aIsDirect = PR_TRUE;
1222  return NS_OK;
1223 }
1224 
1225 /* readonly attribute boolean isBusy; */
1226 NS_IMETHODIMP sbBaseDevice::GetIsBusy(PRBool *aIsBusy)
1227 {
1228  NS_ENSURE_ARG_POINTER(aIsBusy);
1229  NS_ENSURE_TRUE(mStateLock, NS_ERROR_NOT_INITIALIZED);
1230  nsAutoLock lock(mStateLock);
1231  switch (mState) {
1232  case STATE_IDLE:
1233  case STATE_CANCEL:
1234  case STATE_DOWNLOAD_PAUSED:
1235  case STATE_UPLOAD_PAUSED:
1236  *aIsBusy = PR_FALSE;
1237  break;
1238 
1239  default:
1240  *aIsBusy = PR_TRUE;
1241  break;
1242  }
1243  return NS_OK;
1244 }
1245 
1246 /* readonly attribute boolean canDisconnect; */
1247 NS_IMETHODIMP sbBaseDevice::GetCanDisconnect(PRBool *aCanDisconnect)
1248 {
1249  NS_ENSURE_ARG_POINTER(aCanDisconnect);
1250  NS_ENSURE_TRUE(mStateLock, NS_ERROR_NOT_INITIALIZED);
1251  nsAutoLock lock(mStateLock);
1252  switch(mState) {
1253  case STATE_IDLE:
1254  case STATE_CANCEL:
1255  case STATE_MOUNTING:
1256  case STATE_DISCONNECTED:
1257  case STATE_DOWNLOAD_PAUSED:
1258  case STATE_UPLOAD_PAUSED:
1259  *aCanDisconnect = PR_TRUE;
1260  break;
1261 
1262  default:
1263  *aCanDisconnect = PR_FALSE;
1264  break;
1265  }
1266  return NS_OK;
1267 }
1268 
1269 /* readonly attribute unsigned long state; */
1270 NS_IMETHODIMP sbBaseDevice::GetPreviousState(PRUint32 *aState)
1271 {
1272  NS_ENSURE_ARG_POINTER(aState);
1273  NS_ENSURE_TRUE(mPreviousStateLock, NS_ERROR_NOT_INITIALIZED);
1274  nsAutoLock lock(mPreviousStateLock);
1275  *aState = mPreviousState;
1276  return NS_OK;
1277 }
1278 
1280 {
1281  // set state, checking if it changed
1282  NS_ENSURE_TRUE(mPreviousStateLock, NS_ERROR_NOT_INITIALIZED);
1283  nsAutoLock lock(mPreviousStateLock);
1284  if (mPreviousState != aState) {
1286  }
1287  return NS_OK;
1288 }
1289 
1290 /* attribute unsigned long state; */
1291 NS_IMETHODIMP sbBaseDevice::GetState(PRUint32 *aState)
1292 {
1293  NS_ENSURE_ARG_POINTER(aState);
1294  NS_ENSURE_TRUE(mStateLock, NS_ERROR_NOT_INITIALIZED);
1295  nsAutoLock lock(mStateLock);
1296  *aState = mState;
1297  return NS_OK;
1298 }
1299 
1300 /* attribute unsigned long state; */
1301 NS_IMETHODIMP sbBaseDevice::SetState(PRUint32 aState)
1302 {
1303 
1304  nsresult rv;
1305  PRBool stateChanged = PR_FALSE;
1306  PRUint32 prevState;
1307 
1308  // set state, checking if it changed
1309  {
1310  NS_ENSURE_TRUE(mStateLock, NS_ERROR_NOT_INITIALIZED);
1311  nsAutoLock lock(mStateLock);
1312 
1313  // Only allow the cancel state to transition to the idle state. This
1314  // prevents the request processing code from changing the state from cancel
1315  // to some other operation before it has checked for a canceled request.
1316  if ((mState == STATE_CANCEL) && (aState != STATE_IDLE))
1317  return NS_OK;
1318 
1319  prevState = mState;
1320  if (mState != aState) {
1321  mState = aState;
1322  stateChanged = PR_TRUE;
1323  }
1324  // Update the previous state - we set it outside of the if loop, so
1325  // even if the current state isn't changing, the previous state still
1326  // gets updated to the correct previous state.
1327  SetPreviousState(prevState);
1328  }
1329 
1330  // send state changed event. do it outside of lock in case event handler gets
1331  // called immediately and tries to read the state
1332  if (stateChanged) {
1333  nsCOMPtr<nsIWritableVariant> var =
1334  do_CreateInstance("@songbirdnest.com/Songbird/Variant;1", &rv);
1335  NS_ENSURE_SUCCESS(rv, rv);
1336  rv = var->SetAsUint32(aState);
1337  NS_ENSURE_SUCCESS(rv, rv);
1339  }
1340 
1341  return NS_OK;
1342 }
1343 
1345 {
1346  return mStatus->ChangeState(aState);
1347 }
1348 
1349 nsresult sbBaseDevice::CreateDeviceLibrary(const nsAString& aId,
1350  nsIURI* aLibraryLocation,
1351  sbIDeviceLibrary** _retval)
1352 {
1353  NS_ENSURE_ARG_POINTER(_retval);
1354 
1355  nsRefPtr<sbDeviceLibrary> devLib = new sbDeviceLibrary(this);
1356  NS_ENSURE_TRUE(devLib, NS_ERROR_OUT_OF_MEMORY);
1357 
1358  nsresult rv = InitializeDeviceLibrary(devLib, aId, aLibraryLocation);
1359  NS_ENSURE_SUCCESS(rv, rv);
1360 
1361  rv = CallQueryInterface(devLib.get(), _retval);
1362  NS_ENSURE_SUCCESS(rv, rv);
1363 
1364  return NS_OK;
1365 }
1366 
1368  (sbDeviceLibrary* aDevLib,
1369  const nsAString& aId,
1370  nsIURI* aLibraryLocation)
1371 {
1372  NS_ENSURE_ARG_POINTER(aDevLib);
1373 
1374  nsresult rv = aDevLib->Initialize(aId);
1375  NS_ENSURE_SUCCESS(rv, rv);
1376 
1377  // Hide the library on creation. The device is responsible
1378  // for showing it is done mounting.
1379  rv = aDevLib->SetProperty(NS_LITERAL_STRING(SB_PROPERTY_HIDDEN),
1380  NS_LITERAL_STRING("1"));
1381  NS_ENSURE_SUCCESS(rv, rv);
1382 
1383  rv = aDevLib->SetProperty(NS_LITERAL_STRING(SB_PROPERTY_ISSORTABLE),
1384  NS_LITERAL_STRING("1"));
1385  NS_ENSURE_SUCCESS(rv, rv);
1386 
1387  if (!mLibraryListener) {
1388  nsRefPtr<sbBaseDeviceLibraryListener> libListener =
1390  NS_ENSURE_TRUE(libListener, NS_ERROR_OUT_OF_MEMORY);
1391 
1392  rv = libListener->Init(this);
1393  NS_ENSURE_SUCCESS(rv, rv);
1394 
1395  libListener.swap(mLibraryListener);
1396  }
1397 
1398  rv = aDevLib->AddDeviceLibraryListener(mLibraryListener);
1399  NS_ENSURE_SUCCESS(rv, rv);
1400 
1401  // Initialize the library preferences.
1402  rv = InitializeDeviceLibraryPreferences(aDevLib);
1403  NS_ENSURE_SUCCESS(rv, rv);
1404 
1405  return NS_OK;
1406 }
1407 
1408 nsresult
1410 {
1411  // Validate arguments.
1412  NS_ENSURE_ARG_POINTER(aDevLib);
1413 
1414  // Function variables.
1415  nsresult rv;
1416 
1417  // Get the base library preference name.
1418  nsAutoString libraryPreferenceBase;
1419  rv = GetLibraryPreferenceBase(aDevLib, libraryPreferenceBase);
1420  NS_ENSURE_SUCCESS(rv, rv);
1421 
1422  // Check if the library organize enabled preference has been set.
1423  nsAutoString organizeEnabledPref = libraryPreferenceBase;
1424  organizeEnabledPref.Append(NS_LITERAL_STRING(PREF_ORGANIZE_ENABLED));
1425 
1430  // Set the default organize directory format.
1431  nsAutoString organizeDirFormatPref = libraryPreferenceBase;
1432  organizeDirFormatPref.Append(NS_LITERAL_STRING(PREF_ORGANIZE_DIR_FORMAT));
1433  rv = SetPreference(organizeDirFormatPref,
1435  NS_ENSURE_SUCCESS(rv, rv);
1436 
1437  // Enable library organization by default.
1438  rv = SetPreference(organizeEnabledPref,
1439  sbNewVariant(PR_TRUE, nsIDataType::VTYPE_BOOL));
1440  NS_ENSURE_SUCCESS(rv, rv);
1441 
1442  return NS_OK;
1443 }
1444 
1446 {
1447  // Initializes might have failed and we might get finalized
1448  if (mMediaListListeners.IsInitialized()) {
1449  // Finalize and clear the media list listeners.
1451  enumerateInfo.device = this;
1452  enumerateInfo.library = aDevLib;
1453  mMediaListListeners.Enumerate
1454  (sbBaseDevice::EnumerateFinalizeMediaListListeners,
1455  &enumerateInfo);
1456  }
1457  if (mLibraryListener) {
1458  // Finalize the device library.
1459  aDevLib->RemoveDeviceLibraryListener(mLibraryListener);
1460  aDevLib->Finalize();
1461  }
1462 }
1463 
1465 {
1466  // Validate arguments.
1467  NS_ENSURE_ARG_POINTER(aDevLib);
1468 
1469  // Function variables.
1470  nsresult rv;
1471 
1472  // Check library access.
1473  rv = CheckAccess(aDevLib);
1474  NS_ENSURE_SUCCESS(rv, rv);
1475 
1476  // Get the device content.
1477  nsCOMPtr<sbIDeviceContent> content;
1478  rv = GetContent(getter_AddRefs(content));
1479  NS_ENSURE_SUCCESS(rv, rv);
1480 
1481  // Update the device library volume name.
1482  nsRefPtr<sbBaseDeviceVolume> volume;
1483  rv = GetVolumeForItem(aDevLib, getter_AddRefs(volume));
1484  NS_ENSURE_SUCCESS(rv, rv);
1485  rv = UpdateVolumeName(volume);
1486  NS_ENSURE_SUCCESS(rv, rv);
1487 
1488  // Add the library to the device content.
1489  rv = content->AddLibrary(aDevLib);
1490  NS_ENSURE_SUCCESS(rv, rv);
1491 
1492  // Send a device library added event.
1494  sbNewVariant(aDevLib));
1495 
1496  // If no default library has been set, use library as default. Otherwise,
1497  // check default library preference.
1498  if (!mDefaultLibrary) {
1499  rv = UpdateDefaultLibrary(aDevLib);
1500  NS_ENSURE_SUCCESS(rv, rv);
1501  }
1502  else {
1503  // Get the default library GUID.
1504  nsAutoString defaultLibraryGUID;
1505  nsCOMPtr<nsIVariant> defaultLibraryGUIDPref;
1506  rv = GetPreference(NS_LITERAL_STRING("default_library_guid"),
1507  getter_AddRefs(defaultLibraryGUIDPref));
1508  NS_ENSURE_SUCCESS(rv, rv);
1509  rv = defaultLibraryGUIDPref->GetAsAString(defaultLibraryGUID);
1510  NS_ENSURE_SUCCESS(rv, rv);
1511 
1512  // Get the added library GUID.
1513  nsAutoString libraryGUID;
1514  rv = aDevLib->GetGuid(libraryGUID);
1515  NS_ENSURE_SUCCESS(rv, rv);
1516 
1517  // If added library GUID matches default library preference GUID, set it as
1518  // the default.
1519  if (libraryGUID.Equals(defaultLibraryGUID)) {
1520  rv = UpdateDefaultLibrary(aDevLib);
1521  NS_ENSURE_SUCCESS(rv, rv);
1522  }
1523  }
1524 
1525  // Apply the library preferences.
1526  rv = ApplyLibraryPreference(aDevLib, SBVoidString(), nsnull);
1527  NS_ENSURE_SUCCESS(rv, rv);
1528 
1529  return NS_OK;
1530 }
1531 
1533 {
1534  // Validate arguments.
1535  NS_ENSURE_ARG_POINTER(aDevLib);
1536 
1537  // Function variables.
1538  nsresult rv;
1539 
1540  // Get the device properties.
1541  nsCOMPtr<nsIPropertyBag2> deviceProperties;
1542  rv = GetPropertyBag(this, getter_AddRefs(deviceProperties));
1543  NS_ENSURE_SUCCESS(rv, rv);
1544 
1545  // Get the access compatibility.
1546  nsAutoString accessCompatibility;
1547  rv = deviceProperties->GetPropertyAsAString
1548  (NS_LITERAL_STRING(SB_DEVICE_PROPERTY_ACCESS_COMPATIBILITY),
1549  accessCompatibility);
1550  if (NS_FAILED(rv))
1551  accessCompatibility.Truncate();
1552 
1553  // Do nothing more if access is not read-only.
1554  if (!accessCompatibility.Equals(NS_LITERAL_STRING("ro")))
1555  return NS_OK;
1556 
1557  // Prompt user.
1558  // Get a prompter.
1559  nsCOMPtr<sbIPrompter>
1560  prompter = do_CreateInstance(SONGBIRD_PROMPTER_CONTRACTID, &rv);
1561  NS_ENSURE_SUCCESS(rv, rv);
1562 
1563  // Determine whether the access can be changed.
1564  PRBool canChangeAccess = PR_FALSE;
1565  rv = deviceProperties->GetPropertyAsBool
1567  &canChangeAccess);
1568  if (NS_FAILED(rv))
1569  canChangeAccess = PR_FALSE;
1570 
1571  // Get the device name.
1572  nsAutoString deviceName;
1573  rv = GetName(deviceName);
1574  NS_ENSURE_SUCCESS(rv, rv);
1575 
1576  // Get the prompt title.
1577  SBLocalizedString title("device.dialog.read_only_device.title");
1578 
1579  // Get the prompt message.
1580  nsAutoString msg;
1581  nsTArray<nsString> params;
1582  params.AppendElement(deviceName);
1583  if (canChangeAccess) {
1584  msg = SBLocalizedString("device.dialog.read_only_device.can_change.msg",
1585  params);
1586  } else {
1587  msg = SBLocalizedString("device.dialog.read_only_device.cannot_change.msg",
1588  params);
1589  }
1590 
1591  // Configure the buttons.
1592  PRUint32 buttonFlags = 0;
1593  PRInt32 changeAccessButtonIndex = -1;
1594  if (canChangeAccess) {
1595  changeAccessButtonIndex = 0;
1596  buttonFlags += nsIPromptService::BUTTON_POS_0 *
1597  nsIPromptService::BUTTON_TITLE_IS_STRING;
1598  buttonFlags += nsIPromptService::BUTTON_POS_1 *
1599  nsIPromptService::BUTTON_TITLE_IS_STRING;
1600  } else {
1601  buttonFlags += nsIPromptService::BUTTON_POS_0 *
1602  nsIPromptService::BUTTON_TITLE_OK;
1603  }
1604 
1605  // Get the button labels.
1606  SBLocalizedString buttonLabel0("device.dialog.read_only_device.change");
1607  SBLocalizedString buttonLabel1("device.dialog.read_only_device.dont_change");
1608 
1609  // Prompt user.
1610  PRInt32 buttonPressed;
1611  rv = prompter->ConfirmEx(nsnull, // Parent window.
1612  title.get(),
1613  msg.get(),
1614  buttonFlags,
1615  buttonLabel0.get(),
1616  buttonLabel1.get(),
1617  nsnull, // Button 2 label.
1618  nsnull, // Check message.
1619  nsnull, // Check result.
1620  &buttonPressed);
1621  NS_ENSURE_SUCCESS(rv, rv);
1622 
1623  // Change access if user selected to do so.
1624  if (canChangeAccess && (buttonPressed == changeAccessButtonIndex)) {
1625  // Set the access compatibility property to read-write.
1626  nsCOMPtr<nsIWritablePropertyBag>
1627  writeDeviceProperties = do_QueryInterface(deviceProperties, &rv);
1628  accessCompatibility = NS_LITERAL_STRING("rw");
1629  NS_ENSURE_SUCCESS(rv, rv);
1630  writeDeviceProperties->SetProperty
1631  (NS_LITERAL_STRING(SB_DEVICE_PROPERTY_ACCESS_COMPATIBILITY),
1632  sbNewVariant(accessCompatibility));
1633  }
1634 
1635  return NS_OK;
1636 }
1637 
1639 {
1640  // Validate arguments.
1641  NS_ENSURE_ARG_POINTER(aDevLib);
1642 
1643  // Function variables.
1644  nsresult rv;
1645 
1646  // Get the device content.
1647  nsCOMPtr<sbIDeviceContent> content;
1648  rv = GetContent(getter_AddRefs(content));
1649  NS_ENSURE_SUCCESS(rv, rv);
1650 
1651  // If the default library is being removed, change the default to the first
1652  // library.
1653  if (aDevLib == mDefaultLibrary) {
1654  // Get the list of device libraries.
1655  PRUint32 libraryCount;
1656  nsCOMPtr<nsIArray> libraries;
1657  rv = content->GetLibraries(getter_AddRefs(libraries));
1658  NS_ENSURE_SUCCESS(rv, rv);
1659  rv = libraries->GetLength(&libraryCount);
1660  NS_ENSURE_SUCCESS(rv, rv);
1661 
1662  // Set the default library to the first library or null if no libraries.
1663  nsCOMPtr<sbIDeviceLibrary> defaultLibrary;
1664  for (PRUint32 i = 0; i < libraryCount; ++i) {
1665  nsCOMPtr<sbIDeviceLibrary> library = do_QueryElementAt(libraries, i, &rv);
1666  NS_ENSURE_SUCCESS(rv, rv);
1667  if (library != aDevLib) {
1668  defaultLibrary = library;
1669  break;
1670  }
1671  }
1672  rv = UpdateDefaultLibrary(defaultLibrary);
1673  NS_ENSURE_SUCCESS(rv, rv);
1674  }
1675 
1676  // Send a device library removed event.
1677  nsAutoString guid;
1678  rv = aDevLib->GetGuid(guid);
1679  NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to get device library.");
1681  sbNewVariant(guid));
1682 
1683  // Remove the device library from the device content.
1684  rv = content->RemoveLibrary(aDevLib);
1685  NS_ENSURE_SUCCESS(rv, rv);
1686 
1687  return NS_OK;
1688 }
1689 
1690 nsresult
1692  const nsAString& aPropertyID,
1693  const nsAString& aPropertyValue)
1694 {
1695  NS_ENSURE_ARG_POINTER(aLibrary);
1696  nsresult rv;
1697 
1698  // Get the current property value.
1699  nsAutoString currentPropertyValue;
1700  rv = aLibrary->GetProperty(aPropertyID, currentPropertyValue);
1701  NS_ENSURE_SUCCESS(rv, rv);
1702 
1703  // Set the property value if it's changing.
1704  if (!aPropertyValue.Equals(currentPropertyValue)) {
1705  rv = aLibrary->SetProperty(aPropertyID, aPropertyValue);
1706  NS_ENSURE_SUCCESS(rv, rv);
1707  }
1708 
1709  return NS_OK;
1710 }
1711 
1712 nsresult
1714 {
1715  nsresult rv;
1716 
1717  // Do nothing if default library is not changing.
1718  if (aDevLib == mDefaultLibrary)
1719  return NS_OK;
1720 
1721  // Update the default library and volume.
1722  nsRefPtr<sbBaseDeviceVolume> volume;
1723  if (aDevLib) {
1724  rv = GetVolumeForItem(aDevLib, getter_AddRefs(volume));
1725  NS_ENSURE_SUCCESS(rv, rv);
1726  }
1727  mDefaultLibrary = aDevLib;
1728  {
1729  nsAutoLock autoVolumeLock(mVolumeLock);
1730  mDefaultVolume = volume;
1731  }
1732 
1733  // Handle the default library change.
1735 
1736  return NS_OK;
1737 }
1738 
1739 nsresult
1741 {
1742  // Send a default library changed event.
1745 
1746  return NS_OK;
1747 }
1748 
1750 {
1751  NS_ENSURE_ARG_POINTER(aList);
1752 
1753  nsresult rv;
1754 
1755  #if DEBUG
1756  // check to make sure we're not listening to a library
1757  nsCOMPtr<sbILibrary> library = do_QueryInterface(aList);
1758  NS_ASSERTION(!library,
1759  "Should not call sbBaseDevice::ListenToList on a library!");
1760  #endif
1761 
1762  // the extra QI to make sure we're at the canonical pointer
1763  // and not some derived interface
1764  nsCOMPtr<sbIMediaList> list = do_QueryInterface(aList, &rv);
1765  NS_ENSURE_SUCCESS(rv, rv);
1766 
1767  NS_ENSURE_TRUE(mMediaListListeners.IsInitialized(), NS_ERROR_UNEXPECTED);
1768 
1769  // check for an existing listener
1770  if (mMediaListListeners.Get(list, nsnull)) {
1771  // we are already listening to the media list, don't re-add
1772  return NS_OK;
1773  }
1774 
1775  nsRefPtr<sbBaseDeviceMediaListListener> listener =
1777  NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
1778 
1779  rv = listener->Init(this);
1780  NS_ENSURE_SUCCESS(rv, rv);
1781 
1782  rv = list->AddListener(listener,
1783  PR_FALSE, /* weak */
1784  0, /* all */
1785  nsnull /* filter */);
1786  NS_ENSURE_SUCCESS(rv, rv);
1787 
1788  // If we're currently ignoring listeners then we need to ignore this one too
1789  // else we'll get out of balance
1790  if (mIgnoreMediaListCount > 0)
1791  listener->SetIgnoreListener(PR_TRUE);
1792  mMediaListListeners.Put(list, listener);
1793 
1794  return NS_OK;
1795 }
1796 
1797 PLDHashOperator sbBaseDevice::EnumerateFinalizeMediaListListeners
1798  (nsISupports* aKey,
1799  nsRefPtr<sbBaseDeviceMediaListListener>& aData,
1800  void* aClosure)
1801 {
1802  nsresult rv;
1803 
1804  // Get the device and library for which to finalize media list listeners.
1805  EnumerateFinalizeMediaListListenersInfo*
1806  enumerateInfo =
1807  static_cast<EnumerateFinalizeMediaListListenersInfo*>(aClosure);
1808  nsCOMPtr<sbILibrary> library = enumerateInfo->library;
1809 
1810  // Get the listener media list.
1811  nsCOMPtr<sbIMediaList> mediaList = do_QueryInterface(aKey, &rv);
1812  NS_ENSURE_SUCCESS(rv, PL_DHASH_STOP);
1813 
1814  // Do nothing if media list is contained in another library.
1815  nsCOMPtr<sbILibrary> mediaListLibrary;
1816  PRBool equals;
1817  rv = mediaList->GetLibrary(getter_AddRefs(mediaListLibrary));
1818  NS_ENSURE_SUCCESS(rv, PL_DHASH_STOP);
1819  rv = mediaListLibrary->Equals(library, &equals);
1820  NS_ENSURE_SUCCESS(rv, PL_DHASH_STOP);
1821  if (!equals)
1822  return PL_DHASH_NEXT;
1823 
1824  // Remove the media list listener.
1825  mediaList->RemoveListener(aData);
1826 
1827  return PL_DHASH_REMOVE;
1828 }
1829 
1830 PLDHashOperator sbBaseDevice::EnumerateIgnoreMediaListListeners(nsISupports* aKey,
1831  nsRefPtr<sbBaseDeviceMediaListListener> aData,
1832  void* aClosure)
1833 {
1834  nsresult rv;
1835  PRBool *ignore = static_cast<PRBool *>(aClosure);
1836 
1837  rv = aData->SetIgnoreListener(*ignore);
1838  NS_ENSURE_SUCCESS(rv, PL_DHASH_STOP);
1839 
1840  return PL_DHASH_NEXT;
1841 }
1842 
1843 nsresult
1845 {
1846  NS_ENSURE_TRUE(mMediaListListeners.IsInitialized(), NS_ERROR_UNEXPECTED);
1847 
1848  if (aIgnoreListener)
1849  PR_AtomicIncrement(&mIgnoreMediaListCount);
1850  else
1851  PR_AtomicDecrement(&mIgnoreMediaListCount);
1852 
1853  mMediaListListeners.EnumerateRead(sbBaseDevice::EnumerateIgnoreMediaListListeners,
1854  &aIgnoreListener);
1855  return NS_OK;
1856 }
1857 
1858 nsresult
1860 {
1861  NS_ENSURE_STATE(mLibraryListener);
1862  return mLibraryListener->SetIgnoreListener(aIgnoreListener);
1863 }
1864 
1865 nsresult
1867 {
1868  NS_ENSURE_ARG_POINTER(aLibrary);
1869 
1870  nsRefPtr<ShowMediaListEnumerator> enumerator = new ShowMediaListEnumerator(aHidden);
1871  NS_ENSURE_TRUE(enumerator, NS_ERROR_OUT_OF_MEMORY);
1872 
1873  nsresult rv = aLibrary->EnumerateItemsByProperty(NS_LITERAL_STRING(SB_PROPERTY_ISLIST),
1874  NS_LITERAL_STRING("1"),
1875  enumerator,
1877  return rv;
1878 }
1879 
1881  NS_ENSURE_STATE(mLibraryListener);
1882  return mLibraryListener->IgnoreMediaItem(aItem);
1883 }
1884 
1886  NS_ENSURE_STATE(mLibraryListener);
1887  return mLibraryListener->UnignoreMediaItem(aItem);
1888 }
1889 
1890 nsresult
1892 {
1893  NS_ENSURE_ARG_POINTER(aLibrary);
1894  NS_ENSURE_ARG_POINTER(aItem);
1895 
1896  NS_ENSURE_STATE(mLibraryListener);
1897 
1898  SetIgnoreMediaListListeners(PR_TRUE);
1899  mLibraryListener->SetIgnoreListener(PR_TRUE);
1900 
1901  nsresult rv = aLibrary->Remove(aItem);
1902 
1903  SetIgnoreMediaListListeners(PR_FALSE);
1904  mLibraryListener->SetIgnoreListener(PR_FALSE);
1905 
1906  return rv;
1907 }
1908 
1909 nsresult
1911  PRUint32* aContentType)
1912 {
1913  // Validate arguments.
1914  NS_ENSURE_ARG_POINTER(aMediaItem);
1915  NS_ENSURE_ARG_POINTER(aContentType);
1916 
1917  // Function variables.
1918  nsresult rv;
1919 
1920  // Get the format type.
1922  PRUint32 bitRate;
1923  PRUint32 sampleRate;
1924  rv = sbDeviceUtils::GetFormatTypeForItem(aMediaItem,
1925  formatType,
1926  bitRate,
1927  sampleRate);
1928  if (rv == NS_ERROR_NOT_AVAILABLE) {
1929  // Expected error no need to log it to the console just pass it on
1930  return NS_ERROR_NOT_AVAILABLE;
1931  }
1932  else {
1933  NS_ENSURE_SUCCESS(rv, rv);
1934  }
1935 
1936  // Return results.
1937  *aContentType = formatType.ContentType;
1938 
1939  return NS_OK;
1940 }
1941 
1942 nsresult
1944  nsIURI* aURI)
1945 {
1946  // Validate arguments.
1947  NS_ENSURE_ARG_POINTER(aRequest);
1948  NS_ENSURE_ARG_POINTER(aURI);
1949 
1950  // Function variables.
1951  nsresult rv;
1952 
1953  // Ignore changes to the request item while it's being updated.
1954  sbDeviceListenerIgnore ignore(this, aRequest->item);
1955 
1956  // If the content source has not already been updated, update the content
1957  // origin.
1958  if (!aRequest->contentSrcSet) {
1959  // Copy the current content source URL to the origin URL.
1960  nsAutoString originURL;
1961  rv = aRequest->item->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_CONTENTURL),
1962  originURL);
1963  if (NS_SUCCEEDED(rv)) {
1964  rv = aRequest->item->SetProperty(NS_LITERAL_STRING(SB_PROPERTY_ORIGINURL),
1965  originURL);
1966  NS_ENSURE_SUCCESS(rv, rv);
1967  }
1968  }
1969 
1970  // Update the content source.
1971  rv = aRequest->item->SetContentSrc(aURI);
1972  NS_ENSURE_SUCCESS(rv, rv);
1973 
1974  // The content source has now been set.
1975  aRequest->contentSrcSet = PR_TRUE;
1976 
1977  return NS_OK;
1978 }
1979 
1980 nsresult
1982  nsIPropertyBag2 *aRequestParameters,
1983  TransferRequest **aTransferRequest)
1984 {
1985  NS_ENSURE_ARG_POINTER(aRequestParameters);
1986  NS_ENSURE_ARG_POINTER(aTransferRequest);
1987 
1988 
1989  nsresult rv;
1990 
1991  nsCOMPtr<sbIMediaItem> item;
1992  nsCOMPtr<sbIMediaList> list;
1993  nsCOMPtr<nsISupports> data;
1994 
1995  PRUint32 index = PR_UINT32_MAX;
1996  PRUint32 otherIndex = PR_UINT32_MAX;
1997 
1998  rv = aRequestParameters->GetPropertyAsInterface(NS_LITERAL_STRING("item"),
1999  NS_GET_IID(sbIMediaItem),
2000  getter_AddRefs(item));
2001  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "No item present in request parameters.");
2002 
2003  rv = aRequestParameters->GetPropertyAsInterface(NS_LITERAL_STRING("list"),
2004  NS_GET_IID(sbIMediaList),
2005  getter_AddRefs(list));
2006  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "No list present in request parameters.");
2007 
2008  rv = aRequestParameters->GetPropertyAsInterface(NS_LITERAL_STRING("data"),
2009  NS_GET_IID(nsISupports),
2010  getter_AddRefs(data));
2011  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "No data present in request parameters.");
2012 
2013  NS_WARN_IF_FALSE(item || list || data,
2014  "No data of any kind given in request."
2015  "This request will most likely fail.");
2016 
2017  rv = aRequestParameters->GetPropertyAsUint32(NS_LITERAL_STRING("index"),
2018  &index);
2019  if(NS_FAILED(rv)) {
2020  index = PR_UINT32_MAX;
2021  }
2022 
2023  rv = aRequestParameters->GetPropertyAsUint32(NS_LITERAL_STRING("otherIndex"),
2024  &otherIndex);
2025  if(NS_FAILED(rv)) {
2026  otherIndex = PR_UINT32_MAX;
2027  }
2028 
2029  nsRefPtr<TransferRequest> req = TransferRequest::New(aRequestType,
2030  item,
2031  list,
2032  index,
2033  otherIndex,
2034  data);
2035  NS_ENSURE_TRUE(req, NS_ERROR_OUT_OF_MEMORY);
2036 
2037  req.forget(aTransferRequest);
2038 
2039  return NS_OK;
2040 }
2041 
2043  (PRUint32 aType,
2044  nsIVariant *aData,
2045  PRBool aAsync /*= PR_TRUE*/,
2046  sbIDeviceEventTarget* aTarget /*= nsnull*/)
2047 {
2048  nsresult rv;
2049 
2050  nsCOMPtr<sbIDeviceManager2> manager =
2051  do_GetService("@songbirdnest.com/Songbird/DeviceManager;2", &rv);
2052  NS_ENSURE_SUCCESS(rv, rv);
2053 
2054  nsCOMPtr<sbIDeviceStatus> status;
2055  rv = GetCurrentStatus(getter_AddRefs(status));
2056  NS_ENSURE_SUCCESS(rv, rv);
2057 
2058  PRUint32 subState = sbIDevice::STATE_IDLE;
2059  if (status) {
2060  rv = status->GetCurrentSubState(&subState);
2061  NS_ENSURE_SUCCESS(rv, rv);
2062  }
2063 
2064  nsCOMPtr<sbIDeviceEvent> deviceEvent;
2065  rv = manager->CreateEvent(aType,
2066  aData,
2067  static_cast<sbIDevice*>(this),
2068  mState,
2069  subState,
2070  getter_AddRefs(deviceEvent));
2071  NS_ENSURE_SUCCESS(rv, rv);
2072 
2073  PRBool dispatched;
2074  if (aTarget)
2075  return aTarget->DispatchEvent(deviceEvent, aAsync, &dispatched);
2076  return DispatchEvent(deviceEvent, aAsync, &dispatched);
2077 }
2078 
2080  (PRUint32 aType,
2081  nsIVariant *aData,
2082  PRBool aAsync /*= PR_TRUE*/)
2083 {
2084  nsresult rv;
2085 
2086  // Use the device manager as the event target.
2087  nsCOMPtr<sbIDeviceEventTarget> eventTarget =
2088  do_GetService("@songbirdnest.com/Songbird/DeviceManager;2", &rv);
2089  NS_ENSURE_SUCCESS(rv, rv);
2090 
2091  return CreateAndDispatchEvent(aType, aData, aAsync, eventTarget);
2092 }
2093 
2094 nsresult
2096  nsACString & aFilename) {
2097  nsresult rv;
2098  nsCString filename;
2099  nsCString extension;
2100 
2101  nsCOMPtr<nsIURI> sourceContentURI;
2102  rv = aItem->GetContentSrc(getter_AddRefs(sourceContentURI));
2103  NS_ENSURE_SUCCESS(rv, rv);
2104 
2105  nsCOMPtr<nsIURL> sourceContentURL = do_QueryInterface(sourceContentURI, &rv);
2106  if (NS_SUCCEEDED(rv)) {
2107  rv = sourceContentURL->GetFileBaseName(filename);
2108  NS_ENSURE_SUCCESS(rv, rv);
2109  // If the filename already contains the extension then don't ask the URI
2110  // for it
2111  rv = sourceContentURL->GetFileExtension(extension);
2112  NS_ENSURE_SUCCESS(rv, rv);
2113  } else {
2114  // Last ditch effort to figure out the filename/extension
2115  nsCString spec;
2116  rv = sourceContentURI->GetSpec(spec);
2117  NS_ENSURE_SUCCESS(rv, rv);
2118 
2119  PRInt32 lastSlash = spec.RFind("/");
2120  if (lastSlash == -1) {
2121  lastSlash = 0;
2122  }
2123  PRInt32 lastPeriod = spec.RFind(".");
2124  if (lastPeriod == -1 || lastPeriod < lastSlash) {
2125  lastPeriod = spec.Length();
2126  }
2127  filename = Substring(spec, lastSlash + 1, lastPeriod - lastSlash - 1);
2128  extension = Substring(spec, lastPeriod + 1, spec.Length() - lastPeriod - 1);
2129  }
2130  aFilename = filename;
2131  if (!extension.IsEmpty()) {
2132  aFilename += NS_LITERAL_CSTRING(".");
2133  aFilename += extension;
2134  }
2135  return NS_OK;
2136 }
2137 
2138 nsresult
2140  nsIFile **aUniqueFile,
2141  nsIURI **aUniqueURI)
2142 {
2143  NS_ENSURE_ARG_POINTER(aURI);
2144 
2145  nsresult rv;
2146 
2147  // Get a clone of the URI.
2148  nsCOMPtr<nsIURI> uniqueURI;
2149  rv = aURI->Clone(getter_AddRefs(uniqueURI));
2150  NS_ENSURE_SUCCESS(rv, rv);
2151 
2152  // Get the file URL.
2153  nsCOMPtr<nsIFileURL> uniqueFileURL = do_QueryInterface(uniqueURI, &rv);
2154  NS_ENSURE_SUCCESS(rv, rv);
2155 
2156  // Get the file object, invalidating the cache beforehand.
2157  nsCOMPtr<nsIFile> uniqueFile;
2158  rv = sbInvalidateFileURLCache(uniqueFileURL);
2159  NS_ENSURE_SUCCESS(rv, rv);
2160  rv = uniqueFileURL->GetFile(getter_AddRefs(uniqueFile));
2161  NS_ENSURE_SUCCESS(rv, rv);
2162 
2163  // Check if file already exists.
2164  PRBool alreadyExists;
2165  rv = uniqueFile->Exists(&alreadyExists);
2166  NS_ENSURE_SUCCESS(rv, rv);
2167 
2168  // Try different file names until a unique one is found. Limit the number of
2169  // unique names to try to the same limit as nsIFile.createUnique.
2170  for (PRUint32 uniqueIndex = 1;
2171  alreadyExists && (uniqueIndex < 10000);
2172  ++uniqueIndex) {
2173  // Get a clone of the URI.
2174  rv = aURI->Clone(getter_AddRefs(uniqueURI));
2175  NS_ENSURE_SUCCESS(rv, rv);
2176 
2177  // Get the file URL.
2178  uniqueFileURL = do_QueryInterface(uniqueURI, &rv);
2179  NS_ENSURE_SUCCESS(rv, rv);
2180 
2181  // Get the file base name.
2182  nsCAutoString fileBaseName;
2183  rv = uniqueFileURL->GetFileBaseName(fileBaseName);
2184  NS_ENSURE_SUCCESS(rv, rv);
2185 
2186  // Add a unique index to the file base name.
2187  fileBaseName.Append(" (");
2188  fileBaseName.AppendInt(uniqueIndex);
2189  fileBaseName.Append(")");
2190  rv = uniqueFileURL->SetFileBaseName(fileBaseName);
2191  NS_ENSURE_SUCCESS(rv, rv);
2192 
2193  // Get the file object, invalidating the cache beforehand.
2194  rv = sbInvalidateFileURLCache(uniqueFileURL);
2195  NS_ENSURE_SUCCESS(rv, rv);
2196  rv = uniqueFileURL->GetFile(getter_AddRefs(uniqueFile));
2197  NS_ENSURE_SUCCESS(rv, rv);
2198 
2199  // Check if file already exists.
2200  rv = uniqueFile->Exists(&alreadyExists);
2201  NS_ENSURE_SUCCESS(rv, rv);
2202 
2203  // Create file if it doesn't already exist.
2204  if (!alreadyExists) {
2205  rv = uniqueFile->Create(nsIFile::NORMAL_FILE_TYPE,
2207  if (rv == NS_ERROR_FILE_ALREADY_EXISTS) {
2208  alreadyExists = PR_TRUE;
2209  rv = NS_OK;
2210  }
2211  NS_ENSURE_SUCCESS(rv, rv);
2212  }
2213  }
2214 
2215  // Return results.
2216  if (aUniqueFile)
2217  uniqueFile.forget(aUniqueFile);
2218  if (aUniqueURI)
2219  uniqueURI.forget(aUniqueURI);
2220 
2221  return NS_OK;
2222 }
2223 
2224 nsresult
2226  nsIURI **_retval)
2227 {
2228  NS_ENSURE_ARG_POINTER(aItem);
2229  NS_ENSURE_ARG_POINTER(_retval);
2230 
2231  nsresult rv;
2232 
2233  nsCOMPtr<sbIMediaFileManager> fileMan =
2234  do_CreateInstance(SB_MEDIAFILEMANAGER_CONTRACTID, &rv);
2235  NS_ENSURE_SUCCESS(rv, rv);
2236 
2237  // Init with nsnull to get the default file management behavior for
2238  // items in the main library:
2239  rv = fileMan->Init(nsnull);
2240  NS_ENSURE_SUCCESS(rv, rv);
2241 
2242  // Get the path the item would be organized
2243  nsCOMPtr<nsIFile> mediaPath;
2244  rv = fileMan->GetManagedPath(aItem,
2248  getter_AddRefs(mediaPath));
2249  NS_ENSURE_SUCCESS(rv, rv);
2250 
2251  nsCOMPtr<nsIFile> parentDir;
2252  rv = mediaPath->GetParent(getter_AddRefs(parentDir));
2253  NS_ENSURE_SUCCESS(rv, rv);
2254 
2255  PRBool fileExists = PR_FALSE;
2256  rv = parentDir->Exists(&fileExists);
2257  NS_ENSURE_SUCCESS(rv, rv);
2258  if (!fileExists) {
2259  rv = parentDir->Create(nsIFile::DIRECTORY_TYPE, 0755);
2260  NS_ENSURE_SUCCESS(rv, rv);
2261  }
2262 
2263  nsCOMPtr<nsIURI> mediaURI;
2264  rv = sbNewFileURI(mediaPath, getter_AddRefs(mediaURI));
2265  NS_ENSURE_SUCCESS(rv, rv);
2266 
2267  // Make sure the uri we'll return is unique, and if not make it so by adding
2268  // the appropriate ' (X)' suffix.
2269  rv = CreateUniqueMediaFile(mediaURI,
2270  nsnull, // don't return an nsIFile
2271  _retval);
2272  NS_ENSURE_SUCCESS(rv, rv);
2273 
2274  return NS_OK;
2275 }
2276 
2277 nsresult
2279 {
2280  // Start the thread for processing requests
2281  nsresult rv = mRequestThreadQueue->Start(this);
2282  NS_ENSURE_SUCCESS(rv, rv);
2283 
2284  return NS_OK;
2285 }
2286 
2287 nsresult
2288 sbBaseDevice::ReqProcessingStop(nsIRunnable * aShutdownAction)
2289 {
2290  nsresult rv = mRequestThreadQueue->Stop();
2291  NS_ENSURE_SUCCESS(rv, rv);
2292 
2293  return NS_OK;
2294 }
2295 
2296 bool
2298 {
2299  return mRequestThreadQueue->CheckAndResetRequestAbort();
2300 }
2301 
2302 nsresult
2304 {
2305  mRequestThreadQueue->ClearRequests();
2306  return NS_OK;
2307 }
2308 
2309 NS_IMETHODIMP
2311 {
2312  nsresult rv;
2313 
2314  // User cancelled the sync, check if the request thread was running and, if
2315  // so, set the state to CANCEL. If we weren't running, just go to IDLE.
2316  if (mRequestThreadQueue->IsHandlingRequests()) {
2317  rv = SetState(STATE_CANCEL);
2318  NS_ENSURE_SUCCESS(rv, rv);
2319 
2320  nsCOMPtr<sbIDeviceStatus> status;
2321  rv = GetCurrentStatus(getter_AddRefs(status));
2322  NS_ENSURE_SUCCESS(rv, rv);
2323 
2324  rv = status->SetCurrentState(STATE_CANCEL);
2325  NS_ENSURE_SUCCESS(rv, rv);
2326  }
2327  else {
2328  rv = SetState(STATE_IDLE);
2329  NS_ENSURE_SUCCESS(rv, rv);
2330  }
2331 
2332  // We run CancelRequests even if the RTQ is not currently handling requests
2333  // to ensure that any latent requests in the queue are cleared.
2334  rv = mRequestThreadQueue->CancelRequests();
2335  NS_ENSURE_SUCCESS(rv, rv);
2336 
2337  return NS_OK;
2338 }
2339 
2340 PRBool
2342 {
2343  bool aborted = mRequestThreadQueue->CheckAndResetRequestAbort();
2344  if (aborted) {
2345  return PR_TRUE;
2346  }
2347  PRUint32 deviceState;
2348  return NS_FAILED(GetState(&deviceState)) ||
2349  deviceState == sbIDevice::STATE_DISCONNECTED ? PR_TRUE : PR_FALSE;
2350 }
2351 
2352 template <class T>
2353 inline
2355 {
2356  while (start != target && start != end) {
2357  ++start;
2358  }
2359  return start;
2360 }
2361 
2363  sbIDeviceLibrary* aDevLibrary)
2364 {
2365  LOG((" sbBaseDevice::EnsureSpaceForWrite++\n"));
2366 
2367  nsresult rv;
2368 
2369  sbDeviceEnsureSpaceForWrite esfw(this, aDevLibrary, aChangeset);
2370 
2371  rv = esfw.EnsureSpace();
2372  NS_ENSURE_SUCCESS(rv, rv);
2373 
2374  return NS_OK;
2375 }
2376 
2377 /* a helper class to proxy sbBaseDevice::Init onto the main thread
2378  * needed because sbBaseDevice multiply-inherits from nsISupports, so
2379  * AddRef gets confused
2380  */
2381 class sbBaseDeviceInitHelper : public nsRunnable
2382 {
2383 public:
2385  : mDevice(aDevice) {
2386  NS_ADDREF(NS_ISUPPORTS_CAST(sbIDevice*, mDevice));
2387  }
2388 
2389  NS_IMETHOD Run() {
2390  mDevice->Init();
2391  return NS_OK;
2392  }
2393 
2394 private:
2396  NS_ISUPPORTS_CAST(sbIDevice*, mDevice)->Release();
2397  }
2398  sbBaseDevice* mDevice;
2399 };
2400 
2402 {
2403  // make sure we were able to make mStatus during construction
2404  NS_ENSURE_TRUE(mStatus, NS_ERROR_OUT_OF_MEMORY);
2405  nsresult rv;
2406 
2407  NS_ASSERTION(NS_IsMainThread(),
2408  "base device init not on main thread, implement proxying");
2409  if (!NS_IsMainThread()) {
2410  // we need to get the weak reference on the main thread because it is not
2411  // threadsafe, but we only ever use it from the main thread
2412  nsCOMPtr<nsIRunnable> event = new sbBaseDeviceInitHelper(this);
2413  return NS_DispatchToMainThread(event, NS_DISPATCH_SYNC);
2414  }
2415 
2417 
2418  // get a weak ref of the device manager
2419  nsCOMPtr<nsISupportsWeakReference> manager =
2420  do_GetService("@songbirdnest.com/Songbird/DeviceManager;2", &rv);
2421  NS_ENSURE_SUCCESS(rv, rv);
2422 
2423  rv = manager->GetWeakReference(getter_AddRefs(mParentEventTarget));
2424  if (NS_FAILED(rv)) {
2425  mParentEventTarget = nsnull;
2426  return rv;
2427  }
2428 
2429  rv = GetMainLibrary(getter_AddRefs(mMainLibrary));
2430  NS_ENSURE_SUCCESS(rv, rv);
2431 
2432  // Initialize the media folder URL table.
2433  NS_ENSURE_TRUE(mMediaFolderURLTable.Init(), NS_ERROR_OUT_OF_MEMORY);
2434 
2435  // Initialize the device properties.
2436  rv = InitializeProperties();
2437  NS_ENSURE_SUCCESS(rv, rv);
2438 
2439  // Perform derived class intialization
2440  rv = InitDevice();
2441  NS_ENSURE_SUCCESS(rv, rv);
2442 
2443  rv = mStatus->Initialize();
2444  NS_ENSURE_SUCCESS(rv, rv);
2445 
2446  // Perform initial properties update.
2447  UpdateProperties();
2448 
2449  // get transcoding stuff
2451  NS_ENSURE_TRUE(mDeviceTranscoding, NS_ERROR_OUT_OF_MEMORY);
2452 
2453  // get image stuff
2454  mDeviceImages = new sbDeviceImages(this);
2455  NS_ENSURE_TRUE(mDeviceImages, NS_ERROR_OUT_OF_MEMORY);
2456 
2457  return NS_OK;
2458 }
2459 
2460 nsresult
2462  PRInt64* aFreeMusicSpace)
2463 {
2464  // Validate arguments.
2465  NS_ENSURE_ARG_POINTER(aFreeMusicSpace);
2466 
2467  // Function variables.
2468  nsresult rv;
2469 
2470  // Get the available music space.
2471  PRInt64 musicAvailableSpace;
2472  rv = GetMusicAvailableSpace(aLibrary, &musicAvailableSpace);
2473  NS_ENSURE_SUCCESS(rv, rv);
2474 
2475  // Get the device properties.
2476  nsCOMPtr<nsIPropertyBag2> deviceProperties;
2477  rv = GetPropertyBag(this, getter_AddRefs(deviceProperties));
2478  NS_ENSURE_SUCCESS(rv, rv);
2479 
2480  // Get the music used space.
2481  PRInt64 musicUsedSpace;
2482  nsAutoString musicUsedSpaceStr;
2483  rv = aLibrary->GetProperty
2484  (NS_LITERAL_STRING(SB_DEVICE_PROPERTY_MUSIC_USED_SPACE),
2485  musicUsedSpaceStr);
2486  NS_ENSURE_SUCCESS(rv, rv);
2487  musicUsedSpace = nsString_ToInt64(musicUsedSpaceStr, &rv);
2488  NS_ENSURE_SUCCESS(rv, rv);
2489 
2490  // Return result.
2491  if (musicAvailableSpace >= musicUsedSpace)
2492  *aFreeMusicSpace = musicAvailableSpace - musicUsedSpace;
2493  else
2494  *aFreeMusicSpace = 0;
2495 
2496  return NS_OK;
2497 }
2498 
2499 nsresult
2501  PRInt64* aMusicAvailableSpace)
2502 {
2503  // Validate arguments.
2504  NS_ENSURE_ARG_POINTER(aMusicAvailableSpace);
2505 
2506  // Function variables.
2507  nsresult rv;
2508 
2509  // Get the device properties.
2510  nsCOMPtr<nsIPropertyBag2> deviceProperties;
2511  rv = GetPropertyBag(this, getter_AddRefs(deviceProperties));
2512  NS_ENSURE_SUCCESS(rv, rv);
2513 
2514  // Get the total capacity.
2515  PRInt64 capacity;
2516  nsAutoString capacityStr;
2517  rv = aLibrary->GetProperty(NS_LITERAL_STRING(SB_DEVICE_PROPERTY_CAPACITY),
2518  capacityStr);
2519  NS_ENSURE_SUCCESS(rv, rv);
2520  capacity = nsString_ToInt64(capacityStr, &rv);
2521  NS_ENSURE_SUCCESS(rv, rv);
2522 
2523  // Compute the amount of available music space.
2524  PRInt64 musicAvailableSpace;
2525  if (mMusicLimitPercent < 100) {
2526  musicAvailableSpace = (capacity * mMusicLimitPercent) /
2527  static_cast<PRInt64>(100);
2528  } else {
2529  musicAvailableSpace = capacity;
2530  }
2531 
2532  // Return results.
2533  *aMusicAvailableSpace = musicAvailableSpace;
2534 
2535  return NS_OK;
2536 }
2537 
2538 nsresult
2540  PRBool aReportErrors,
2541  PRBool* _retval)
2542 {
2543  NS_ENSURE_ARG_POINTER(aMediaItem);
2544  NS_ENSURE_ARG_POINTER(_retval);
2545 
2546  nsresult rv;
2547 
2548  // DRM is not supported by default. Subclasses can override this.
2549  if (aReportErrors) {
2551  (aMediaItem, SBLocalizedString("transcode.file.drmprotected"));
2552  NS_ENSURE_SUCCESS(rv, rv);
2553  }
2554  *_retval = PR_FALSE;
2555 
2556  return NS_OK;
2557 }
2558 
2559 //------------------------------------------------------------------------------
2560 //
2561 // Device volume services.
2562 //
2563 //------------------------------------------------------------------------------
2564 
2565 nsresult
2567 {
2568  TRACE(("%s[%p]", __FUNCTION__, this));
2569  // Validate arguments.
2570  NS_ENSURE_ARG_POINTER(aVolume);
2571 
2572  // Function variables.
2573  nsresult rv;
2574 
2575  // Add the volume to the volume lists and tables.
2576  nsAutoString volumeGUID;
2577  rv = aVolume->GetGUID(volumeGUID);
2578  NS_ENSURE_SUCCESS(rv, rv);
2579  {
2580  nsAutoLock autoVolumeLock(mVolumeLock);
2581  NS_ENSURE_TRUE(mVolumeList.AppendElement(aVolume), NS_ERROR_OUT_OF_MEMORY);
2582  NS_ENSURE_TRUE(mVolumeGUIDTable.Put(volumeGUID, aVolume),
2583  NS_ERROR_OUT_OF_MEMORY);
2584  }
2585 
2586  // If the device is currently marked as "hidden" and a new volume was added,
2587  // reset the hidden property.
2588  nsCOMPtr<sbIDeviceProperties> deviceProperties;
2589  rv = GetProperties(getter_AddRefs(deviceProperties));
2590  NS_ENSURE_SUCCESS(rv, rv);
2591 
2592  PRBool isHidden = PR_FALSE;
2593  rv = deviceProperties->GetHidden(&isHidden);
2594  if (NS_SUCCEEDED(rv) && isHidden) {
2595  rv = deviceProperties->SetHidden(PR_FALSE);
2596  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Could not mark device as not hidden!");
2597  }
2598 
2599  return NS_OK;
2600 }
2601 
2602 nsresult
2604 {
2605  // Validate arguments.
2606  NS_ENSURE_ARG_POINTER(aVolume);
2607 
2608  // Function variables.
2609  nsresult rv;
2610  PRBool isVolumeListEmpty = PR_FALSE;
2611 
2612  // If the device volume has a device library, get the library GUID.
2613  nsAutoString libraryGUID;
2614  nsCOMPtr<sbIDeviceLibrary> library;
2615  rv = aVolume->GetDeviceLibrary(getter_AddRefs(library));
2616  NS_ENSURE_SUCCESS(rv, rv);
2617  if (library)
2618  library->GetGuid(libraryGUID);
2619 
2620  // Remove the volume from the volume lists and tables.
2621  nsAutoString volumeGUID;
2622  rv = aVolume->GetGUID(volumeGUID);
2623  NS_ENSURE_SUCCESS(rv, rv);
2624  {
2625  nsAutoLock autoVolumeLock(mVolumeLock);
2626  mVolumeList.RemoveElement(aVolume);
2627  mVolumeGUIDTable.Remove(volumeGUID);
2628  if (!libraryGUID.IsEmpty())
2629  mVolumeLibraryGUIDTable.Remove(libraryGUID);
2630  if (mPrimaryVolume == aVolume)
2631  mPrimaryVolume = nsnull;
2632 
2633  isVolumeListEmpty = mVolumeList.IsEmpty();
2634  }
2635 
2636  // If the last volume has been ejected, mark this device as hidden
2637  if (isVolumeListEmpty) {
2638  nsCOMPtr<sbIDeviceProperties> deviceProperties;
2639  rv = GetProperties(getter_AddRefs(deviceProperties));
2640  NS_ENSURE_SUCCESS(rv, rv);
2641 
2642  rv = deviceProperties->SetHidden(PR_TRUE);
2643  NS_ENSURE_SUCCESS(rv, rv);
2644  }
2645 
2646  return NS_OK;
2647 }
2648 
2649 nsresult
2651  sbBaseDeviceVolume** aVolume)
2652 {
2653  // Validate arguments.
2654  NS_ENSURE_ARG_POINTER(aItem);
2655  NS_ENSURE_ARG_POINTER(aVolume);
2656 
2657  // Function variables.
2658  nsresult rv;
2659 
2660  // Get the item's library's guid.
2661  nsAutoString libraryGUID;
2662  nsCOMPtr<sbILibrary> library;
2663  rv = aItem->GetLibrary(getter_AddRefs(library));
2664  NS_ENSURE_SUCCESS(rv, rv);
2665  rv = library->GetGuid(libraryGUID);
2666  NS_ENSURE_SUCCESS(rv, rv);
2667 
2668  // Get the volume from the volume library GUID table.
2669  nsRefPtr<sbBaseDeviceVolume> volume;
2670  {
2671  nsAutoLock autoVolumeLock(mVolumeLock);
2672  PRBool present = mVolumeLibraryGUIDTable.Get(libraryGUID,
2673  getter_AddRefs(volume));
2674  NS_ENSURE_TRUE(present, NS_ERROR_NOT_AVAILABLE);
2675  }
2676 
2677  // Return results.
2678  volume.forget(aVolume);
2679 
2680  return NS_OK;
2681 }
2682 
2683 //------------------------------------------------------------------------------
2684 //
2685 // Device settings services.
2686 //
2687 //------------------------------------------------------------------------------
2688 
2689 nsresult
2691  (nsIDOMDocument** aDeviceSettingsDocument)
2692 {
2693  // No device settings document.
2694  NS_ENSURE_ARG_POINTER(aDeviceSettingsDocument);
2695  *aDeviceSettingsDocument = nsnull;
2696  return NS_OK;
2697 }
2698 
2699 nsresult
2701  (nsIFile* aDeviceSettingsFile,
2702  nsIDOMDocument** aDeviceSettingsDocument)
2703 {
2704  // Validate arguments.
2705  NS_ENSURE_ARG_POINTER(aDeviceSettingsFile);
2706  NS_ENSURE_ARG_POINTER(aDeviceSettingsDocument);
2707 
2708  // Function variables.
2709  nsresult rv;
2710 
2711  // If the device settings file does not exist, just return null.
2712  PRBool exists;
2713  rv = aDeviceSettingsFile->Exists(&exists);
2714  NS_ENSURE_SUCCESS(rv, rv);
2715  if (!exists) {
2716  *aDeviceSettingsDocument = nsnull;
2717  return NS_OK;
2718  }
2719 
2720  // Get the device settings file URI spec.
2721  nsCAutoString deviceSettingsURISpec;
2722  nsCOMPtr<nsIURI> deviceSettingsURI;
2723  rv = NS_NewFileURI(getter_AddRefs(deviceSettingsURI), aDeviceSettingsFile);
2724  NS_ENSURE_SUCCESS(rv, rv);
2725  rv = deviceSettingsURI->GetSpec(deviceSettingsURISpec);
2726  NS_ENSURE_SUCCESS(rv, rv);
2727 
2728  // Create an XMLHttpRequest object.
2729  nsCOMPtr<nsIXMLHttpRequest>
2730  xmlHttpRequest = do_CreateInstance(NS_XMLHTTPREQUEST_CONTRACTID, &rv);
2731  NS_ENSURE_SUCCESS(rv, rv);
2732  nsCOMPtr<nsIScriptSecurityManager> ssm =
2733  do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
2734  NS_ENSURE_SUCCESS(rv, rv);
2735  nsCOMPtr<nsIPrincipal> principal;
2736  rv = ssm->GetSystemPrincipal(getter_AddRefs(principal));
2737  NS_ENSURE_SUCCESS(rv, rv);
2738  rv = xmlHttpRequest->Init(principal, nsnull, nsnull, nsnull);
2739  NS_ENSURE_SUCCESS(rv, rv);
2740 
2741  // Read the device settings file document.
2742  rv = xmlHttpRequest->OpenRequest(NS_LITERAL_CSTRING("GET"),
2743  deviceSettingsURISpec,
2744  PR_FALSE, // async
2745  SBVoidString(), // user
2746  SBVoidString()); // password
2747  NS_ENSURE_SUCCESS(rv, rv);
2748  rv = xmlHttpRequest->Send(nsnull);
2749  NS_ENSURE_SUCCESS(rv, rv);
2750  rv = xmlHttpRequest->GetResponseXML(aDeviceSettingsDocument);
2751  NS_ENSURE_SUCCESS(rv, rv);
2752 
2753  return NS_OK;
2754 }
2755 
2756 nsresult
2758  (nsTArray<PRUint8>& aDeviceSettingsContent,
2759  nsIDOMDocument** aDeviceSettingsDocument)
2760 {
2761  // Validate arguments.
2762  NS_ENSURE_ARG_POINTER(aDeviceSettingsDocument);
2763 
2764  // Function variables.
2765  nsresult rv;
2766 
2767  // Parse the device settings document from the content.
2768  nsCOMPtr<nsIDOMParser> domParser = do_CreateInstance(NS_DOMPARSER_CONTRACTID,
2769  &rv);
2770  NS_ENSURE_SUCCESS(rv, rv);
2771  rv = domParser->ParseFromBuffer(aDeviceSettingsContent.Elements(),
2772  aDeviceSettingsContent.Length(),
2773  "text/xml",
2774  aDeviceSettingsDocument);
2775  NS_ENSURE_SUCCESS(rv, rv);
2776 
2777  return NS_OK;
2778 }
2779 
2780 nsresult
2782 {
2783  nsresult rv;
2784 
2785  // This function should only be called on the main thread.
2786  NS_ASSERTION(NS_IsMainThread(), "not on main thread");
2787 
2788  // Get the device settings document. Do nothing if device settings document
2789  // is not available.
2790  nsCOMPtr<nsIDOMDocument> deviceSettingsDocument;
2791  rv = GetDeviceSettingsDocument(getter_AddRefs(deviceSettingsDocument));
2792  NS_ENSURE_SUCCESS(rv, rv);
2793  if (!deviceSettingsDocument)
2794  return NS_OK;
2795 
2796  // Apply the device settings.
2797  rv = ApplyDeviceSettings(deviceSettingsDocument);
2798  NS_ENSURE_SUCCESS(rv, rv);
2799 
2800  return NS_OK;
2801 }
2802 
2803 nsresult
2804 sbBaseDevice::ApplyDeviceSettings(nsIDOMDocument* aDeviceSettingsDocument)
2805 {
2806  // Validate arguments.
2807  NS_ENSURE_ARG_POINTER(aDeviceSettingsDocument);
2808 
2809  // Function variables.
2810  nsresult rv;
2811 
2812  // Apply the device friendly name setting.
2814  (aDeviceSettingsDocument,
2815  NS_LITERAL_STRING(SB_DEVICE_PROPERTY_NAME));
2816  NS_ENSURE_SUCCESS(rv, rv);
2817 
2818  // Apply device settings device info.
2819  rv = ApplyDeviceSettingsDeviceInfo(aDeviceSettingsDocument);
2820  NS_ENSURE_SUCCESS(rv, rv);
2821 
2822  // Apply the device capabilities.
2823  rv = ApplyDeviceSettingsToCapabilities(aDeviceSettingsDocument);
2824  NS_ENSURE_SUCCESS(rv, rv);
2825 
2826  return NS_OK;
2827 }
2828 
2829 nsresult
2831  (nsIDOMDocument* aDeviceSettingsDocument,
2832  const nsAString& aPropertyName)
2833 {
2834  // Validate arguments.
2835  NS_ENSURE_ARG_POINTER(aDeviceSettingsDocument);
2836  NS_ENSURE_TRUE(StringBeginsWith(aPropertyName,
2837  NS_LITERAL_STRING(SB_DEVICE_PROPERTY_BASE)),
2838  NS_ERROR_INVALID_ARG);
2839 
2840  // Function variables.
2841  NS_NAMED_LITERAL_STRING(devPropNS, SB_DEVICE_PROPERTY_NS);
2842  nsCOMPtr<nsIDOMNode> dummyNode;
2843  nsresult rv;
2844 
2845  // This function should only be called on the main thread.
2846  NS_ASSERTION(NS_IsMainThread(), "not on main thread");
2847 
2848  // Get the device property name suffix.
2849  nsAutoString propertyNameSuffix(Substring(aPropertyName,
2850  strlen(SB_DEVICE_PROPERTY_BASE)));
2851 
2852  // Get the device setting element.
2853  nsCOMPtr<nsIDOMElement> deviceSettingElement;
2854  nsCOMPtr<nsIDOMNodeList> elementList;
2855  nsCOMPtr<nsIDOMNode> elementNode;
2856  PRUint32 elementCount;
2857  rv = aDeviceSettingsDocument->GetElementsByTagNameNS
2858  (devPropNS,
2859  propertyNameSuffix,
2860  getter_AddRefs(elementList));
2861  NS_ENSURE_SUCCESS(rv, rv);
2862  rv = elementList->GetLength(&elementCount);
2863  NS_ENSURE_SUCCESS(rv, rv);
2864  if (elementCount > 0) {
2865  rv = elementList->Item(0, getter_AddRefs(elementNode));
2866  NS_ENSURE_SUCCESS(rv, rv);
2867  deviceSettingElement = do_QueryInterface(elementNode, &rv);
2868  NS_ENSURE_SUCCESS(rv, rv);
2869  }
2870 
2871  // Do nothing if device settings element does not exist.
2872  if (!deviceSettingElement)
2873  return NS_OK;
2874 
2875  // Apply the device setting to the property.
2876  nsAutoString propertyValue;
2877  rv = deviceSettingElement->GetAttribute(NS_LITERAL_STRING("value"),
2878  propertyValue);
2879  NS_ENSURE_SUCCESS(rv, rv);
2880  rv = ApplyDeviceSettingsToProperty(aPropertyName,
2881  sbNewVariant(propertyValue));
2882  NS_ENSURE_SUCCESS(rv, rv);
2883 
2884  return NS_OK;
2885 }
2886 
2887 nsresult
2888 sbBaseDevice::ApplyDeviceSettingsToProperty(const nsAString& aPropertyName,
2889  nsIVariant* aPropertyValue)
2890 {
2891  // Nothing for the base class to do.
2892  return NS_OK;
2893 }
2894 
2895 nsresult
2897  (nsIDOMDocument* aDeviceSettingsDocument)
2898 {
2899  // Validate arguments.
2900  NS_ENSURE_ARG_POINTER(aDeviceSettingsDocument);
2901 
2902  // Function variables.
2903  nsAutoPtr<nsString> folderURL;
2904  PRBool needMediaFolderUpdate = PR_FALSE;
2905  PRBool success;
2906  nsresult rv;
2907 
2908  // Get the device info from the device settings document. Do nothing if no
2909  // device info present.
2910  nsAutoPtr<sbDeviceXMLInfo> deviceXMLInfo(new sbDeviceXMLInfo(this));
2911  PRBool present;
2912  NS_ENSURE_TRUE(deviceXMLInfo, NS_ERROR_OUT_OF_MEMORY);
2913  rv = deviceXMLInfo->Read(aDeviceSettingsDocument);
2914  NS_ENSURE_SUCCESS(rv, rv);
2915  rv = deviceXMLInfo->GetDeviceInfoPresent(&present);
2916  NS_ENSURE_SUCCESS(rv, rv);
2917  if (!present)
2918  return NS_OK;
2919 
2920  // Get device folders.
2921  for (PRUint32 i = 0;
2922  i < NS_ARRAY_LENGTH(sbBaseDeviceSupportedFolderContentTypeList);
2923  ++i) {
2924  // Get the next folder content type.
2925  PRUint32 folderContentType = sbBaseDeviceSupportedFolderContentTypeList[i];
2926 
2927  // Allocate a folder URL.
2928  nsAutoPtr<nsString> folderURL(new nsString());
2929  NS_ENSURE_TRUE(folderURL, NS_ERROR_OUT_OF_MEMORY);
2930 
2931  // Get the device folder URL and add it to the media folder URL table.
2932  rv = deviceXMLInfo->GetDeviceFolder(folderContentType, *folderURL);
2933  NS_ENSURE_SUCCESS(rv, rv);
2934  if (!folderURL->IsEmpty()) {
2935  success = mMediaFolderURLTable.Put(folderContentType, folderURL);
2936  NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
2937  folderURL.forget();
2938  needMediaFolderUpdate = PR_TRUE;
2939  }
2940  }
2941 
2942  nsString excludedFolders;
2943  rv = deviceXMLInfo->GetExcludedFolders(excludedFolders);
2944  NS_ENSURE_SUCCESS(rv, rv);
2945 
2946  // Get the device properties.
2947  nsCOMPtr<nsIWritablePropertyBag> deviceProperties;
2948  rv = GetWritableDeviceProperties(this, getter_AddRefs(deviceProperties));
2949  NS_ENSURE_SUCCESS(rv, rv);
2950 
2951  if (!excludedFolders.IsEmpty()) {
2952  LOG(("Excluded Folders: %s",
2953  NS_LossyConvertUTF16toASCII(excludedFolders).BeginReading()));
2954 
2955  rv = deviceProperties->SetProperty(
2956  NS_LITERAL_STRING(SB_DEVICE_PROPERTY_EXCLUDED_FOLDERS),
2957  sbNewVariant(excludedFolders));
2958  NS_ENSURE_SUCCESS(rv, rv);
2959  }
2960 
2961  // Get import rules:
2962  nsCOMPtr<nsIArray> importRules;
2963  rv = deviceXMLInfo->GetImportRules(getter_AddRefs(importRules));
2964  NS_ENSURE_SUCCESS(rv, rv);
2965 
2966  // Stow the rules, if any, in the device properties:
2967  if (importRules) {
2968  nsCOMPtr<nsIWritablePropertyBag2> devProps2 =
2969  do_QueryInterface(deviceProperties, &rv);
2970  NS_ENSURE_SUCCESS(rv, rv);
2971  rv = devProps2->SetPropertyAsInterface(
2972  NS_LITERAL_STRING(SB_DEVICE_PROPERTY_IMPORT_RULES),
2973  importRules);
2974  NS_ENSURE_SUCCESS(rv, rv);
2975  }
2976 
2977  // Update media folders if needed. Ignore errors if media folders fail to
2978  // update.
2979  if (needMediaFolderUpdate)
2980  UpdateMediaFolders();
2981 
2982  // Log the device folders.
2983  LogDeviceFolders();
2984 
2985  // Determine if the device supports format.
2986  PRBool supportsFormat;
2987  rv = deviceXMLInfo->GetDoesDeviceSupportReformat(&supportsFormat);
2988  NS_ENSURE_SUCCESS(rv, rv);
2989 
2990  rv = deviceProperties->SetProperty(
2991  NS_LITERAL_STRING(SB_DEVICE_PROPERTY_SUPPORTS_REFORMAT),
2992  sbNewVariant(supportsFormat));
2993  NS_ENSURE_SUCCESS(rv, rv);
2994 
2995  return NS_OK;
2996 }
2997 
2998 nsresult
3000  (nsIDOMDocument* aDeviceSettingsDocument)
3001 {
3002  // Validate arguments.
3003  NS_ENSURE_ARG_POINTER(aDeviceSettingsDocument);
3004 
3005  // Function variables.
3006  nsresult rv;
3007 
3008  // Get the device capabilities from the device settings document.
3009  nsCOMPtr<sbIDeviceCapabilities> deviceCaps;
3010  rv = sbDeviceXMLCapabilities::GetCapabilities(getter_AddRefs(deviceCaps),
3011  aDeviceSettingsDocument,
3012  this);
3013  NS_ENSURE_SUCCESS(rv, rv);
3014 
3015  // If the device settings document has device capabilities, use them;
3016  // otherwise, continue using current device capabilities.
3017  if (deviceCaps)
3018  mCapabilities = deviceCaps;
3019 
3020  return NS_OK;
3021 }
3022 
3023 //------------------------------------------------------------------------------
3024 //
3025 // Device properties services.
3026 //
3027 //------------------------------------------------------------------------------
3028 
3029 nsresult
3031 {
3032  return NS_OK;
3033 }
3034 
3035 
3040 nsresult
3042 {
3043  TRACE(("%s[%p]", __FUNCTION__, this));
3044  nsresult rv;
3045 
3046  // Update the device statistics properties.
3048  NS_ENSURE_SUCCESS(rv, rv);
3049 
3050  // Update the volume names.
3051  rv = UpdateVolumeNames();
3052  NS_ENSURE_SUCCESS(rv, rv);
3053 
3054  return NS_OK;
3055 }
3056 
3057 
3064 nsresult
3066 {
3067  return NS_OK;
3068 }
3069 
3070 
3075 nsresult
3077 {
3078  nsresult rv;
3079 
3080  // Get the list of all volumes.
3081  nsTArray< nsRefPtr<sbBaseDeviceVolume> > volumeList;
3082  {
3083  nsAutoLock autoVolumeLock(mVolumeLock);
3084  volumeList = mVolumeList;
3085  }
3086 
3087  TRACE(("%s[%p] (%u volumes)", __FUNCTION__, this, volumeList.Length()));
3088 
3089  // Update the statistics properties for all volumes.
3090  for (PRUint32 i = 0; i < volumeList.Length(); i++) {
3091  // Get the volume.
3092  nsRefPtr<sbBaseDeviceVolume> volume = volumeList[i];
3093 
3094  // Skip volume if it's not mounted.
3095  PRBool isMounted;
3096  rv = volume->GetIsMounted(&isMounted);
3097  NS_ENSURE_SUCCESS(rv, rv);
3098  if (!isMounted) {
3099  #if PR_LOGGING
3100  nsString volumeGuid;
3101  rv = volume->GetGUID(volumeGuid);
3102  if (NS_FAILED(rv)) volumeGuid.AssignLiteral("<unknown guid>");
3103  TRACE(("%s[%p] - volume %s not mounted",
3104  __FUNCTION__,
3105  this,
3106  NS_ConvertUTF16toUTF8(volumeGuid).get()));
3107  #endif /* PR_LOGGING */
3108  continue;
3109  }
3110 
3111  // Get the volume library and statistics.
3112  nsCOMPtr<sbIDeviceLibrary> deviceLibrary;
3113  nsRefPtr<sbDeviceStatistics> deviceStatistics;
3114  rv = volume->GetDeviceLibrary(getter_AddRefs(deviceLibrary));
3115  NS_ENSURE_SUCCESS(rv, rv);
3116  rv = volume->GetStatistics(getter_AddRefs(deviceStatistics));
3117  NS_ENSURE_SUCCESS(rv, rv);
3118 
3119  // Update the volume statistics properties.
3121  (deviceLibrary,
3122  NS_LITERAL_STRING(SB_DEVICE_PROPERTY_MUSIC_ITEM_COUNT),
3123  sbAutoString(deviceStatistics->AudioCount()));
3124  NS_ENSURE_SUCCESS(rv, rv);
3125  TRACE(("%s[%p]: %s = %u",
3126  __FUNCTION__,
3127  this,
3128  "AudioCount",
3129  deviceStatistics->AudioCount()));
3131  (deviceLibrary,
3132  NS_LITERAL_STRING(SB_DEVICE_PROPERTY_MUSIC_USED_SPACE),
3133  sbAutoString(deviceStatistics->AudioUsed()));
3134  NS_ENSURE_SUCCESS(rv, rv);
3135  TRACE(("%s[%p]: %s = %llu",
3136  __FUNCTION__,
3137  this,
3138  "AudioUsed",
3139  deviceStatistics->AudioUsed()));
3141  (deviceLibrary,
3142  NS_LITERAL_STRING(SB_DEVICE_PROPERTY_MUSIC_TOTAL_PLAY_TIME),
3143  sbAutoString(deviceStatistics->AudioPlayTime()));
3144  NS_ENSURE_SUCCESS(rv, rv);
3145  TRACE(("%s[%p]: %s = %llu",
3146  __FUNCTION__,
3147  this,
3148  "AudioPlayTime",
3149  deviceStatistics->AudioPlayTime()));
3151  (deviceLibrary,
3152  NS_LITERAL_STRING(SB_DEVICE_PROPERTY_VIDEO_ITEM_COUNT),
3153  sbAutoString(deviceStatistics->VideoCount()));
3154  NS_ENSURE_SUCCESS(rv, rv);
3155  TRACE(("%s[%p]: %s = %u",
3156  __FUNCTION__,
3157  this,
3158  "VideoCount",
3159  deviceStatistics->VideoCount()));
3161  (deviceLibrary,
3162  NS_LITERAL_STRING(SB_DEVICE_PROPERTY_VIDEO_USED_SPACE),
3163  sbAutoString(deviceStatistics->VideoUsed()));
3164  NS_ENSURE_SUCCESS(rv, rv);
3165  TRACE(("%s[%p]: %s = %llu",
3166  __FUNCTION__,
3167  this,
3168  "VideoUsed",
3169  deviceStatistics->VideoUsed()));
3171  (deviceLibrary,
3172  NS_LITERAL_STRING(SB_DEVICE_PROPERTY_VIDEO_TOTAL_PLAY_TIME),
3173  sbAutoString(deviceStatistics->VideoPlayTime()));
3174  NS_ENSURE_SUCCESS(rv, rv);
3175  TRACE(("%s[%p]: %s = %llu",
3176  __FUNCTION__,
3177  this,
3178  "VideoPlayTime",
3179  deviceStatistics->VideoPlayTime()));
3181  (deviceLibrary,
3182  NS_LITERAL_STRING(SB_DEVICE_PROPERTY_IMAGE_ITEM_COUNT),
3183  sbAutoString(deviceStatistics->ImageCount()));
3184  NS_ENSURE_SUCCESS(rv, rv);
3185  TRACE(("%s[%p]: %s = %u",
3186  __FUNCTION__,
3187  this,
3188  "ImageCount",
3189  deviceStatistics->ImageCount()));
3191  (deviceLibrary,
3192  NS_LITERAL_STRING(SB_DEVICE_PROPERTY_IMAGE_USED_SPACE),
3193  sbAutoString(deviceStatistics->ImageUsed()));
3194  NS_ENSURE_SUCCESS(rv, rv);
3195  TRACE(("%s[%p]: %s = %llu",
3196  __FUNCTION__,
3197  this,
3198  "ImageUsed",
3199  deviceStatistics->ImageUsed()));
3200  }
3201 
3202  return NS_OK;
3203 }
3204 
3205 
3210 nsresult
3212 {
3213  // Get the list of all volumes.
3214  nsTArray< nsRefPtr<sbBaseDeviceVolume> > volumeList;
3215  {
3216  nsAutoLock autoVolumeLock(mVolumeLock);
3217  volumeList = mVolumeList;
3218  }
3219 
3220  // Update the names for all volumes.
3221  for (PRUint32 i = 0; i < volumeList.Length(); i++) {
3222  // Update the volume name, continuing on error.
3223  UpdateVolumeName(volumeList[i]);
3224  }
3225 
3226  return NS_OK;
3227 }
3228 
3229 
3236 nsresult
3238 {
3239  // Validate arguments.
3240  NS_ENSURE_ARG_POINTER(aVolume);
3241 
3242  // Function variables.
3243  nsresult rv;
3244 
3245  // Get the volume device library.
3246  nsCOMPtr<sbIDeviceLibrary> deviceLibrary;
3247  rv = aVolume->GetDeviceLibrary(getter_AddRefs(deviceLibrary));
3248  NS_ENSURE_SUCCESS(rv, rv);
3249 
3250  // Get the volume capacity.
3251  nsAutoString displayCapacity;
3252  nsAutoString capacity;
3253  if (deviceLibrary) {
3254  rv = deviceLibrary->GetProperty
3255  (NS_LITERAL_STRING(SB_DEVICE_PROPERTY_CAPACITY),
3256  capacity);
3257  if (NS_SUCCEEDED(rv) && !capacity.IsEmpty()) {
3258  // Convert the capacity to a display capacity.
3259  nsCOMPtr<sbIPropertyUnitConverter> storageConverter =
3260  do_CreateInstance(SB_STORAGEPROPERTYUNITCONVERTER_CONTRACTID, &rv);
3261  NS_ENSURE_SUCCESS(rv, rv);
3262  rv = storageConverter->AutoFormat(capacity, -1, 1, displayCapacity);
3263  NS_ENSURE_SUCCESS(rv, rv);
3264  }
3265  }
3266 
3267  // Check if the volume is removable.
3268  PRBool storageRemovable = PR_FALSE;
3269  PRInt32 removable;
3270  rv = aVolume->GetRemovable(&removable);
3271  NS_ENSURE_SUCCESS(rv, rv);
3272  if (removable >= 0) {
3273  storageRemovable = (removable != 0);
3274  }
3275  else {
3276  // Assume first volume is internal and all others are removable.
3277  PRUint32 volumeIndex;
3278  {
3279  nsAutoLock autoVolumeLock(mVolumeLock);
3280  volumeIndex = mVolumeList.IndexOf(aVolume);
3281  }
3282  NS_ASSERTION(volumeIndex != mVolumeList.NoIndex, "Volume not found");
3283  storageRemovable = (volumeIndex != 0);
3284  }
3285 
3286  // Produce the library name.
3287  nsAutoString libraryName;
3288  nsTArray<nsString> libraryNameParams;
3289  libraryNameParams.AppendElement(displayCapacity);
3290  if (!storageRemovable) {
3291  if (!displayCapacity.IsEmpty()) {
3292  libraryName =
3293  SBLocalizedString("device.volume.internal.name_with_capacity",
3294  libraryNameParams);
3295  }
3296  else {
3297  libraryName = SBLocalizedString("device.volume.internal.name");
3298  }
3299  }
3300  else {
3301  if (!displayCapacity.IsEmpty()) {
3302  libraryName =
3303  SBLocalizedString("device.volume.removable.name_with_capacity",
3304  libraryNameParams);
3305  }
3306  else {
3307  libraryName = SBLocalizedString("device.volume.removable.name");
3308  }
3309  }
3310 
3311  // Update the library name if necessary.
3312  if (deviceLibrary) {
3313  nsAutoString currentLibraryName;
3314  rv = deviceLibrary->GetName(currentLibraryName);
3315  NS_ENSURE_SUCCESS(rv, rv);
3316  if (!currentLibraryName.Equals(libraryName)) {
3317  rv = deviceLibrary->SetName(libraryName);
3318  NS_ENSURE_SUCCESS(rv, rv);
3319  }
3320  }
3321  return NS_OK;
3322 }
3323 
3324 
3325 //------------------------------------------------------------------------------
3326 //
3327 // Device preference services.
3328 //
3329 //------------------------------------------------------------------------------
3330 
3331 NS_IMETHODIMP sbBaseDevice::SetWarningDialogEnabled(const nsAString & aWarning, PRBool aEnabled)
3332 {
3333  nsresult rv;
3334 
3335  // get the key for this warning
3336  nsString prefKey(NS_LITERAL_STRING(PREF_WARNING));
3337  prefKey.Append(aWarning);
3338 
3339  // have a variant to set
3340  nsCOMPtr<nsIWritableVariant> var =
3341  do_CreateInstance("@songbirdnest.com/Songbird/Variant;1", &rv);
3342  NS_ENSURE_SUCCESS(rv, rv);
3343 
3344  rv = var->SetAsBool(aEnabled);
3345  NS_ENSURE_SUCCESS(rv, rv);
3346 
3347  rv = SetPreference(prefKey, var);
3348  NS_ENSURE_SUCCESS(rv, rv);
3349 
3350  return NS_OK;
3351 }
3352 
3353 NS_IMETHODIMP sbBaseDevice::GetWarningDialogEnabled(const nsAString & aWarning, PRBool *_retval)
3354 {
3355  NS_ENSURE_ARG_POINTER(_retval);
3356 
3357  nsresult rv;
3358 
3359  // get the key for this warning
3360  nsString prefKey(NS_LITERAL_STRING(PREF_WARNING));
3361  prefKey.Append(aWarning);
3362 
3363  nsCOMPtr<nsIVariant> var;
3364  rv = GetPreference(prefKey, getter_AddRefs(var));
3365  NS_ENSURE_SUCCESS(rv, rv);
3366 
3367  // does the pref exist?
3368  PRUint16 dataType;
3369  rv = var->GetDataType(&dataType);
3370  NS_ENSURE_SUCCESS(rv, rv);
3371 
3372  if (dataType == nsIDataType::VTYPE_EMPTY ||
3373  dataType == nsIDataType::VTYPE_VOID)
3374  {
3375  // by default warnings are enabled
3376  *_retval = PR_TRUE;
3377  } else {
3378  rv = var->GetAsBool(_retval);
3379  NS_ENSURE_SUCCESS(rv, rv);
3380  }
3381 
3382  return NS_OK;
3383 }
3384 
3386 {
3387  nsresult rv;
3388 
3389  // get the pref branch for this device
3390  nsCOMPtr<nsIPrefBranch> prefBranch;
3391  rv = GetPrefBranch(getter_AddRefs(prefBranch));
3392  NS_ENSURE_SUCCESS(rv, rv);
3393 
3394  // the key for all warnings
3395  nsString prefKey(NS_LITERAL_STRING(PREF_WARNING));
3396 
3397  // clear the prefs
3398  rv = prefBranch->DeleteBranch(NS_ConvertUTF16toUTF8(prefKey).get());
3399  NS_ENSURE_SUCCESS(rv, rv);
3400 
3401  return NS_OK;
3402 }
3403 
3404 NS_IMETHODIMP sbBaseDevice::OpenInputStream(nsIURI* aURI,
3405  nsIInputStream** retval)
3406 {
3407  return NS_ERROR_NOT_AVAILABLE;
3408 }
3409 
3410 nsresult sbBaseDevice::GetPrefBranch(const char *aPrefBranchName,
3411  nsIPrefBranch** aPrefBranch)
3412 {
3413  NS_ENSURE_ARG_POINTER(aPrefBranch);
3414  nsresult rv;
3415 
3416  // If we're not on the main thread proxy the service
3417  PRBool const isMainThread = NS_IsMainThread();
3418 
3419  // get the prefs service
3420  nsCOMPtr<nsIPrefService> prefService;
3421 
3422  if (!isMainThread) {
3423  prefService = do_ProxiedGetService(NS_PREFSERVICE_CONTRACTID, &rv);
3424  NS_ENSURE_SUCCESS(rv, rv);
3425  }
3426  else {
3427  prefService = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
3428  NS_ENSURE_SUCCESS(rv, rv);
3429  }
3430 
3431  nsCOMPtr<nsIThread> target;
3432  rv = NS_GetMainThread(getter_AddRefs(target));
3433  NS_ENSURE_SUCCESS(rv, rv);
3434 
3435  // get the pref branch
3436  nsCOMPtr<nsIPrefBranch> prefBranch;
3437  rv = prefService->GetBranch(aPrefBranchName, getter_AddRefs(prefBranch));
3438  NS_ENSURE_SUCCESS(rv, rv);
3439 
3440  // If we're not on the main thread proxy the pref branch
3441  if (!isMainThread) {
3442  nsCOMPtr<nsIPrefBranch> proxy;
3443  rv = do_GetProxyForObject(target,
3444  NS_GET_IID(nsIPrefBranch),
3445  prefBranch,
3446  nsIProxyObjectManager::INVOKE_SYNC |
3447  nsIProxyObjectManager::FORCE_PROXY_CREATION,
3448  getter_AddRefs(proxy));
3449  NS_ENSURE_SUCCESS(rv, rv);
3450  prefBranch.swap(proxy);
3451  }
3452 
3453  prefBranch.forget(aPrefBranch);
3454 
3455  return rv;
3456 }
3457 
3458 nsresult sbBaseDevice::GetPrefBranchRoot(nsACString& aRoot)
3459 {
3460  nsresult rv;
3461 
3462  // get id of this device
3463  nsID* id;
3464  rv = GetId(&id);
3465  NS_ENSURE_SUCCESS(rv, rv);
3466 
3467  // get that as a string
3468  char idString[NSID_LENGTH];
3469  id->ToProvidedString(idString);
3470  NS_Free(id);
3471 
3472  // create the pref branch root
3473  aRoot.Assign(PREF_DEVICE_PREFERENCES_BRANCH);
3474  aRoot.Append(idString);
3475  aRoot.AppendLiteral(".preferences.");
3476 
3477  return NS_OK;
3478 }
3479 
3481 {
3482  NS_ENSURE_ARG_POINTER(aPrefBranch);
3483  nsresult rv;
3484 
3485  // get the pref branch root
3486  nsCAutoString root;
3487  rv = GetPrefBranchRoot(root);
3488  NS_ENSURE_SUCCESS(rv, rv);
3489 
3490  return GetPrefBranch(root.get(), aPrefBranch);
3491 }
3492 
3494  nsIPrefBranch** aPrefBranch)
3495 {
3496  NS_ENSURE_ARG_POINTER(aLibrary);
3497  NS_ENSURE_ARG_POINTER(aPrefBranch);
3498  nsresult rv;
3499 
3500  // start with the pref branch root
3501  nsCAutoString prefKey;
3502  rv = GetPrefBranchRoot(prefKey);
3503  NS_ENSURE_SUCCESS(rv, rv);
3504 
3505  // add the library pref key
3506  nsAutoString libraryGUID;
3507  rv = aLibrary->GetGuid(libraryGUID);
3508  NS_ENSURE_SUCCESS(rv, rv);
3509  prefKey.Append(".library.");
3510  prefKey.Append(NS_ConvertUTF16toUTF8(libraryGUID));
3511  prefKey.Append(".");
3512 
3513  return GetPrefBranch(prefKey.get(), aPrefBranch);
3514 }
3515 
3516 nsresult sbBaseDevice::ApplyPreference(const nsAString& aPrefName,
3517  nsIVariant* aPrefValue)
3518 {
3519  // Validate arguments.
3520  NS_ENSURE_ARG_POINTER(aPrefValue);
3521 
3522  // Function variables.
3523  nsresult rv;
3524 
3525  // Check if it's a library preference.
3526  PRBool isLibraryPreference = GetIsLibraryPreference(aPrefName);
3527 
3528  // Apply preference.
3529  if (isLibraryPreference) {
3530  // Get the library preference info.
3531  nsCOMPtr<sbIDeviceLibrary> library;
3532  nsAutoString libraryPrefBase;
3533  nsAutoString libraryPrefName;
3534  rv = GetPreferenceLibrary(aPrefName,
3535  getter_AddRefs(library),
3536  libraryPrefBase);
3537  NS_ENSURE_SUCCESS(rv, rv);
3538  rv = GetLibraryPreferenceName(aPrefName, libraryPrefBase, libraryPrefName);
3539  NS_ENSURE_SUCCESS(rv, rv);
3540 
3541  // Apply the library preference.
3542  rv = ApplyLibraryPreference(library, libraryPrefName, aPrefValue);
3543  NS_ENSURE_SUCCESS(rv, rv);
3544  }
3545 
3546  return NS_OK;
3547 }
3548 
3549 PRBool sbBaseDevice::GetIsLibraryPreference(const nsAString& aPrefName)
3550 {
3551  return StringBeginsWith(aPrefName,
3552  NS_LITERAL_STRING(PREF_DEVICE_LIBRARY_BASE));
3553 }
3554 
3555 nsresult sbBaseDevice::GetPreferenceLibrary(const nsAString& aPrefName,
3556  sbIDeviceLibrary** aLibrary,
3557  nsAString& aLibraryPrefBase)
3558 {
3559  // Function variables.
3560  nsresult rv;
3561 
3562  // Get the device content.
3563  nsCOMPtr<sbIDeviceContent> content;
3564  rv = GetContent(getter_AddRefs(content));
3565  NS_ENSURE_SUCCESS(rv, rv);
3566  nsCOMPtr<nsIArray> libraryList;
3567  rv = content->GetLibraries(getter_AddRefs(libraryList));
3568  NS_ENSURE_SUCCESS(rv, rv);
3569 
3570  // Search the libraries for a match. Return results if found.
3571  PRUint32 libraryCount;
3572  rv = libraryList->GetLength(&libraryCount);
3573  NS_ENSURE_SUCCESS(rv, rv);
3574  for (PRUint32 i = 0; i < libraryCount; i++) {
3575  // Get the next library.
3576  nsCOMPtr<sbIDeviceLibrary> library = do_QueryElementAt(libraryList, i, &rv);
3577  NS_ENSURE_SUCCESS(rv, rv);
3578 
3579  // Get the library info.
3580  nsAutoString guid;
3581  rv = library->GetGuid(guid);
3582  NS_ENSURE_SUCCESS(rv, rv);
3583 
3584  // Return library if it matches pref.
3585  nsAutoString libraryPrefBase;
3586  rv = GetLibraryPreferenceBase(library, libraryPrefBase);
3587  NS_ENSURE_SUCCESS(rv, rv);
3588  if (StringBeginsWith(aPrefName, libraryPrefBase)) {
3589  if (aLibrary)
3590  library.forget(aLibrary);
3591  aLibraryPrefBase.Assign(libraryPrefBase);
3592  return NS_OK;
3593  }
3594  }
3595 
3596  // Library not found.
3597  return NS_ERROR_NOT_AVAILABLE;
3598 }
3599 
3601  const nsAString& aLibraryPrefName,
3602  nsIVariant** aPrefValue)
3603 {
3604  // Validate arguments.
3605  NS_ENSURE_ARG_POINTER(aLibrary);
3606 
3607  // Function variables.
3608  nsresult rv;
3609 
3610  // Get the library preference base.
3611  nsAutoString libraryPrefBase;
3612  rv = GetLibraryPreferenceBase(aLibrary, libraryPrefBase);
3613  NS_ENSURE_SUCCESS(rv, rv);
3614 
3615  return GetLibraryPreference(libraryPrefBase, aLibraryPrefName, aPrefValue);
3616 }
3617 
3618 nsresult sbBaseDevice::GetLibraryPreference(const nsAString& aLibraryPrefBase,
3619  const nsAString& aLibraryPrefName,
3620  nsIVariant** aPrefValue)
3621 {
3622  // Get the full preference name.
3623  nsAutoString prefName(aLibraryPrefBase);
3624  prefName.Append(aLibraryPrefName);
3625 
3626  return GetPreference(prefName, aPrefValue);
3627 }
3628 
3630  (sbIDeviceLibrary* aLibrary,
3631  const nsAString& aLibraryPrefName,
3632  nsIVariant* aPrefValue)
3633 {
3634  nsresult rv;
3635 
3636  // Operate under the preference lock.
3637  nsAutoLock preferenceLock(mPreferenceLock);
3638 
3639  // Get the library pref base.
3640  nsAutoString prefBase;
3641  rv = GetLibraryPreferenceBase(aLibrary, prefBase);
3642  NS_ENSURE_SUCCESS(rv, rv);
3643 
3644  // If no preference name is specified, read and apply all library preferences.
3645  PRBool applyAll = PR_FALSE;
3646  if (aLibraryPrefName.IsEmpty())
3647  applyAll = PR_TRUE;
3648 
3649  // Apply music limit preference.
3650  if (applyAll ||
3651  aLibraryPrefName.EqualsLiteral("music_limit_percent") ||
3652  aLibraryPrefName.EqualsLiteral("use_music_limit_percent"))
3653  {
3654  // First ensure that the music limit percentage pref is enabled.
3655  PRBool shouldLimitMusicSpace = PR_FALSE;
3656  rv = GetShouldLimitMusicSpace(prefBase, &shouldLimitMusicSpace);
3657  if (NS_SUCCEEDED(rv) && shouldLimitMusicSpace) {
3658  PRUint32 musicLimitPercent = 100;
3659  rv = GetMusicLimitSpacePercent(prefBase, &musicLimitPercent);
3660  if (NS_SUCCEEDED(rv)) {
3661  // Finally, apply the preference value.
3662  mMusicLimitPercent = musicLimitPercent;
3663  }
3664  }
3665  else {
3666  // Music space limiting is disabled, set the limit percent to 100%.
3667  mMusicLimitPercent = 100;
3668  }
3669  }
3670 
3671  return ApplyLibraryOrganizePreference(aLibrary,
3672  aLibraryPrefName,
3673  prefBase,
3674  aPrefValue);
3675 }
3676 
3678  (sbIDeviceLibrary* aLibrary,
3679  const nsAString& aLibraryPrefName,
3680  const nsAString& aLibraryPrefBase,
3681  nsIVariant* aPrefValue)
3682 {
3683  nsresult rv;
3684  PRBool applyAll = aLibraryPrefName.IsEmpty();
3685 
3686  if (!applyAll && !StringBeginsWith(aLibraryPrefName,
3687  NS_LITERAL_STRING(PREF_ORGANIZE_PREFIX)))
3688  {
3689  return NS_OK;
3690  }
3691 
3692  nsString prefBase(aLibraryPrefBase);
3693  if (prefBase.IsEmpty()) {
3694  // Get the library pref base.
3695  rv = GetLibraryPreferenceBase(aLibrary, prefBase);
3696  NS_ENSURE_SUCCESS(rv, rv);
3697  }
3698 
3699  nsString guidString;
3700  rv = aLibrary->GetGuid(guidString);
3701  NS_ENSURE_SUCCESS(rv, rv);
3702  nsID libraryGuid;
3703  PRBool success =
3704  libraryGuid.Parse(NS_LossyConvertUTF16toASCII(guidString).get());
3705  NS_ENSURE_TRUE(success, NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA);
3706 
3707  nsAutoPtr<OrganizeData> libraryDataReleaser;
3708  OrganizeData* libraryData;
3709  PRBool found = mOrganizeLibraryPrefs.Get(libraryGuid, &libraryData);
3710  if (!found) {
3711  libraryData = new OrganizeData;
3712  libraryDataReleaser = libraryData;
3713  }
3714  NS_ENSURE_TRUE(libraryData, NS_ERROR_OUT_OF_MEMORY);
3715 
3716  // Get the preference value.
3717  nsCOMPtr<nsIVariant> prefValue = aPrefValue;
3718 
3719  if (applyAll ||
3720  aLibraryPrefName.EqualsLiteral(PREF_ORGANIZE_ENABLED))
3721  {
3722  if (applyAll || !prefValue) {
3723  rv = GetLibraryPreference(prefBase,
3724  NS_LITERAL_STRING(PREF_ORGANIZE_ENABLED),
3725  getter_AddRefs(prefValue));
3726  if (NS_FAILED(rv))
3727  prefValue = nsnull;
3728  }
3729  if (prefValue) {
3730  PRUint16 dataType;
3731  rv = prefValue->GetDataType(&dataType);
3732  if (NS_SUCCEEDED(rv) && dataType == nsIDataType::VTYPE_BOOL) {
3733  rv = prefValue->GetAsBool(&libraryData->organizeEnabled);
3734  NS_ENSURE_SUCCESS(rv, rv);
3735  }
3736  }
3737  }
3738  if (applyAll ||
3739  aLibraryPrefName.EqualsLiteral(PREF_ORGANIZE_DIR_FORMAT))
3740  {
3741  if (applyAll || !prefValue) {
3742  rv = GetLibraryPreference(prefBase,
3743  NS_LITERAL_STRING(PREF_ORGANIZE_DIR_FORMAT),
3744  getter_AddRefs(prefValue));
3745  if (NS_FAILED(rv))
3746  prefValue = nsnull;
3747  }
3748  if (prefValue) {
3749  PRUint16 dataType;
3750  rv = prefValue->GetDataType(&dataType);
3751  if (NS_SUCCEEDED(rv) && dataType != nsIDataType::VTYPE_EMPTY) {
3752  rv = prefValue->GetAsACString(libraryData->dirFormat);
3753  NS_ENSURE_SUCCESS(rv, rv);
3754  }
3755  }
3756  }
3757  if (applyAll ||
3758  aLibraryPrefName.EqualsLiteral(PREF_ORGANIZE_FILE_FORMAT))
3759  {
3760  if (applyAll || !prefValue) {
3761  rv = GetLibraryPreference(prefBase,
3762  NS_LITERAL_STRING(PREF_ORGANIZE_FILE_FORMAT),
3763  getter_AddRefs(prefValue));
3764  if (NS_FAILED(rv))
3765  prefValue = nsnull;
3766  }
3767  if (prefValue) {
3768  PRUint16 dataType;
3769  rv = prefValue->GetDataType(&dataType);
3770  if (NS_SUCCEEDED(rv) && dataType != nsIDataType::VTYPE_EMPTY) {
3771  rv = prefValue->GetAsACString(libraryData->fileFormat);
3772  NS_ENSURE_SUCCESS(rv, rv);
3773  }
3774  }
3775  }
3776 
3777  if (!found) {
3778  success = mOrganizeLibraryPrefs.Put(libraryGuid, libraryData);
3779  NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
3780  libraryDataReleaser.forget();
3781  }
3782 
3783  return NS_OK;
3784 }
3785 
3787  (const nsAString& aPrefName,
3788  nsAString& aLibraryPrefName)
3789 {
3790  nsresult rv;
3791 
3792  // Get the preference library preference base.
3793  nsAutoString libraryPrefBase;
3794  rv = GetPreferenceLibrary(aPrefName, nsnull, libraryPrefBase);
3795  NS_ENSURE_SUCCESS(rv, rv);
3796 
3797  return GetLibraryPreferenceName(aPrefName, libraryPrefBase, aLibraryPrefName);
3798 }
3799 
3801  (const nsAString& aPrefName,
3802  const nsAString& aLibraryPrefBase,
3803  nsAString& aLibraryPrefName)
3804 {
3805  // Validate pref name.
3806  NS_ENSURE_TRUE(StringBeginsWith(aPrefName, aLibraryPrefBase),
3807  NS_ERROR_ILLEGAL_VALUE);
3808 
3809  // Extract the library preference name.
3810  aLibraryPrefName.Assign(Substring(aPrefName, aLibraryPrefBase.Length()));
3811 
3812  return NS_OK;
3813 }
3814 
3816  nsAString& aPrefBase)
3817 {
3818  // Validate arguments.
3819  NS_ENSURE_ARG_POINTER(aLibrary);
3820 
3821  // Function variables.
3822  nsresult rv;
3823 
3824  // Get the library info.
3825  nsAutoString guid;
3826  rv = aLibrary->GetGuid(guid);
3827  NS_ENSURE_SUCCESS(rv, rv);
3828 
3829  // Produce the library preference base.
3830  aPrefBase.Assign(NS_LITERAL_STRING(PREF_DEVICE_LIBRARY_BASE));
3831  aPrefBase.Append(guid);
3832  aPrefBase.AppendLiteral(".");
3833 
3834  return NS_OK;
3835 }
3836 
3837 nsresult
3838 sbBaseDevice::GetCapabilitiesPreference(nsIVariant** aCapabilities)
3839 {
3840  NS_ENSURE_ARG_POINTER(aCapabilities);
3841 
3842  nsresult rv;
3843 
3844  // Get the device settings document.
3845  nsCOMPtr<nsIDOMDocument> domDocument;
3846  rv = GetDeviceSettingsDocument(getter_AddRefs(domDocument));
3847  NS_ENSURE_SUCCESS(rv, rv);
3848 
3849  // Read the device capabilities from the device settings document.
3850  if (domDocument) {
3851  nsCOMPtr<sbIDeviceCapabilities> deviceCapabilities;
3853  (getter_AddRefs(deviceCapabilities),
3854  domDocument,
3855  this);
3856  NS_ENSURE_SUCCESS(rv, rv);
3857 
3858  // Return any device capabilities from the device settings document.
3859  if (deviceCapabilities) {
3860  sbNewVariant capabilitiesVariant(deviceCapabilities);
3861  NS_ENSURE_TRUE(capabilitiesVariant.get(), NS_ERROR_FAILURE);
3862  NS_ADDREF(*aCapabilities = capabilitiesVariant.get());
3863  return NS_OK;
3864  }
3865  }
3866 
3867  // Return no capabilities.
3868  sbNewVariant capabilitiesVariant;
3869  NS_ENSURE_TRUE(capabilitiesVariant.get(), NS_ERROR_FAILURE);
3870  NS_ADDREF(*aCapabilities = capabilitiesVariant.get());
3871 
3872  return NS_OK;
3873 }
3874 
3875 nsresult sbBaseDevice::GetLocalDeviceDir(nsIFile** aLocalDeviceDir)
3876 {
3877  NS_ENSURE_ARG_POINTER(aLocalDeviceDir);
3878  PRBool exists;
3879  nsresult rv;
3880 
3881  // Get the root of all local device directories, creating it if needed.
3882  nsCOMPtr<nsIFile> localDeviceDir;
3883  rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
3884  getter_AddRefs(localDeviceDir));
3885  NS_ENSURE_SUCCESS(rv, rv);
3886  rv = localDeviceDir->Append(NS_LITERAL_STRING("devices"));
3887  NS_ENSURE_SUCCESS(rv, rv);
3888  rv = localDeviceDir->Exists(&exists);
3889  NS_ENSURE_SUCCESS(rv, rv);
3890  if (!exists) {
3891  rv = localDeviceDir->Create(nsIFile::DIRECTORY_TYPE,
3893  NS_ENSURE_SUCCESS(rv, rv);
3894  }
3895 
3896  // get id of this device
3897  nsID* id;
3898  rv = GetId(&id);
3899  NS_ENSURE_SUCCESS(rv, rv);
3900 
3901  // get that as a string
3902  char idString[NSID_LENGTH];
3903  id->ToProvidedString(idString);
3904  NS_Free(id);
3905 
3906  // Produce this device's sub directory name.
3907  nsAutoString deviceSubDirName;
3908  deviceSubDirName.Assign(NS_LITERAL_STRING("device"));
3909  deviceSubDirName.Append(NS_ConvertUTF8toUTF16(idString + 1, NSID_LENGTH - 3));
3910 
3911  // Remove any illegal characters.
3912  PRUnichar *begin, *end;
3913  for (deviceSubDirName.BeginWriting(&begin, &end); begin < end; ++begin) {
3914  if (*begin & (~0x7F)) {
3915  *begin = PRUnichar('_');
3916  }
3917  }
3918  deviceSubDirName.StripChars(FILE_ILLEGAL_CHARACTERS
3919  FILE_PATH_SEPARATOR
3920  " _-{}");
3921 
3922  // Get this device's local directory, creating it if needed.
3923  rv = localDeviceDir->Append(deviceSubDirName);
3924  NS_ENSURE_SUCCESS(rv, rv);
3925  rv = localDeviceDir->Exists(&exists);
3926  NS_ENSURE_SUCCESS(rv, rv);
3927  if (!exists) {
3928  rv = localDeviceDir->Create(nsIFile::DIRECTORY_TYPE,
3930  #if PR_LOGGING
3931  if (NS_FAILED(rv)) {
3932  nsString path;
3933  nsresult rv2 = localDeviceDir->GetPath(path);
3934  if (NS_FAILED(rv2)) path.AssignLiteral("<unknown>");
3935  TRACE(("%s[%p]: Failed to create device directory %s",
3936  __FUNCTION__,
3937  this,
3938  NS_ConvertUTF16toUTF8(path).BeginReading()));
3939  }
3940  #endif /* PR_LOGGING */
3941  NS_ENSURE_SUCCESS(rv, rv);
3942  }
3943 
3944  // Return results.
3945  localDeviceDir.forget(aLocalDeviceDir);
3946 
3947  return NS_OK;
3948 }
3949 
3950 //------------------------------------------------------------------------------
3951 //
3952 // Device sync services.
3953 //
3954 //------------------------------------------------------------------------------
3955 
3956 nsresult
3958 {
3959  nsresult rv;
3960 
3961  nsCOMPtr<nsIWritablePropertyBag2> syncCompleteParams =
3962  do_CreateInstance(NS_HASH_PROPERTY_BAG_CONTRACTID, &rv);
3963  NS_ENSURE_SUCCESS(rv, rv);
3964 
3965  nsCOMPtr<nsISupportsPRUint64> timestamp =
3966  do_CreateInstance(NS_SUPPORTS_PRUINT64_CONTRACTID, &rv);
3967  NS_ENSURE_SUCCESS(rv, rv);
3968 
3969  PRUint64 now = PR_Now();
3970  rv = timestamp->SetData(now);
3971  NS_ENSURE_SUCCESS(rv, rv);
3972 
3973  rv = syncCompleteParams->SetPropertyAsInterface(NS_LITERAL_STRING("data"),
3974  timestamp);
3975  NS_ENSURE_SUCCESS(rv, rv);
3976 
3977  rv = syncCompleteParams->SetPropertyAsInterface(NS_LITERAL_STRING("list"),
3978  NS_ISUPPORTS_CAST(sbIMediaList*, mDefaultLibrary));
3979  NS_ENSURE_SUCCESS(rv, rv);
3980 
3982  syncCompleteParams);
3983  NS_ENSURE_SUCCESS(rv, rv);
3984 
3985  return NS_OK;
3986 }
3987 
3988 nsresult
3990 {
3991  // Validate arguments.
3992  NS_ENSURE_ARG_POINTER(aRequest);
3993 
3994  // Function variables.
3995  nsresult rv;
3996 
3998  NS_ENSURE_SUCCESS(rv, rv);
3999 
4000  // Produce the sync change set.
4001  nsCOMPtr<sbILibraryChangeset> exportChangeset;
4002  nsCOMPtr<sbILibraryChangeset> importChangeset;
4003  rv = SyncProduceChangeset(aRequest,
4004  getter_AddRefs(exportChangeset),
4005  getter_AddRefs(importChangeset));
4006  NS_ENSURE_SUCCESS(rv, rv);
4007 
4008  if (IsRequestAborted()) {
4009  return NS_ERROR_ABORT;
4010  }
4011 
4012  // Setup the device state for sync'ing
4013  rv = SetState(STATE_SYNCING);
4014  NS_ENSURE_SUCCESS(rv, rv);
4015 
4016  nsCOMPtr<sbIDeviceStatus> status;
4017  rv = GetCurrentStatus(getter_AddRefs(status));
4018  NS_ENSURE_SUCCESS(rv, rv);
4019 
4020  rv = status->SetCurrentState(STATE_SYNCING);
4021  NS_ENSURE_SUCCESS(rv, rv);
4022 
4023  rv = status->SetCurrentSubState(STATE_SYNCING);
4024  NS_ENSURE_SUCCESS(rv, rv);
4025 
4026  // Reset the sync type for the upcoming sync
4028 
4029  nsCOMPtr<sbIDeviceLibrary> devLib = do_QueryInterface(aRequest->list, &rv);
4030  NS_ENSURE_SUCCESS(rv, rv);
4031 
4032  rv = ExportToDevice(devLib, exportChangeset);
4033  NS_ENSURE_SUCCESS(rv, rv);
4034 
4035  nsCOMPtr<sbILibrary> mainLib;
4036  rv = GetMainLibrary(getter_AddRefs(mainLib));
4037  NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to get the main library");
4038 
4039  rv = ImportFromDevice(mainLib, importChangeset);
4040  NS_ENSURE_SUCCESS(rv, rv);
4041 
4042  rv = SendSyncCompleteRequest();
4043  NS_ENSURE_SUCCESS(rv, rv);
4044 
4045  // Update the sync types (audio/video/image) after queuing requests
4046  aRequest->itemType = mSyncType;
4047 
4048  nsCOMPtr<sbIDeviceCapabilities> capabilities;
4049  rv = GetCapabilities(getter_AddRefs(capabilities));
4050  NS_ENSURE_SUCCESS(rv, rv);
4051 
4052  // Check if the device supports images
4053  PRBool isSupported;
4054  rv = capabilities->SupportsContent(
4057  &isSupported);
4058  NS_ENSURE_SUCCESS(rv, rv);
4059 
4060  // Check if our settings have imagesync enabled
4061  nsCOMPtr<sbIDeviceLibrarySyncSettings> syncSettings;
4062  rv = devLib->GetSyncSettings(getter_AddRefs(syncSettings));
4063  NS_ENSURE_SUCCESS(rv, rv);
4064 
4065  nsCOMPtr<sbIDeviceLibraryMediaSyncSettings> imageSyncSettings;
4066  rv = syncSettings->GetMediaSettings(sbIDeviceLibrary::MEDIATYPE_IMAGE,
4067  getter_AddRefs(imageSyncSettings));
4068  NS_ENSURE_SUCCESS(rv, rv);
4069 
4070  PRUint32 imageMgmtType;
4071  rv = imageSyncSettings->GetMgmtType(&imageMgmtType);
4072  NS_ENSURE_SUCCESS(rv, rv);
4073 
4074  PRBool imageSyncEnabled = (imageMgmtType !=
4076 
4077  // Do not proceed to image sync request submission if image is not supported
4078  // or not enabled at all.
4079  if (!isSupported || !imageSyncEnabled) {
4080  return NS_OK;
4081  }
4082 
4083  // If the user has enabled image sync, trigger it after the audio/video sync
4084  // If the user has disabled image sync, trigger it to do the removal.
4085  nsCOMPtr<nsIWritablePropertyBag2> requestParams =
4086  do_CreateInstance(NS_HASH_PROPERTY_BAG_CONTRACTID, &rv);
4087  NS_ENSURE_SUCCESS(rv, rv);
4088 
4089  rv = requestParams->SetPropertyAsInterface
4090  (NS_LITERAL_STRING("list"),
4091  NS_ISUPPORTS_CAST(sbIMediaList*, mDefaultLibrary));
4092  NS_ENSURE_SUCCESS(rv, rv);
4093  rv = SubmitRequest(sbIDevice::REQUEST_IMAGESYNC, requestParams);
4094  NS_ENSURE_SUCCESS(rv, rv);
4095 
4096  return NS_OK;
4097 }
4098 
4099 nsresult
4101 {
4102  NS_ENSURE_ARG_POINTER(aRequest);
4103  nsresult rv;
4104 
4105  if (IsRequestAborted()) {
4106  return NS_ERROR_ABORT;
4107  }
4108 
4109  nsCOMPtr<nsISupportsPRUint64> timestamp =
4110  do_QueryInterface(aRequest->data, &rv);
4111  NS_ENSURE_SUCCESS(rv, rv);
4112 
4113  PRUint64 ts = 0;
4114  rv = timestamp->GetData(&ts);
4115  NS_ENSURE_SUCCESS(rv, rv);
4116 
4117  // This list is actually the device library.
4118  nsCOMPtr<sbIMediaList> list = aRequest->list;
4119  NS_ENSURE_TRUE(list, NS_ERROR_FAILURE);
4120 
4121  sbAutoString timestampStr((PRUint64)(ts / PR_MSEC_PER_SEC));
4122  rv = list->SetProperty(NS_LITERAL_STRING(SB_PROPERTY_LAST_SYNC_TIME),
4123  timestampStr);
4124  NS_ENSURE_SUCCESS(rv, rv);
4125 
4126  return NS_OK;
4127 }
4128 
4129 namespace
4130 {
4131  nsresult GetSourceLibraryForChangeset(sbILibraryChangeset * aChangeset,
4132  sbILibrary ** aLibrary)
4133  {
4134  NS_ASSERTION(aChangeset, "aChangeset must not be null");
4135  NS_ASSERTION(aLibrary, "aLibrary must not be null");
4136 
4137  nsresult rv;
4138 
4139  nsCOMPtr<nsIArray> changes;
4140  rv = aChangeset->GetChanges(getter_AddRefs(changes));
4141  NS_ENSURE_SUCCESS(rv, rv);
4142 
4143  PRUint32 length;
4144  rv = changes->GetLength(&length);
4145  NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && length > 0, NS_ERROR_NOT_AVAILABLE);
4146 
4147  nsCOMPtr<sbILibraryChange> change = do_QueryElementAt(changes, 0, &rv);
4148  NS_ENSURE_SUCCESS(rv, rv);
4149 
4150  nsCOMPtr<sbIMediaItem> item;
4151  rv = change->GetSourceItem(getter_AddRefs(item));
4152  NS_ENSURE_SUCCESS(rv, rv);
4153 
4154  rv = item->GetLibrary(aLibrary);
4155  NS_ENSURE_SUCCESS(rv, rv);
4156 
4157  return NS_OK;
4158  }
4159 }
4160 
4161 nsresult
4163  (sbILibrary* aSrcLib,
4164  sbIDeviceLibrary* aDstLib,
4165  PRInt64 aAvailableSpace)
4166 {
4167  // Validate arguments.
4168  NS_ENSURE_ARG_POINTER(aSrcLib);
4169  NS_ENSURE_ARG_POINTER(aDstLib);
4170 
4171  // Function variables.
4172  nsresult rv;
4173 
4174  // Clear sync playlist to prevent syncing while creating the sync playlist.
4175  nsCOMPtr<sbIDeviceLibrarySyncSettings> syncSettings;
4176  rv = aDstLib->GetSyncSettings(getter_AddRefs(syncSettings));
4177  NS_ENSURE_SUCCESS(rv, rv);
4178 
4179  nsCOMPtr<sbIDeviceLibraryMediaSyncSettings> mediaSyncSettings;
4180  for (PRUint32 i = 0; i < sbIDeviceLibrary::MEDIATYPE_COUNT; ++i) {
4181  // Skip image type since we don't support it right now.
4183  continue;
4184 
4185  rv = syncSettings->GetMediaSettings(i, getter_AddRefs(mediaSyncSettings));
4186  NS_ENSURE_SUCCESS(rv, rv);
4187 
4188  rv = mediaSyncSettings->ClearSelectedPlaylists();
4189  NS_ENSURE_SUCCESS(rv, rv);
4190 
4191  rv = mediaSyncSettings->SetMgmtType(
4193  NS_ENSURE_SUCCESS(rv, rv);
4194  }
4195 
4196  rv = aDstLib->SetSyncSettings(syncSettings);
4197  NS_ENSURE_SUCCESS(rv, rv);
4198 
4199  // Check for abort.
4200  NS_ENSURE_FALSE(IsRequestAborted(), NS_ERROR_ABORT);
4201 
4202  // Create a new source sync media list.
4203  nsCOMPtr<sbIMediaList> syncMediaList;
4204  rv = SyncCreateSyncMediaList(aSrcLib,
4205  aDstLib,
4206  aAvailableSpace,
4207  getter_AddRefs(syncMediaList));
4208  if (rv == NS_ERROR_ABORT)
4209  return rv;
4210  NS_ENSURE_SUCCESS(rv, rv);
4211 
4212  // Check for abort.
4213  NS_ENSURE_FALSE(IsRequestAborted(), NS_ERROR_ABORT);
4214 
4215  // Sync to the sync media list.
4216  rv = SyncToMediaList(aDstLib, syncMediaList);
4217  NS_ENSURE_SUCCESS(rv, rv);
4218 
4219  return NS_OK;
4220 }
4221 
4222 nsresult
4224  sbIDeviceLibrary* aDstLib,
4225  PRInt64 aAvailableSpace,
4226  sbIMediaList** aSyncMediaList)
4227 {
4228  // Validate arguments.
4229  NS_ENSURE_ARG_POINTER(aSrcLib);
4230  NS_ENSURE_ARG_POINTER(aSyncMediaList);
4231 
4232  // Function variables.
4233  nsresult rv;
4234 
4235  nsCOMPtr<sbIMutablePropertyArray> propertyArray =
4236  do_CreateInstance(SB_MUTABLEPROPERTYARRAY_CONTRACTID, &rv);
4237  NS_ENSURE_SUCCESS(rv, rv);
4238 
4239  nsCOMPtr<sbIDeviceLibrary> devLib;
4240  rv = GetDefaultLibrary(getter_AddRefs(devLib));
4241  NS_ENSURE_SUCCESS(rv, rv);
4242  nsString guid;
4243  rv = devLib->GetGuid(guid);
4244  NS_ENSURE_SUCCESS(rv, rv);
4245 
4246  rv = propertyArray->AppendProperty(
4247  NS_LITERAL_STRING(SB_PROPERTY_DEVICE_LIBRARY_GUID),
4248  guid);
4249  NS_ENSURE_SUCCESS(rv, rv);
4250  rv = propertyArray->AppendProperty(
4251  NS_LITERAL_STRING(SB_PROPERTY_LISTTYPE),
4252  NS_LITERAL_STRING("2"));
4253  NS_ENSURE_SUCCESS(rv, rv);
4254  rv = propertyArray->AppendProperty(
4255  NS_LITERAL_STRING(SB_PROPERTY_ISLIST),
4256  NS_LITERAL_STRING("1"));
4257  NS_ENSURE_SUCCESS(rv, rv);
4258 
4259  nsCOMPtr<nsIArray> randomMediaList;
4260  rv = aSrcLib->GetItemsByProperties(propertyArray,
4261  getter_AddRefs(randomMediaList));
4262  if (rv != NS_ERROR_NOT_AVAILABLE) {
4263  NS_ENSURE_SUCCESS(rv, rv);
4264  }
4265 
4266  PRUint32 length;
4267  rv = randomMediaList->GetLength(&length);
4268  NS_ENSURE_SUCCESS(rv, rv);
4269 
4270  NS_WARN_IF_FALSE(length < 2, "Multiple random sync'ing playlists");
4271  nsCOMPtr<sbIMediaList> syncMediaList;
4272  if (length > 0) {
4273  rv = randomMediaList->QueryElementAt(0,
4274  NS_GET_IID(sbIMediaList),
4275  getter_AddRefs(syncMediaList));
4276  NS_ENSURE_SUCCESS(rv, rv);
4277 
4278  // Calculate the smart list total item size. Return the list if the size
4279  // can fit on the device. Create a new one if not.
4280  PRInt64 totalSyncSize = 0;
4281  PRUint32 itemCount;
4282  rv = syncMediaList->GetLength(&itemCount);
4283  NS_ENSURE_SUCCESS(rv, rv);
4284  for (PRUint32 i = 0; i < itemCount; ++i) {
4285  // Get the sync item.
4286  nsCOMPtr<sbIMediaItem> mediaItem;
4287  rv = syncMediaList->GetItemByIndex(i, getter_AddRefs(mediaItem));
4288  NS_ENSURE_SUCCESS(rv, rv);
4289 
4290  // Media List inside of media list?
4291  nsCOMPtr<sbIMediaList> mediaList = do_QueryInterface(mediaItem, &rv);
4292  if (NS_SUCCEEDED(rv))
4293  continue;
4294 
4295  // Get the item write length adding in the per track overhead. Assume a
4296  // length of 0 on error.
4297  PRUint64 writeLength;
4299  mediaItem,
4300  &writeLength);
4301  if (NS_FAILED(rv))
4302  writeLength = 0;
4303  writeLength += mPerTrackOverhead;
4304 
4305  totalSyncSize += writeLength;
4306  }
4307 
4308  if (totalSyncSize <= aAvailableSpace) {
4309  // smart playlist found.
4310  syncMediaList.forget(aSyncMediaList);
4311  return NS_OK;
4312  }
4313  else {
4314  // If not enough space is available to hold the existing smart list
4315  // content, ask the user what action to take. If the user does not abort
4316  // the operation, create another smart list and sync to it that will fit
4317  // in the available space. Otherwise, set the management type to manual
4318  // and return.
4319  PRBool abort;
4321  aDstLib,
4322  totalSyncSize,
4323  aAvailableSpace,
4324  &abort);
4325  NS_ENSURE_SUCCESS(rv, rv);
4326  if (abort)
4327  return NS_ERROR_ABORT;
4328 
4329  // Reset the library guid property to ignore for next over-capacity sync.
4330  // And create another smart list.
4331  rv = syncMediaList->SetProperty(
4332  NS_LITERAL_STRING(SB_PROPERTY_DEVICE_LIBRARY_GUID),
4333  NS_LITERAL_STRING(""));
4334  }
4335  }
4336 
4337  // Create a new source sync smart media list.
4338  nsCOMPtr<nsIThread> target;
4339  rv = NS_GetMainThread(getter_AddRefs(target));
4340  NS_ENSURE_SUCCESS(rv, rv);
4341 
4342  nsCOMPtr<sbILibrary> proxiedLibrary;
4343  rv = do_GetProxyForObject(target,
4344  aSrcLib,
4345  NS_PROXY_SYNC | NS_PROXY_ALWAYS,
4346  getter_AddRefs(proxiedLibrary));
4347  NS_ENSURE_SUCCESS(rv, rv);
4348 
4349  rv = proxiedLibrary->CreateMediaList(NS_LITERAL_STRING("smart"),
4350  propertyArray,
4351  getter_AddRefs(syncMediaList));
4352  NS_ENSURE_SUCCESS(rv, rv);
4353 
4354  // get the device name
4355  nsString deviceName;
4356  rv = GetName(deviceName);
4357  NS_ENSURE_SUCCESS(rv, rv);
4358 
4359  // Produce the sync media list name.
4360  nsString listName;
4361  nsTArray<nsString> listNameParams;
4362  listNameParams.AppendElement(deviceName);
4363  rv = SBGetLocalizedFormattedString(listName,
4364  NS_LITERAL_STRING(RANDOM_LISTNAME),
4365  listNameParams,
4366  NS_LITERAL_STRING("Autofill"),
4367  nsnull);
4368  NS_ENSURE_SUCCESS(rv, rv);
4369 
4370  nsString uniqueName;
4372  listName,
4373  uniqueName);
4374  NS_ENSURE_SUCCESS(rv, rv);
4375 
4376  rv = syncMediaList->SetName(uniqueName);
4377  NS_ENSURE_SUCCESS(rv, rv);
4378 
4379  nsCOMPtr<sbILocalDatabaseSmartMediaList> randomList =
4380  do_QueryInterface(syncMediaList, &rv);
4381  NS_ENSURE_SUCCESS(rv, rv);
4382 
4383  // Set the smart list condition to be "media type is audio" with limited
4384  // storage capacity and select by random.
4385  nsCOMPtr<sbIPropertyOperator> equal;
4386  rv = sbLibraryUtils::GetEqualOperator(getter_AddRefs(equal));
4387  NS_ENSURE_SUCCESS(rv, rv);
4388 
4389  nsCOMPtr<sbILocalDatabaseSmartMediaListCondition> condition;
4390  rv = randomList->AppendCondition(NS_LITERAL_STRING(SB_PROPERTY_CONTENTTYPE),
4391  equal,
4392  NS_LITERAL_STRING("audio"),
4393  nsString(),
4394  nsString(),
4395  getter_AddRefs(condition));
4396  NS_ENSURE_SUCCESS(rv, rv);
4397 
4398  rv = randomList->SetMatchType(sbILocalDatabaseSmartMediaList::MATCH_TYPE_ALL);
4399  NS_ENSURE_SUCCESS(rv, rv);
4400 
4401  rv = randomList->SetLimitType(
4403  NS_ENSURE_SUCCESS(rv, rv);
4404 
4405  PRUint64 syncSpace = aAvailableSpace * SYNC_PLAYLIST_AVAILABLE_PCT / 100;
4406 
4407  nsString uiLimitType;
4408  uiLimitType.AssignLiteral("GB");
4409  syncSpace = syncSpace / BYTES_PER_10MB * BYTES_PER_10MB;
4410 
4411  rv = randomList->SetProperty(NS_LITERAL_STRING(SB_PROPERTY_UILIMITTYPE),
4412  uiLimitType);
4413  NS_ENSURE_SUCCESS(rv, rv);
4414 
4415  rv = randomList->SetLimit(syncSpace);
4416  NS_ENSURE_SUCCESS(rv, rv);
4417 
4418  rv = randomList->SetRandomSelection(PR_TRUE);
4419  NS_ENSURE_SUCCESS(rv, rv);
4420 
4421  // Rebuild after the conditions are set.
4422  rv = randomList->Rebuild();
4423  NS_ENSURE_SUCCESS(rv, rv);
4424 
4425  // Return results.
4426  syncMediaList.forget(aSyncMediaList);
4427 
4428  return NS_OK;
4429 }
4430 
4431 nsresult
4433  sbIMediaList* aMediaList)
4434 {
4435  // Validate arguments.
4436  NS_ENSURE_ARG_POINTER(aDstLib);
4437  NS_ENSURE_ARG_POINTER(aMediaList);
4438 
4439  // Function variables.
4440  nsresult rv;
4441 
4442  PRUint16 contentType;
4443  rv = aMediaList->GetListContentType(&contentType);
4444  NS_ENSURE_SUCCESS(rv, rv);
4445  NS_ENSURE_SUCCESS(contentType > 0, NS_ERROR_FAILURE);
4446 
4447  nsCOMPtr<sbIDeviceLibrarySyncSettings> syncSettings;
4448  rv = aDstLib->GetSyncSettings(getter_AddRefs(syncSettings));
4449  NS_ENSURE_SUCCESS(rv, rv);
4450 
4451  nsCOMPtr<sbIDeviceLibraryMediaSyncSettings> audioMediaSyncSettings;
4452  rv = syncSettings->GetMediaSettings(sbIDeviceLibrary::MEDIATYPE_AUDIO,
4453  getter_AddRefs(audioMediaSyncSettings));
4454  NS_ENSURE_SUCCESS(rv, rv);
4455 
4456  nsCOMPtr<sbIDeviceLibraryMediaSyncSettings> videoMediaSyncSettings;
4457  rv = syncSettings->GetMediaSettings(sbIDeviceLibrary::MEDIATYPE_VIDEO,
4458  getter_AddRefs(videoMediaSyncSettings));
4459  NS_ENSURE_SUCCESS(rv, rv);
4460 
4461  nsCOMPtr<nsIMutableArray> syncList =
4462  do_CreateInstance("@songbirdnest.com/moz/xpcom/threadsafe-array;1", &rv);
4463  NS_ENSURE_SUCCESS(rv, rv);
4464 
4465  rv = syncList->AppendElement(aMediaList, PR_FALSE);
4466  NS_ENSURE_SUCCESS(rv, rv);
4467  // Set to sync to the sync media list.
4468  if (contentType & sbIMediaList::CONTENTTYPE_AUDIO) {
4469  rv = audioMediaSyncSettings->SetSelectedPlaylists(syncList);
4470  NS_ENSURE_SUCCESS(rv, rv);
4471  rv = videoMediaSyncSettings->ClearSelectedPlaylists();
4472  NS_ENSURE_SUCCESS(rv, rv);
4473  }
4474  if (contentType & sbIMediaList::CONTENTTYPE_VIDEO) {
4475  rv = videoMediaSyncSettings->SetSelectedPlaylists(syncList);
4476  NS_ENSURE_SUCCESS(rv, rv);
4477  rv = audioMediaSyncSettings->ClearSelectedPlaylists();
4478  NS_ENSURE_SUCCESS(rv, rv);
4479  }
4480 
4481  rv = audioMediaSyncSettings->SetMgmtType(
4483  NS_ENSURE_SUCCESS(rv, rv);
4484 
4485  PRUint32 mgmtType;
4486  if (contentType == sbIMediaList::CONTENTTYPE_AUDIO)
4488  else
4490  rv = videoMediaSyncSettings->SetMgmtType(mgmtType);
4491  NS_ENSURE_SUCCESS(rv, rv);
4492 
4493  rv = aDstLib->SetSyncSettings(syncSettings);
4494  NS_ENSURE_SUCCESS(rv, rv);
4495 
4496  return NS_OK;
4497 }
4498 
4500  sbILibraryChange * aChange)
4501 {
4502  NS_ASSERTION(aChange, "aChange must not be null");
4503 
4504  nsresult rv;
4505 
4506  nsCOMPtr<sbIMediaItem> source;
4507  rv = aChange->GetSourceItem(getter_AddRefs(source));
4508  NS_ENSURE_SUCCESS(rv, rv);
4509 
4510  // Get the item write length adding in the per track overhead. Assume a
4511  // length of 0 on error.
4512  PRUint64 writeLength;
4513  rv = sbDeviceUtils::GetDeviceWriteLength(aDestLibrary,
4514  source,
4515  &writeLength);
4516  if (NS_FAILED(rv))
4517  writeLength = 0;
4518  writeLength += mPerTrackOverhead;
4519 
4520  PRUint32 operation;
4521  rv = aChange->GetOperation(&operation);
4522  NS_ENSURE_SUCCESS(rv, 0);
4523 
4524  switch (operation) {
4525  case sbILibraryChange::ADDED: {
4526  return writeLength;
4527  }
4529  nsCOMPtr<sbIMediaItem> destinationItem;
4530  rv = aChange->GetDestinationItem(getter_AddRefs(destinationItem));
4531  NS_ENSURE_SUCCESS(rv, 0);
4532 
4533  PRInt64 destinationLength;
4534  rv = destinationItem->GetContentLength(&destinationLength);
4535  NS_ENSURE_SUCCESS(rv, writeLength);
4536 
4537  return writeLength - destinationLength;
4538  }
4540  // This won't occur with the current sync behavior
4541  NS_WARNING("sbILibraryChange::DELETED not supported");
4542  break;
4543  }
4544  default: {
4545  NS_WARNING("Unexpected change operation");
4546  break;
4547  }
4548  }
4549  // Ideally we'll never get here unless we get an operation we can't handle
4550  return 0;
4551 }
4552 
4553 nsresult
4555  sbILibraryChangeset* aChangeset,
4556  PRInt64 aAvailableSpace,
4557  PRUint32& aLastChangeThatFit,
4558  PRInt64& aTotalSyncSize)
4559 {
4560  // Validate arguments.
4561  NS_ENSURE_ARG_POINTER(aChangeset);
4562 
4563  // Function variables.
4564  nsresult rv;
4565 
4566  aTotalSyncSize = 0;
4567 
4568  // Fill in the sync item size table and calculate the total sync size.
4569  nsCOMPtr<nsIArray> changes;
4570  rv = aChangeset->GetChanges(getter_AddRefs(changes));
4571  NS_ENSURE_SUCCESS(rv, rv);
4572 
4573  PRUint32 length;
4574  rv = changes->GetLength(&length);
4575  NS_ENSURE_SUCCESS(rv, rv);
4576  for (PRUint32 i = 0; i < length; ++i) {
4577  // Check for abort.
4578  NS_ENSURE_FALSE(IsRequestAborted(), NS_ERROR_ABORT);
4579 
4580  // Get the next sync media item.
4581  nsCOMPtr<sbILibraryChange> change = do_QueryElementAt(changes, i, &rv);
4582  NS_ENSURE_SUCCESS(rv, rv);
4583 
4584  // Don't count lists
4585  // TODO: There probably is some size associated with storing a list at
4586  // sometime we might want to investigate that add some best estimate.
4587  PRBool isList;
4588  rv = change->GetItemIsList(&isList);
4589  NS_ENSURE_SUCCESS(rv, 0);
4590  if (isList) {
4591  continue;
4592  }
4593  // If we've seen this item before don't count it.
4594  nsCOMPtr<sbIMediaItem> mediaItem;
4595  rv = change->GetSourceItem(getter_AddRefs(mediaItem));
4596  NS_ENSURE_SUCCESS(rv, rv);
4597 
4598  nsCOMPtr<nsISupports> supports = do_QueryInterface(mediaItem);
4599  aTotalSyncSize += GetChangeSize(aDestLibrary, change);
4600  if (aTotalSyncSize <= aAvailableSpace) {
4601  aLastChangeThatFit = i;
4602  }
4603  }
4604 
4605 
4606  return NS_OK;
4607 }
4608 
4609 nsresult
4611  PRInt64* aAvailableSpace)
4612 {
4613  // Validate arguments.
4614  NS_ENSURE_ARG_POINTER(aLibrary);
4615  NS_ENSURE_ARG_POINTER(aAvailableSpace);
4616 
4617  // Function variables.
4618  nsresult rv;
4619 
4620  // Get the device properties.
4621  nsCOMPtr<nsIPropertyBag2> deviceProperties;
4622  rv = GetPropertyBag(this, getter_AddRefs(deviceProperties));
4623  NS_ENSURE_SUCCESS(rv, rv);
4624 
4625  // Get the free space.
4626  PRInt64 freeSpace;
4627  nsAutoString freeSpaceStr;
4628  rv = aLibrary->GetProperty(NS_LITERAL_STRING(SB_DEVICE_PROPERTY_FREE_SPACE),
4629  freeSpaceStr);
4630  NS_ENSURE_SUCCESS(rv, rv);
4631  freeSpace = nsString_ToInt64(freeSpaceStr, &rv);
4632  NS_ENSURE_SUCCESS(rv, rv);
4633 
4634  // Get the music used space.
4635  PRInt64 musicUsedSpace;
4636  nsAutoString musicUsedSpaceStr;
4637  rv = aLibrary->GetProperty
4638  (NS_LITERAL_STRING(SB_DEVICE_PROPERTY_MUSIC_USED_SPACE),
4639  musicUsedSpaceStr);
4640  NS_ENSURE_SUCCESS(rv, rv);
4641  musicUsedSpace = nsString_ToInt64(musicUsedSpaceStr, &rv);
4642  NS_ENSURE_SUCCESS(rv, rv);
4643 
4644  // Add track overhead to the music used space.
4645  PRUint32 trackCount;
4646  rv = aLibrary->GetLength(&trackCount);
4647  NS_ENSURE_SUCCESS(rv, rv);
4648  musicUsedSpace += trackCount * mPerTrackOverhead;
4649 
4650  // Determine the total available space for syncing as the free space plus the
4651  // space used for music.
4652  PRInt64 availableSpace = freeSpace + musicUsedSpace;
4653 
4654  // Apply limit to the total space available for music.
4655  PRInt64 musicAvailableSpace;
4656  rv = GetMusicFreeSpace(aLibrary, &musicAvailableSpace);
4657  NS_ENSURE_SUCCESS(rv, rv);
4658  if (availableSpace >= musicAvailableSpace)
4659  availableSpace = musicAvailableSpace;
4660 
4661  // Return results.
4662  *aAvailableSpace = availableSpace;
4663 
4664  return NS_OK;
4665 }
4666 
4667 namespace {
4668 
4669  nsresult GetMediaSettingsValues(sbIDeviceLibrarySyncSettings * aSyncSettings,
4670  PRUint32 aMediaType,
4671  PRUint32 * aMgmtType,
4672  PRBool * aImport,
4673  nsIMutableArray * aSelectedPlaylists)
4674  {
4675  NS_ENSURE_ARG_POINTER(aSyncSettings);
4676  NS_ENSURE_ARG_POINTER(aMgmtType);
4677  NS_ENSURE_ARG_POINTER(aImport);
4678  NS_ENSURE_ARG_POINTER(aSelectedPlaylists);
4679 
4680  nsresult rv;
4681 
4682  nsCOMPtr<sbIDeviceLibraryMediaSyncSettings> settings;
4683  rv = aSyncSettings->GetMediaSettings(aMediaType,
4684  getter_AddRefs(settings));
4685  NS_ENSURE_SUCCESS(rv, rv);
4686 
4687  rv = settings->GetMgmtType(aMgmtType);
4688  NS_ENSURE_SUCCESS(rv, rv);
4689 
4691  nsCOMPtr<nsIArray> playlists;
4692  rv = settings->GetSelectedPlaylists(getter_AddRefs(playlists));
4693  NS_ENSURE_SUCCESS(rv, rv);
4694  rv = sbAppendnsIArray(playlists,
4695  aSelectedPlaylists);
4696  NS_ENSURE_SUCCESS(rv, rv);
4697  }
4698 
4699  rv = settings->GetImport(aImport);
4700  NS_ENSURE_SUCCESS(rv, rv);
4701 
4702  return NS_OK;
4703  }
4704 }
4705 
4706 nsresult
4708  sbILibraryChangeset** aExportChangeset,
4709  sbILibraryChangeset** aImportChangeset)
4710 {
4711  // Validate arguments.
4712  NS_ENSURE_ARG_POINTER(aRequest);
4713  NS_ENSURE_ARG_POINTER(aExportChangeset);
4714  NS_ENSURE_ARG_POINTER(aImportChangeset);
4715 
4716  // Function variables.
4717  nsresult rv;
4718 
4719  // Get the sync source and destination libraries.
4720  nsCOMPtr<sbILibrary> mainLib = do_QueryInterface(aRequest->item, &rv);
4721  NS_ENSURE_SUCCESS(rv, rv);
4722  nsCOMPtr<sbIDeviceLibrary> devLib = do_QueryInterface(aRequest->list, &rv);
4723  NS_ENSURE_SUCCESS(rv, rv);
4724 
4725  nsCOMPtr<sbIDeviceLibrarySyncSettings> syncSettings;
4726  rv = devLib->GetSyncSettings(getter_AddRefs(syncSettings));
4727  NS_ENSURE_SUCCESS(rv, rv);
4728 
4729  nsCOMPtr<nsIMutableArray> selectedPlaylists =
4730  do_CreateInstance("@songbirdnest.com/moz/xpcom/threadsafe-array;1", &rv);
4731 
4732  PRUint32 audioMgmtType;
4733  PRBool audioImport;
4734  rv = GetMediaSettingsValues(syncSettings,
4736  &audioMgmtType,
4737  &audioImport,
4738  selectedPlaylists);
4739  NS_ENSURE_SUCCESS(rv, rv);
4740 
4741  PRUint32 videoMgmtType;
4742  PRBool videoImport;
4743  rv = GetMediaSettingsValues(syncSettings,
4745  &videoMgmtType,
4746  &videoImport,
4747  selectedPlaylists);
4748  NS_ENSURE_SUCCESS(rv, rv);
4749 
4750  // Figure out the sync media types we're interested in
4751  PRUint32 exportAllMediaTypes = 0;
4752  if (audioMgmtType == sbIDeviceLibraryMediaSyncSettings::SYNC_MGMT_ALL) {
4753  exportAllMediaTypes = sbIDeviceLibrarySyncDiff::SYNC_TYPE_AUDIO;
4754  }
4755  if (videoMgmtType == sbIDeviceLibraryMediaSyncSettings::SYNC_MGMT_ALL) {
4756  exportAllMediaTypes |= sbIDeviceLibrarySyncDiff::SYNC_TYPE_VIDEO;
4757  }
4758 
4759  PRUint32 importAllMediaTypes = 0;
4760  if (audioImport)
4761  importAllMediaTypes = sbIDeviceLibrarySyncDiff::SYNC_TYPE_AUDIO;
4762  if (videoImport)
4763  importAllMediaTypes = sbIDeviceLibrarySyncDiff::SYNC_TYPE_VIDEO;
4764 
4765  nsCOMPtr<sbIDeviceLibrarySyncDiff> syncDiff =
4766  do_CreateInstance(SONGBIRD_DEVICELIBRARYSYNCDIFF_CONTRACTID, &rv);
4767 
4768  rv = syncDiff->GenerateSyncLists(exportAllMediaTypes,
4769  importAllMediaTypes,
4770  mainLib,
4771  devLib,
4772  selectedPlaylists,
4773  aExportChangeset,
4774  aImportChangeset);
4775  NS_ENSURE_SUCCESS(rv, rv);
4776 
4777  return NS_OK;
4778 }
4779 
4780 nsresult
4782  nsIArray * aMediaLists)
4783 {
4784  NS_ENSURE_ARG_POINTER(aLibrary);
4785  NS_ENSURE_ARG_POINTER(aMediaLists);
4786 
4787  nsresult rv;
4788 
4789  // Add media lists.
4790  PRUint32 count;
4791  rv = aMediaLists->GetLength(&count);
4792  NS_ENSURE_SUCCESS(rv, rv);
4793 
4794  for (PRUint32 i = 0; i < count; i++) {
4795  if (IsRequestAborted()) {
4796  return NS_ERROR_ABORT;
4797  }
4798  nsCOMPtr<sbILibraryChange> change =
4799  do_QueryElementAt(aMediaLists, i, &rv);
4800 
4801  nsCOMPtr<sbIMediaItem> libMediaItem;
4802  rv = change->GetSourceItem(getter_AddRefs(libMediaItem));
4803  NS_ENSURE_SUCCESS(rv, rv);
4804 
4805  nsCOMPtr<sbIMediaList> libMediaList = do_QueryInterface(libMediaItem, &rv);
4806  NS_ENSURE_SUCCESS(rv, rv);
4807 
4808  // Build a property array with the name of the list
4809  nsString listName;
4810  rv = libMediaList->GetName(listName);
4811  NS_ENSURE_SUCCESS(rv, rv);
4812 
4813  nsCOMPtr<sbIMutablePropertyArray> properties =
4814  do_CreateInstance(SB_MUTABLEPROPERTYARRAY_CONTRACTID, &rv);
4815  NS_ENSURE_SUCCESS(rv, rv);
4816 
4817  rv = properties->AppendProperty(NS_LITERAL_STRING(SB_PROPERTY_MEDIALISTNAME),
4818  listName);
4819  NS_ENSURE_SUCCESS(rv, rv);
4820 
4821 
4822  nsCOMPtr<sbIMediaList> newMediaList;
4823  rv = aLibrary->CreateMediaList(NS_LITERAL_STRING("simple"),
4824  properties,
4825  getter_AddRefs(newMediaList));
4826  NS_ENSURE_SUCCESS(rv, rv);
4827 
4828  // LinkCopy will do the right thing even if the newMediaList
4829  // is in the main library.
4830  rv = sbLibraryUtils::LinkCopy(libMediaItem, newMediaList);
4831  NS_ENSURE_SUCCESS(rv, rv);
4832 
4833  rv = CopyChangedMediaItemsToMediaList(change, newMediaList);
4834  NS_ENSURE_SUCCESS(rv, rv);
4835  }
4836 
4837  return NS_OK;
4838 }
4839 
4840 nsresult
4841 sbBaseDevice::UpdateMediaLists(nsIArray * aMediaLists)
4842 {
4843  NS_ENSURE_ARG_POINTER(aMediaLists);
4844 
4845  nsresult rv;
4846 
4847  PRUint32 count;
4848  rv = aMediaLists->GetLength(&count);
4849  NS_ENSURE_SUCCESS(rv, rv);
4850 
4851  for (PRUint32 i = 0; i < count; i++) {
4852  if (IsRequestAborted()) {
4853  return NS_ERROR_ABORT;
4854  }
4855 
4856  nsCOMPtr<sbILibraryChange> change =
4857  do_QueryElementAt(aMediaLists, i, &rv);
4858  if (NS_FAILED(rv)) {
4859  NS_WARNING("Unable to retrieve update change from array");
4860  continue;
4861  }
4862  nsCOMPtr<sbIMediaItem> destItem;
4863  rv = change->GetDestinationItem(getter_AddRefs(destItem));
4864  NS_ENSURE_SUCCESS(rv, rv);
4865 
4866  nsCOMPtr<sbIMediaList> destList = do_QueryInterface(destItem , &rv);
4867  NS_ENSURE_SUCCESS(rv, rv);
4868 
4869  rv = destList->Clear();
4870  NS_ENSURE_SUCCESS(rv, rv);
4871 
4872  nsCOMPtr<sbIMediaItem> sourceItem;
4873  rv = change->GetSourceItem(getter_AddRefs(sourceItem));
4874  NS_ENSURE_SUCCESS(rv, rv);
4875 
4876  nsCOMPtr<sbIMediaList> sourceList = do_QueryInterface(sourceItem, &rv);
4877  NS_ENSURE_SUCCESS(rv, rv);
4878 
4879  nsString name;
4880  rv = sourceList->GetName(name);
4881  NS_ENSURE_SUCCESS(rv, rv);
4882 
4883  rv = destList->SetName(name);
4884  NS_ENSURE_SUCCESS(rv, rv);
4885 
4887  destList);
4888  NS_ENSURE_SUCCESS(rv, rv);
4889  }
4890  return NS_OK;
4891 }
4892 
4893 NS_IMETHODIMP
4895  sbILibraryChangeset* aChangeset)
4896 {
4897  // Validate arguments.
4898  NS_ENSURE_ARG_POINTER(aDevLibrary);
4899  NS_ENSURE_ARG_POINTER(aChangeset);
4900 
4901  // Function variables.
4902  nsresult rv;
4903 
4904  rv = EnsureSpaceForWrite(aChangeset, aDevLibrary);
4905  if (NS_FAILED(rv)) {
4906 
4907  // User cancelled the sync, set the state as such
4908  rv = SetState(STATE_CANCEL);
4909  NS_ENSURE_SUCCESS(rv, rv);
4910 
4911  nsCOMPtr<sbIDeviceStatus> status;
4912  rv = GetCurrentStatus(getter_AddRefs(status));
4913  NS_ENSURE_SUCCESS(rv, rv);
4914 
4915  rv = status->SetCurrentState(STATE_CANCEL);
4916  NS_ENSURE_SUCCESS(rv, rv);
4917  return NS_OK;
4918  }
4919 
4920  // Create some change list arrays.
4921  nsCOMPtr<nsIMutableArray> addMediaLists =
4922  do_CreateInstance("@songbirdnest.com/moz/xpcom/threadsafe-array;1", &rv);
4923  NS_ENSURE_SUCCESS(rv, rv);
4924  nsCOMPtr<nsIMutableArray> removeItemList =
4925  do_CreateInstance("@songbirdnest.com/moz/xpcom/threadsafe-array;1", &rv);
4926  NS_ENSURE_SUCCESS(rv, rv);
4927  nsCOMPtr<nsIMutableArray> addItemList =
4928  do_CreateInstance("@songbirdnest.com/moz/xpcom/threadsafe-array;1", &rv);
4929  NS_ENSURE_SUCCESS(rv, rv);
4930  nsCOMPtr<nsIMutableArray> updateMediaLists =
4931  do_CreateInstance("@songbirdnest.com/moz/xpcom/threadsafe-array;1", &rv);
4932  NS_ENSURE_SUCCESS(rv, rv);
4933 
4934  bool const playlistsSupported = sbDeviceUtils::ArePlaylistsSupported(this);
4935 
4936  // Get the list of all changes.
4937  nsCOMPtr<nsIArray> changeList;
4938  PRUint32 changeCount;
4939  rv = aChangeset->GetChanges(getter_AddRefs(changeList));
4940  NS_ENSURE_SUCCESS(rv, rv);
4941  rv = changeList->GetLength(&changeCount);
4942  NS_ENSURE_SUCCESS(rv, rv);
4943 
4944  // Group changes for later processing but apply property updates immediately.
4945  for (PRUint32 i = 0; i < changeCount; i++) {
4946  if (IsRequestAborted()) {
4947  return NS_ERROR_ABORT;
4948  }
4949  // Get the next change.
4950  nsCOMPtr<sbILibraryChange> change = do_QueryElementAt(changeList, i, &rv);
4951  NS_ENSURE_SUCCESS(rv, rv);
4952 
4953  // Put the change into the appropriate list.
4954  PRUint32 operation;
4955  rv = change->GetOperation(&operation);
4956  NS_ENSURE_SUCCESS(rv, rv);
4957 
4958  // Add item to add media list list or add item list.
4959  PRBool itemIsList;
4960  rv = change->GetItemIsList(&itemIsList);
4961  NS_ENSURE_SUCCESS(rv, rv);
4962 
4963  // if this is a playlist and they're not supported ignore the change
4964  if (itemIsList && !playlistsSupported) {
4965  continue;
4966  }
4967 
4968  switch (operation)
4969  {
4971  {
4972  // We no longer remove items from the device
4973  } break;
4974 
4976  {
4977  nsCOMPtr<sbIMediaItem> srcItem;
4978  rv = change->GetSourceItem(getter_AddRefs(srcItem));
4979  NS_ENSURE_SUCCESS(rv, rv);
4980 
4981  if (itemIsList) {
4982  nsCOMPtr<sbIMediaList> mediaList = do_QueryInterface(srcItem,
4983  &rv);
4984  NS_ENSURE_SUCCESS(rv, rv);
4985 
4986  // Do not add empty media lists.
4987  PRBool isEmpty;
4988  rv = mediaList->GetIsEmpty(&isEmpty);
4989  NS_ENSURE_SUCCESS(rv, rv);
4990 
4991  if (!isEmpty) {
4992  rv = addMediaLists->AppendElement(change, PR_FALSE);
4993  NS_ENSURE_SUCCESS(rv, rv);
4994  }
4995  } else {
4996  rv = addItemList->AppendElement(srcItem, PR_FALSE);
4997  NS_ENSURE_SUCCESS(rv, rv);
4998  }
4999  } break;
5000 
5002  {
5003  nsCOMPtr<sbIMediaItem> destItem;
5004  rv = change->GetDestinationItem(getter_AddRefs(destItem));
5005  NS_ENSURE_SUCCESS(rv, rv);
5006 
5007  nsCOMPtr<sbIMediaItem> srcItem;
5008  rv = change->GetSourceItem(getter_AddRefs(srcItem));
5009  NS_ENSURE_SUCCESS(rv, rv);
5010 
5011  if (itemIsList) {
5012  nsCOMPtr<sbIMediaList> mediaList = do_QueryInterface(srcItem, &rv);
5013  NS_ENSURE_SUCCESS(rv, rv);
5014 
5015  PRBool isEmpty;
5016  rv = mediaList->GetIsEmpty(&isEmpty);
5017  NS_ENSURE_SUCCESS(rv, rv);
5018 
5019  // Do not add empty media lists.
5020  if (isEmpty) {
5021  break;
5022  }
5023  }
5024 
5025  nsCOMPtr<sbIMediaList> destItemAsList = do_QueryInterface(destItem);
5026  NS_ENSURE_SUCCESS(rv, rv);
5027 
5028  if (destItemAsList) {
5029  rv = updateMediaLists->AppendElement(change, PR_FALSE);
5030  NS_ENSURE_SUCCESS(rv, rv);
5031  }
5032  else {
5033  // Update mediaitem property changes
5034  nsCOMPtr<nsIArray> properties;
5035 
5036  rv = change->GetProperties(getter_AddRefs(properties));
5037  NS_ENSURE_SUCCESS(rv, rv);
5038 
5039  nsCOMPtr<nsISimpleEnumerator> propEnum;
5040  rv = properties->Enumerate(getter_AddRefs(propEnum));
5041  NS_ENSURE_SUCCESS(rv, rv);
5042 
5043  PRBool hasMoreElements;
5044  while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMoreElements)) &&
5045  hasMoreElements) {
5046  nsCOMPtr<sbIPropertyChange> propertyChange;
5047 
5048  rv = propEnum->GetNext(getter_AddRefs(propertyChange));
5049  NS_ENSURE_SUCCESS(rv, rv);
5050 
5051  nsString propertyId;
5052  nsString propertyValue;
5053 
5054  rv = propertyChange->GetId(propertyId);
5055  NS_ENSURE_SUCCESS(rv, rv);
5056 
5057  rv = propertyChange->GetNewValue(propertyValue);
5058  NS_ENSURE_SUCCESS(rv, rv);
5059 
5060  rv = destItem->SetProperty(propertyId, propertyValue);
5061  NS_ENSURE_SUCCESS(rv, rv);
5062  }
5063  }
5064  } break;
5065 
5066  default:
5067  break;
5068  }
5069  }
5070 
5071  if (IsRequestAborted()) {
5072  return NS_ERROR_ABORT;
5073  }
5074 
5075  nsCOMPtr<nsISimpleEnumerator> itemEnum;
5076  rv = removeItemList->Enumerate(getter_AddRefs(itemEnum));
5077  NS_ENSURE_SUCCESS(rv, rv);
5078  rv = aDevLibrary->RemoveSome(itemEnum);
5079  NS_ENSURE_SUCCESS(rv, rv);
5080 
5081  // Add items.
5082  rv = addItemList->Enumerate(getter_AddRefs(itemEnum));
5083  NS_ENSURE_SUCCESS(rv, rv);
5084  rv = aDevLibrary->AddSome(itemEnum);
5085  NS_ENSURE_SUCCESS(rv, rv);
5086 
5087  if (IsRequestAborted()) {
5088  rv = sbDeviceUtils::DeleteByProperty(aDevLibrary,
5089  NS_LITERAL_STRING(SB_PROPERTY_HIDDEN),
5090  NS_LITERAL_STRING("1"));
5091  NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to remove partial added items");
5092  return NS_ERROR_ABORT;
5093  }
5094 
5095  rv = AddMediaLists(aDevLibrary, addMediaLists);
5096  NS_ENSURE_SUCCESS(rv, rv);
5097 
5098  rv = UpdateMediaLists(updateMediaLists);
5099  NS_ENSURE_SUCCESS(rv, rv);
5100 
5101  return NS_OK;
5102 }
5103 
5104 nsresult
5106 {
5107  TRACE(("%s", __FUNCTION__));
5108  NS_ENSURE_ARG_POINTER(aMediaItem);
5109  NS_ENSURE_STATE(mMainLibrary);
5110 
5111  nsresult rv;
5112 
5113  // Get the guid of the original item, if any, that aMediaItem was
5114  // copied from. The origin _library_ guid is ignored here to
5115  // avoid an extra check. This is more efficient on configurations
5116  // where few items have been copied to the device from a library
5117  // other than the main library:
5118  nsAutoString originItemGuid;
5119  rv = aMediaItem->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_ORIGINITEMGUID),
5120  originItemGuid);
5121  NS_ENSURE_SUCCESS(rv, rv);
5122 
5123  // Get the last saved value of SB_PROPERTY_ORIGIN_IS_IN_MAIN_LIBRARY.
5124  // wasInMainLibrary will be an empty string if there is no last saved value,
5125  // which will force SB_PROPERTY_ORIGIN_IS_IN_MAIN_LIBRARY to be set
5126  // to isInMainLibrary at the end of this function.
5127  nsAutoString wasInMainLibrary;
5128  rv = aMediaItem->GetProperty(
5129  NS_LITERAL_STRING(SB_PROPERTY_ORIGIN_IS_IN_MAIN_LIBRARY),
5130  wasInMainLibrary);
5131  NS_ENSURE_SUCCESS(rv, rv);
5132 
5133  // Check whether the item is in the main library:
5134  nsAutoString isInMainLibrary;
5135  if (originItemGuid.IsEmpty()) {
5136  isInMainLibrary.AppendInt(0);
5137  }
5138  else {
5139  nsCOMPtr<sbIMediaItem> originItem;
5140  // GetMediaItem() returns an error if the item is not present, but
5141  // this behavior--and what error to expect--is undocumented. Just
5142  // ignore the result code and test the returned item instead.
5143  mMainLibrary->GetMediaItem(originItemGuid, getter_AddRefs(originItem));
5144  isInMainLibrary.AppendInt(originItem != NULL);
5145  }
5146 
5147  // Update SB_PROPERTY_ORIGIN_IS_IN_MAIN_LIBRARY if it changed:
5148  if (isInMainLibrary != wasInMainLibrary) {
5149  rv = aMediaItem->SetProperty(
5150  NS_LITERAL_STRING(SB_PROPERTY_ORIGIN_IS_IN_MAIN_LIBRARY),
5151  isInMainLibrary);
5152  NS_ENSURE_SUCCESS(rv, rv);
5153  }
5154 
5155  return NS_OK;
5156 }
5157 
5158 nsresult
5160 {
5161  TRACE(("%s", __FUNCTION__));
5162  NS_ENSURE_ARG_POINTER(aEject);
5163 
5164  nsresult rv;
5165 
5166  sbPrefBranch prefBranch("songbird.device.dialog.", &rv);
5167  NS_ENSURE_SUCCESS(rv, rv);
5168 
5169  PRBool hide_dialog = prefBranch.GetBoolPref("eject_while_playing", PR_FALSE);
5170 
5171  if (hide_dialog) {
5172  // if the dialog is disabled, continue as if the user had said yes
5173  *aEject = PR_TRUE;
5174  return NS_OK;
5175  }
5176 
5177  // get the prompter service and wait for a window to be available
5178  nsCOMPtr<sbIPrompter> prompter =
5179  do_GetService("@songbirdnest.com/Songbird/Prompter;1");
5180  NS_ENSURE_SUCCESS(rv, rv);
5181  rv = prompter->SetWaitForWindow(PR_TRUE);
5182  NS_ENSURE_SUCCESS(rv, rv);
5183 
5184  // get the stringbundle
5186 
5187  // get the window title
5188  nsString const& title = bundle.Get("device.dialog.eject_while_playing.title");
5189 
5190  // get the device name
5191  nsString deviceName;
5192  rv = GetName(deviceName);
5193  NS_ENSURE_SUCCESS(rv, rv);
5194 
5195  // get the message, based on the device name
5196  nsTArray<nsString> formatParams;
5197  formatParams.AppendElement(deviceName);
5198  nsString const& message =
5199  bundle.Format("device.dialog.eject_while_playing.message", formatParams);
5200 
5201  // get the text for the eject button
5202  nsString const& eject = bundle.Get("device.dialog.eject_while_playing.eject");
5203 
5204  // get the text for the checkbox
5205  nsString const& check =
5206  bundle.Get("device.dialog.eject_while_playing.dontask");
5207 
5208  // show the dialog box
5209  PRBool accept;
5210  rv = prompter->ConfirmEx(nsnull, title.get(), message.get(),
5211  (nsIPromptService::BUTTON_POS_0 *
5212  nsIPromptService::BUTTON_TITLE_IS_STRING) +
5213  (nsIPromptService::BUTTON_POS_1 *
5214  nsIPromptService::BUTTON_TITLE_CANCEL), eject.get(), nsnull, nsnull,
5215  check.get(), &hide_dialog, &accept);
5216  NS_ENSURE_SUCCESS(rv, rv);
5217 
5218  *aEject = !accept;
5219 
5220  // save the checkbox state
5221  rv = prefBranch.SetBoolPref("eject_while_playing", hide_dialog);
5222  NS_ENSURE_SUCCESS(rv, rv);
5223 
5224  return NS_OK;
5225 }
5226 
5227 nsresult
5229 {
5230  // Nothing for the base class to do.
5231  return NS_OK;
5232 }
5233 
5235  (sbIMediaItem* aWriteDstItem,
5236  nsIURI* aContentSrcBaseURI,
5237  nsIURI* aWriteSrcURI,
5238  nsIURI ** aContentSrc)
5239 {
5240  TRACE(("%s", __FUNCTION__));
5241  // Validate arguments.
5242  NS_ENSURE_ARG_POINTER(aWriteDstItem);
5243  NS_ENSURE_ARG_POINTER(aContentSrcBaseURI);
5244  NS_ENSURE_ARG_POINTER(aContentSrc);
5245 
5246  // Function variables.
5247  nsString kIllegalChars =
5248  NS_ConvertASCIItoUTF16(FILE_ILLEGAL_CHARACTERS);
5249  nsCOMPtr<nsIURI> writeSrcURI = aWriteSrcURI;
5250  nsresult rv;
5251 
5252  // If no write source URI is given, get it from the write source media item.
5253  if (!writeSrcURI) {
5254  // Get the origin item for the write destination item.
5255  nsCOMPtr<sbIMediaItem> writeSrcItem;
5256  rv = sbLibraryUtils::GetOriginItem(aWriteDstItem,
5257  getter_AddRefs(writeSrcItem));
5258  if (NS_FAILED(rv)) {
5259  // If there is not an existing origin for the write item, use the URI
5260  // of |aWriteDstItem|.
5261  rv = aWriteDstItem->GetContentSrc(getter_AddRefs(writeSrcURI));
5262  NS_ENSURE_SUCCESS(rv, rv);
5263  }
5264  else {
5265  // Get the write source URI.
5266  rv = writeSrcItem->GetContentSrc(getter_AddRefs(writeSrcURI));
5267  NS_ENSURE_SUCCESS(rv, rv);
5268  }
5269  }
5270 
5271  // Convert our nsIURI to an nsIFileURL and nsIFile
5272  nsCOMPtr<nsIFile> writeSrcFile;
5273  nsCOMPtr<nsIFileURL> writeSrcFileURL = do_QueryInterface(writeSrcURI, &rv);
5274  if (NS_SUCCEEDED(rv)) {
5275  // Now get the nsIFile
5276  rv = writeSrcFileURL->GetFile(getter_AddRefs(writeSrcFile));
5277  NS_ENSURE_SUCCESS(rv, rv);
5278 
5279  // Now check to make sure the source file actually exists
5280  PRBool fileExists = PR_FALSE;
5281  rv = writeSrcFile->Exists(&fileExists);
5282  NS_ENSURE_SUCCESS(rv, rv);
5283  if (!fileExists) {
5284  // Create the device error event and dispatch it
5285  nsCOMPtr<nsIVariant> var = sbNewVariant(aWriteDstItem).get();
5286  CreateAndDispatchEvent(sbIDeviceEvent::EVENT_DEVICE_FILE_MISSING,
5287  var, PR_TRUE);
5288 
5289  // Remove item from library
5290  nsCOMPtr<sbILibrary> destLibrary;
5291  rv = aWriteDstItem->GetLibrary(getter_AddRefs(destLibrary));
5292  NS_ENSURE_SUCCESS(rv, rv);
5293 
5294  rv = DeleteItem(destLibrary, aWriteDstItem);
5295  NS_ENSURE_SUCCESS(rv, rv);
5296 
5297  return NS_ERROR_NOT_AVAILABLE;
5298  }
5299  }
5300 
5301  // Check if the item needs to be organized
5302  nsCOMPtr<sbILibrary> destLibrary;
5303  rv = aWriteDstItem->GetLibrary(getter_AddRefs(destLibrary));
5304  NS_ENSURE_SUCCESS(rv, rv);
5305  nsString destLibGuidStr;
5306  rv = destLibrary->GetGuid(destLibGuidStr);
5307  NS_ENSURE_SUCCESS(rv, rv);
5308  nsID destLibGuid;
5309  PRBool success =
5310  destLibGuid.Parse(NS_LossyConvertUTF16toASCII(destLibGuidStr).get());
5311  OrganizeData* organizeData = nsnull;
5312  if (success) {
5313  success = mOrganizeLibraryPrefs.Get(destLibGuid, &organizeData);
5314  }
5315 
5316  nsCOMPtr<nsIFile> contentSrcFile;
5317  if (success && organizeData->organizeEnabled) {
5318  nsCOMPtr<nsIFileURL> baseFileUrl =
5319  do_QueryInterface(aContentSrcBaseURI, &rv);
5320  NS_ENSURE_SUCCESS(rv, rv);
5321  nsCOMPtr<nsIFile> baseFile;
5322  rv = baseFileUrl->GetFile(getter_AddRefs(baseFile));
5323  NS_ENSURE_SUCCESS(rv, rv);
5324 
5325  // Get the managed path
5326  nsCOMPtr<sbIMediaFileManager> fileMgr =
5327  do_CreateInstance(SB_MEDIAFILEMANAGER_CONTRACTID, &rv);
5328  NS_ENSURE_SUCCESS(rv, rv);
5329 
5330  NS_NAMED_LITERAL_STRING(KEY_MEDIA_FOLDER, "media-folder");
5331  NS_NAMED_LITERAL_STRING(KEY_FILE_FORMAT, "file-format");
5332  NS_NAMED_LITERAL_STRING(KEY_DIR_FORMAT, "dir-format");
5333  nsCOMPtr<nsIWritablePropertyBag2> writableBag =
5334  do_CreateInstance("@songbirdnest.com/moz/xpcom/sbpropertybag;1");
5335  NS_ENSURE_TRUE(writableBag, NS_ERROR_OUT_OF_MEMORY);
5336  rv = writableBag->SetPropertyAsInterface(KEY_MEDIA_FOLDER, baseFile);
5337  NS_ENSURE_SUCCESS(rv, rv);
5338  rv = writableBag->SetPropertyAsACString(KEY_FILE_FORMAT, organizeData->fileFormat);
5339  NS_ENSURE_SUCCESS(rv, rv);
5340  rv = writableBag->SetPropertyAsACString(KEY_DIR_FORMAT, organizeData->dirFormat);
5341  NS_ENSURE_SUCCESS(rv, rv);
5342  rv = fileMgr->Init(writableBag);
5343  NS_ENSURE_SUCCESS(rv, rv);
5344 
5345  rv = fileMgr->GetManagedPath(aWriteDstItem,
5348  getter_AddRefs(contentSrcFile));
5349  NS_ENSURE_SUCCESS(rv, rv);
5350 
5351  nsCOMPtr<nsIFile> parentDir;
5352  rv = contentSrcFile->GetParent(getter_AddRefs(parentDir));
5353  NS_ENSURE_SUCCESS(rv, rv);
5354  rv = parentDir->Create(nsIFile::DIRECTORY_TYPE, 0755);
5355  if (rv != NS_ERROR_FILE_ALREADY_EXISTS) {
5356  NS_ENSURE_SUCCESS(rv, rv);
5357  }
5358  }
5359  else {
5360  // Get the write source file name, unescape it, and replace illegal
5361  // characters.
5362  nsAutoString writeSrcFileName;
5363  if (writeSrcFile) {
5364  nsCOMPtr<nsIFile> canonicalFile;
5365  nsCOMPtr<sbILibraryUtils> libUtils =
5366  do_GetService("@songbirdnest.com/Songbird/library/Manager;1", &rv);
5367  rv = libUtils->GetCanonicalPath(writeSrcFile,
5368  getter_AddRefs(canonicalFile));
5369  NS_ENSURE_SUCCESS(rv, rv);
5370  rv = canonicalFile->GetLeafName(writeSrcFileName);
5371  NS_ENSURE_SUCCESS(rv, rv);
5372  }
5373  else {
5374  nsCOMPtr<nsIURL>
5375  writeSrcURL = do_MainThreadQueryInterface(writeSrcURI, &rv);
5376  NS_ENSURE_SUCCESS(rv, rv);
5377  nsCAutoString fileName;
5378  rv = writeSrcURL->GetFileName(fileName);
5379  NS_ENSURE_SUCCESS(rv, rv);
5380  writeSrcFileName = NS_ConvertUTF8toUTF16(fileName);
5381  }
5382 
5383  // replace illegal characters
5384  nsString_ReplaceChar(writeSrcFileName, kIllegalChars, PRUnichar('_'));
5385 
5386  // Get a file object for the content base.
5387  nsCOMPtr<nsIFileURL>
5388  contentSrcBaseFileURL = do_QueryInterface(aContentSrcBaseURI, &rv);
5389  NS_ENSURE_SUCCESS(rv, rv);
5390  nsCOMPtr<nsIFile> contentSrcBaseFile;
5391  rv = contentSrcBaseFileURL->GetFile(getter_AddRefs(contentSrcBaseFile));
5392  NS_ENSURE_SUCCESS(rv, rv);
5393 
5394  // Start the content source at the base.
5395  rv = contentSrcBaseFile->Clone(getter_AddRefs(contentSrcFile));
5396  NS_ENSURE_SUCCESS(rv, rv);
5397 
5398  // Append file name of the write source file.
5399  rv = contentSrcFile->Append(writeSrcFileName);
5400  NS_ENSURE_SUCCESS(rv, rv);
5401  }
5402 
5403  // Check if the content source file already exists.
5404  PRBool exists;
5405  rv = contentSrcFile->Exists(&exists);
5406  NS_ENSURE_SUCCESS(rv, rv);
5407 
5408  // Create a unique file if content source file already exists.
5409  if (exists) {
5410  // Get the permissions of the content source parent.
5411  PRUint32 permissions;
5412  nsCOMPtr<nsIFile> parent;
5413  rv = contentSrcFile->GetParent(getter_AddRefs(parent));
5414  NS_ENSURE_SUCCESS(rv, rv);
5415  rv = parent->GetPermissions(&permissions);
5416  NS_ENSURE_SUCCESS(rv, rv);
5417 
5418  // Create a unique file.
5419  rv = contentSrcFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, permissions);
5420  NS_ENSURE_SUCCESS(rv, rv);
5421  }
5422 
5423  rv = sbNewFileURI(contentSrcFile, aContentSrc);
5424  NS_ENSURE_SUCCESS(rv, rv);
5425 
5426  return NS_OK;
5427 }
5428 
5430 {
5431  nsresult rv;
5432 
5433 // hook up the media list listeners to the existing lists
5434  nsRefPtr<MediaListListenerAttachingEnumerator> enumerator =
5436 
5437  NS_ENSURE_TRUE(enumerator, NS_ERROR_OUT_OF_MEMORY);
5438 
5439  rv = aLibrary->EnumerateItemsByProperty(NS_LITERAL_STRING(SB_PROPERTY_ISLIST),
5440  NS_LITERAL_STRING("1"),
5441  enumerator,
5443  NS_ENSURE_SUCCESS(rv, rv);
5444 
5445  return NS_OK;
5446 }
5448 {
5449  TRACE(("%s", __FUNCTION__));
5450  nsresult rv;
5451 
5452  // Cancel any pending deferred setup device timer.
5454  rv = mDeferredSetupDeviceTimer->Cancel();
5455  NS_ENSURE_SUCCESS(rv, rv);
5456  mDeferredSetupDeviceTimer = nsnull;
5457  }
5458 
5459  // Defer device setup for a small time delay to allow device connection and
5460  // mounting to complete. Since device setup presents a modal dialog,
5461  // presenting the dialog immediately may stop mounting of other device
5462  // volumes, preventing them from showing up in the device setup dialog. In
5463  // addition, the dialog can prevent device connection from completing,
5464  // causing problems if the device is disconnected while the device setup
5465  // dialog is presented.
5466  mDeferredSetupDeviceTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
5467  NS_ENSURE_SUCCESS(rv, rv);
5468  rv = mDeferredSetupDeviceTimer->InitWithFuncCallback(DeferredSetupDevice,
5469  this,
5471  nsITimer::TYPE_ONE_SHOT);
5472  NS_ENSURE_SUCCESS(rv, rv);
5473 
5474  return NS_OK;
5475 }
5476 
5477 /* static */ void
5479  void* aClosure)
5480 {
5481  TRACE(("%s", __FUNCTION__));
5482  sbBaseDevice* baseDevice = reinterpret_cast<sbBaseDevice*>(aClosure);
5483  baseDevice->DeferredSetupDevice();
5484 }
5485 
5486 nsresult
5488 {
5489  TRACE(("%s", __FUNCTION__));
5490  nsresult rv;
5491 
5492  // Clear the deferred setup device timer.
5493  mDeferredSetupDeviceTimer = nsnull;
5494 
5495  // Present the setup device dialog.
5496  nsCOMPtr<sbIPrompter>
5497  prompter = do_CreateInstance(SONGBIRD_PROMPTER_CONTRACTID, &rv);
5498  NS_ENSURE_SUCCESS(rv, rv);
5499  nsCOMPtr<nsIDOMWindow> dialogWindow;
5500  rv = prompter->OpenDialog
5501  (nsnull,
5502  NS_LITERAL_STRING
5503  ("chrome://songbird/content/xul/device/deviceSetupDialog.xul"),
5504  NS_LITERAL_STRING("DeviceSetup"),
5505  NS_LITERAL_STRING("chrome,centerscreen,modal=yes,titlebar=no"),
5506  NS_ISUPPORTS_CAST(sbIDevice*, this),
5507  getter_AddRefs(dialogWindow));
5508  NS_ENSURE_SUCCESS(rv, rv);
5509 
5510  return NS_OK;
5511 }
5512 
5513 nsresult
5515 {
5516  TRACE(("%s", __FUNCTION__));
5517  // If we haven't built the registrars then do so
5519  return NS_OK;
5520  }
5521 
5522  nsresult rv;
5523  nsCOMPtr<nsICategoryManager> catMgr =
5524  do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
5525  NS_ENSURE_SUCCESS(rv, rv);
5526 
5527  nsCOMPtr<nsISimpleEnumerator> enumerator;
5528  rv = catMgr->EnumerateCategory(SB_DEVICE_INFO_REGISTRAR_CATEGORY,
5529  getter_AddRefs(enumerator));
5530  NS_ENSURE_SUCCESS(rv, rv);
5531 
5532  // Enumerate the registrars and find the highest scoring one (Greatest type)
5533  PRBool hasMore;
5534  rv = enumerator->HasMoreElements(&hasMore);
5535  NS_ENSURE_SUCCESS(rv, rv);
5536 
5537  while(hasMore) {
5538  nsCOMPtr<nsISupports> supports;
5539  rv = enumerator->GetNext(getter_AddRefs(supports));
5540  NS_ENSURE_SUCCESS(rv, rv);
5541 
5542  nsCOMPtr<nsISupportsCString> data = do_QueryInterface(supports, &rv);
5543  NS_ENSURE_SUCCESS(rv, rv);
5544 
5545  nsCString entryName;
5546  rv = data->GetData(entryName);
5547  NS_ENSURE_SUCCESS(rv, rv);
5548 
5549  nsCString contractId;
5550  rv = catMgr->GetCategoryEntry(SB_DEVICE_INFO_REGISTRAR_CATEGORY,
5551  entryName.get(),
5552  getter_Copies(contractId));
5553  NS_ENSURE_SUCCESS(rv, rv);
5554 
5555  nsCOMPtr<sbIDeviceInfoRegistrar> infoRegistrar =
5556  do_CreateInstance(contractId.get(), &rv);
5557  NS_ENSURE_SUCCESS(rv, rv);
5558 
5559  PRBool interested;
5560  rv = infoRegistrar->InterestedInDevice(this, &interested);
5561  NS_ENSURE_SUCCESS(rv, rv);
5562  if (interested) {
5563  PRUint32 type;
5564  rv = infoRegistrar->GetType(&type);
5565  NS_ENSURE_SUCCESS(rv, rv);
5566  if (type >= mInfoRegistrarType) {
5567  mInfoRegistrar = infoRegistrar;
5568  mInfoRegistrarType = type;
5569  }
5570  }
5571 
5572  rv = enumerator->HasMoreElements(&hasMore);
5573  NS_ENSURE_SUCCESS(rv, rv);
5574  }
5575  return NS_OK;
5576 }
5577 
5578 nsresult
5580 {
5581  TRACE(("%s", __FUNCTION__));
5582 
5583  PRBool success;
5584  nsresult rv;
5585 
5586  // Process the device info registrars.
5587  rv = ProcessInfoRegistrars();
5588  NS_ENSURE_SUCCESS(rv, rv);
5589 
5590  // Get the device properties.
5591  nsCOMPtr<nsIWritablePropertyBag> deviceProperties;
5592  rv = GetWritableDeviceProperties(this, getter_AddRefs(deviceProperties));
5593  NS_ENSURE_SUCCESS(rv, rv);
5594 
5595  // Register device default name.
5596  nsString defaultName;
5597  rv = mInfoRegistrar->GetDefaultName(this, defaultName);
5598  NS_ENSURE_SUCCESS(rv, rv);
5599 
5600  LOG(("Default Name: %s", NS_ConvertUTF16toUTF8(defaultName).get()));
5601 
5602  if (!defaultName.IsEmpty()) {
5603  rv = deviceProperties->SetProperty(
5604  NS_LITERAL_STRING(SB_DEVICE_PROPERTY_DEFAULT_NAME),
5605  sbNewVariant(defaultName));
5606  NS_ENSURE_SUCCESS(rv, rv);
5607  }
5608 
5609  // Register device folders.
5610  for (PRUint32 i = 0;
5611  i < NS_ARRAY_LENGTH(sbBaseDeviceSupportedFolderContentTypeList);
5612  ++i) {
5613  // Get the next folder content type.
5614  PRUint32 folderContentType = sbBaseDeviceSupportedFolderContentTypeList[i];
5615 
5616  // Allocate a folder URL.
5617  nsAutoPtr<nsString> folderURL(new nsString());
5618  NS_ENSURE_TRUE(folderURL, NS_ERROR_OUT_OF_MEMORY);
5619 
5620  // Get the device folder URL and add it to the media folder URL table.
5621  rv = mInfoRegistrar->GetDeviceFolder(this, folderContentType, *folderURL);
5622  NS_ENSURE_SUCCESS(rv, rv);
5623  if (!folderURL->IsEmpty()) {
5624  success = mMediaFolderURLTable.Put(folderContentType, folderURL);
5625  NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
5626  folderURL.forget();
5627  }
5628  }
5629 
5630  nsString excludedFolders;
5631  rv = mInfoRegistrar->GetExcludedFolders(this, excludedFolders);
5632  NS_ENSURE_SUCCESS(rv, rv);
5633 
5634  LOG(("Excluded Folders: %s",
5635  NS_LossyConvertUTF16toASCII(excludedFolders).BeginReading()));
5636 
5637  if (!excludedFolders.IsEmpty()) {
5638  rv = deviceProperties->SetProperty(
5639  NS_LITERAL_STRING(SB_DEVICE_PROPERTY_EXCLUDED_FOLDERS),
5640  sbNewVariant(excludedFolders));
5641  NS_ENSURE_SUCCESS(rv, rv);
5642  }
5643 
5644  // Get import rules:
5645  nsCOMPtr<nsIArray> importRules;
5646  rv = mInfoRegistrar->GetImportRules(this, getter_AddRefs(importRules));
5647  NS_ENSURE_SUCCESS(rv, rv);
5648 
5649  // Stow the rules, if any, in the device properties:
5650  if (importRules) {
5651  nsCOMPtr<nsIWritablePropertyBag2> devProps2 =
5652  do_QueryInterface(deviceProperties, &rv);
5653  NS_ENSURE_SUCCESS(rv, rv);
5654  rv = devProps2->SetPropertyAsInterface(
5655  NS_LITERAL_STRING(SB_DEVICE_PROPERTY_IMPORT_RULES),
5656  importRules);
5657  NS_ENSURE_SUCCESS(rv, rv);
5658  }
5659 
5660  // Log the device folders.
5661  LogDeviceFolders();
5662 
5663  // Determine if the device supports format.
5664  PRBool supportsFormat;
5665  rv = mInfoRegistrar->GetDoesDeviceSupportReformat(this, &supportsFormat);
5666  NS_ENSURE_SUCCESS(rv, rv);
5667 
5668  rv = deviceProperties->SetProperty(
5669  NS_LITERAL_STRING(SB_DEVICE_PROPERTY_SUPPORTS_REFORMAT),
5670  sbNewVariant(supportsFormat));
5671  NS_ENSURE_SUCCESS(rv, rv);
5672 
5673  return NS_OK;
5674 }
5675 
5680 nsresult
5682 {
5683  TRACE(("%s", __FUNCTION__));
5684  NS_ENSURE_ARG_POINTER(aCapabilities);
5685 
5686  nsresult rv;
5687 
5688  rv = ProcessInfoRegistrars();
5689  NS_ENSURE_SUCCESS(rv, rv);
5690 
5691  if (mInfoRegistrar) {
5692  rv = mInfoRegistrar->AddCapabilities(this, aCapabilities);
5693  NS_ENSURE_SUCCESS(rv, rv);
5694  }
5695 
5696  return NS_OK;
5697 }
5698 
5699 NS_IMETHODIMP
5701  sbIDeviceSupportsItemCallback* aCallback)
5702 {
5703  // This is always async, so it's fine to always create a new runnable and
5704  // do anything there
5705  NS_ENSURE_ARG_POINTER(aMediaItem);
5706  NS_ENSURE_ARG_POINTER(aCallback);
5707 
5708  nsresult rv;
5709  nsRefPtr<sbDeviceSupportsItemHelper> helper =
5711  NS_ENSURE_TRUE(helper, NS_ERROR_OUT_OF_MEMORY);
5712  rv = helper->Init(aMediaItem, this, aCallback);
5713  NS_ENSURE_SUCCESS(rv, rv);
5714 
5715  if (!NS_IsMainThread()) {
5716  nsCOMPtr<nsIRunnable> runnable =
5717  NS_NEW_RUNNABLE_METHOD(sbDeviceSupportsItemHelper,
5718  helper.get(),
5719  RunSupportsMediaItem);
5720  NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
5721  rv = NS_DispatchToMainThread(runnable);
5722  NS_ENSURE_SUCCESS(rv, rv);
5723  }
5724  else {
5725  helper->RunSupportsMediaItem();
5726  }
5727  return NS_OK;
5728 }
5729 
5730 nsresult
5732  sbDeviceSupportsItemHelper* aCallback,
5733  PRBool aReportErrors,
5734  PRBool* _retval)
5735 {
5736  // we will always need the aMediaItem and retval
5737  NS_ENSURE_ARG_POINTER(aMediaItem);
5738  NS_ENSURE_ARG_POINTER(_retval);
5739  if (NS_IsMainThread()) {
5740  // it is an error to call this on the main thread with no callback
5741  NS_ENSURE_ARG_POINTER(aCallback);
5742  }
5743 
5744  nsresult rv;
5745 
5746  // Handle image media items using file extensions.
5747  nsString contentType;
5748  rv = aMediaItem->GetContentType(contentType);
5749  NS_ENSURE_SUCCESS(rv, rv);
5750  if (contentType.Equals(NS_LITERAL_STRING("image"))) {
5751  // Get the media item file extension.
5752  nsCString sourceFileExtension;
5753  nsCOMPtr<nsIURI> sourceURI;
5754  rv = aMediaItem->GetContentSrc(getter_AddRefs(sourceURI));
5755  NS_ENSURE_SUCCESS(rv, rv);
5756  nsCOMPtr<nsIFileURL> sourceFileURL = do_QueryInterface(sourceURI, &rv);
5757  NS_ENSURE_SUCCESS(rv, rv);
5758  rv = sourceFileURL->GetFileExtension(sourceFileExtension);
5759  NS_ENSURE_SUCCESS(rv, rv);
5760  ToLowerCase(sourceFileExtension);
5761 
5762  // Get the list of file extensions supported by the device.
5763  nsTArray<nsString> fileExtensionList;
5765  (this,
5767  fileExtensionList);
5768  NS_ENSURE_SUCCESS(rv, rv);
5769 
5770  // Item is supported if its file extension is supported.
5771  *_retval = fileExtensionList.Contains
5772  (NS_ConvertUTF8toUTF16(sourceFileExtension));
5773 
5774  return NS_OK;
5775  }
5776 
5777  if (sbDeviceUtils::IsItemDRMProtected(aMediaItem)) {
5778  rv = SupportsMediaItemDRM(aMediaItem, aReportErrors, _retval);
5779  NS_ENSURE_SUCCESS(rv, rv);
5780 
5781  return NS_OK;
5782  }
5783 
5784  PRUint32 const transcodeType =
5785  GetDeviceTranscoding()->GetTranscodeType(aMediaItem);
5786  bool needsTranscoding = false;
5787 
5788  if (transcodeType == sbITranscodeProfile::TRANSCODE_TYPE_AUDIO &&
5790  *_retval = (mCanTranscodeAudio == CAN_TRANSCODE_YES) ? PR_TRUE : PR_FALSE;
5791  return NS_OK;
5792  }
5793  else if(transcodeType == sbITranscodeProfile::TRANSCODE_TYPE_AUDIO_VIDEO &&
5795  *_retval = (mCanTranscodeVideo == CAN_TRANSCODE_YES) ? PR_TRUE : PR_FALSE;
5796  return NS_OK;
5797  }
5798 
5799  // Try to check if we can transcode first, since it's cheaper than trying
5800  // to inspect the actual file (and both ways we get which files we can get
5801  // on the device).
5802  // XXX MOOK this needs to be fixed to be not gstreamer specific
5803  nsCOMPtr<nsIURI> inputUri;
5804  rv = aMediaItem->GetContentSrc(getter_AddRefs(inputUri));
5805  NS_ENSURE_SUCCESS(rv, rv);
5806 
5807  nsCOMPtr<sbIDeviceTranscodingConfigurator> configurator;
5808  rv = sbDeviceUtils::GetTranscodingConfigurator(transcodeType,
5809  getter_AddRefs(configurator));
5810  NS_ENSURE_SUCCESS(rv, rv);
5811 
5812  rv = configurator->SetInputUri(inputUri);
5813  NS_ENSURE_SUCCESS(rv, rv);
5814  nsCOMPtr<sbIDevice> device =
5815  do_QueryInterface(NS_ISUPPORTS_CAST(sbIDevice*, this), &rv);
5816  NS_ENSURE_SUCCESS(rv, rv);
5817  rv = configurator->SetDevice(device);
5818  NS_ENSURE_SUCCESS(rv, rv);
5819 
5820  rv = configurator->DetermineOutputType();
5821  if (NS_SUCCEEDED(rv)) {
5822  *_retval = PR_TRUE;
5823 
5824  if (transcodeType == sbITranscodeProfile::TRANSCODE_TYPE_AUDIO) {
5826  }
5827  else if(transcodeType == sbITranscodeProfile::TRANSCODE_TYPE_AUDIO_VIDEO) {
5829  }
5830 
5831  return NS_OK;
5832  }
5833 
5834  // Can't transcode, check the media format as a fallback.
5835  if (aCallback) {
5836  // asynchronous
5837  nsCOMPtr<sbIMediaInspector> inspector;
5838  rv = GetDeviceTranscoding()->GetMediaInspector(getter_AddRefs(inspector));
5839  NS_ENSURE_SUCCESS(rv, rv);
5840  rv = aCallback->InitJobProgress(inspector, transcodeType);
5841  NS_ENSURE_SUCCESS(rv, rv);
5842  rv = inspector->InspectMediaAsync(aMediaItem);
5843  NS_ENSURE_SUCCESS(rv, rv);
5844  return NS_ERROR_IN_PROGRESS;
5845  }
5846  // synchronous
5847  nsCOMPtr<sbIMediaFormat> mediaFormat;
5848  rv = GetDeviceTranscoding()->GetMediaFormat(transcodeType,
5849  aMediaItem,
5850  getter_AddRefs(mediaFormat));
5851  NS_ENSURE_SUCCESS(rv, rv);
5852  rv = sbDeviceUtils::DoesItemNeedTranscoding(transcodeType,
5853  mediaFormat,
5854  this,
5855  needsTranscoding);
5856 
5857  *_retval = (NS_SUCCEEDED(rv) && !needsTranscoding);
5858 
5859  if (transcodeType == sbITranscodeProfile::TRANSCODE_TYPE_AUDIO) {
5860  mCanTranscodeAudio = (*_retval == PR_TRUE) ? CAN_TRANSCODE_YES : CAN_TRANSCODE_NO;
5861  }
5862  else if(transcodeType == sbITranscodeProfile::TRANSCODE_TYPE_AUDIO_VIDEO) {
5863  mCanTranscodeVideo = (*_retval == PR_TRUE) ? CAN_TRANSCODE_YES : CAN_TRANSCODE_NO;
5864  }
5865 
5866  return NS_OK;
5867 }
5868 
5869 nsresult
5871 {
5872  nsresult rv;
5873 
5874  // Iterate over the batch updating item transferable
5875  const Batch::const_iterator end = aBatch.end();
5876  for (Batch::const_iterator iter = aBatch.begin();
5877  iter != end;
5878  ++iter) {
5879  TransferRequest * const request = static_cast<TransferRequest*>(*iter);
5880 
5881  // Skip everything but read and write requests
5882  switch (request->GetType()) {
5885  break;
5886  default:
5887  continue;
5888  }
5889 
5890  nsCOMPtr<sbIMediaItem> mediaItem = request->item;
5891 
5892  nsString trackType;
5893  rv = mediaItem->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_TRACKTYPE),
5894  trackType);
5895  NS_ENSURE_SUCCESS(rv, rv);
5896 
5897  if (trackType.IsEmpty())
5898  continue;
5899 
5900  PRBool isSupported = PR_FALSE;
5901  if (!mTrackSourceTable.Get(trackType, &isSupported)) {
5902  PRMonitor * stopWaitMonitor = mRequestThreadQueue->GetStopWaitMonitor();
5903 
5904  // check transferable only once.
5905  nsRefPtr<sbDeviceStreamingHandler> listener;
5906  rv = sbDeviceStreamingHandler::New(getter_AddRefs(listener),
5907  mediaItem,
5908  stopWaitMonitor);
5909  NS_ENSURE_SUCCESS(rv, rv);
5910 
5911  rv = listener->CheckTransferable();
5912  NS_ENSURE_SUCCESS(rv, rv);
5913 
5914  // Wait for the transferable check to complete.
5915  PRBool isComplete = PR_FALSE;
5916  while (!isComplete) {
5917  // Operate within the request wait monitor.
5918  nsAutoMonitor monitor(stopWaitMonitor);
5919 
5920  // Check for abort.
5921  NS_ENSURE_FALSE(IsRequestAborted(), NS_ERROR_ABORT);
5922 
5923  // Check if the transferable check is complete.
5924  isComplete = listener->IsComplete();
5925 
5926  // If not complete, wait for completion. If requests are cancelled,
5927  // the request wait monitor will be notified.
5928  if (!isComplete)
5929  monitor.Wait();
5930  }
5931 
5932  isSupported = listener->IsStreamingItemSupported();
5933  NS_ENSURE_TRUE(mTrackSourceTable.Put(trackType, isSupported),
5934  NS_ERROR_OUT_OF_MEMORY);
5935  }
5936 
5937  if (!isSupported) {
5938  request->destinationCompatibility =
5940  }
5941  }
5942 
5943  // Clear the table so next batch will be re-checked.
5944  mTrackSourceTable.Clear();
5945 
5946  return NS_OK;
5947 }
5948 
5949 /* attribute sbIDeviceLibrary defaultLibrary; */
5950 NS_IMETHODIMP
5952 {
5953  NS_ENSURE_ARG_POINTER(aDefaultLibrary);
5954  NS_IF_ADDREF(*aDefaultLibrary = mDefaultLibrary);
5955  return NS_OK;
5956 }
5957 
5958 NS_IMETHODIMP
5960 {
5961  NS_ENSURE_ARG_POINTER(aDefaultLibrary);
5962  nsresult rv;
5963 
5964  // Do nothing if default library is not changing.
5965  if (mDefaultLibrary == aDefaultLibrary)
5966  return NS_OK;
5967 
5968  // Ensure library is in the device content.
5969  nsCOMPtr<nsIArray> libraries;
5970  nsCOMPtr<sbIDeviceContent> content;
5971  PRUint32 index;
5972  rv = GetContent(getter_AddRefs(content));
5973  NS_ENSURE_SUCCESS(rv, rv);
5974  rv = content->GetLibraries(getter_AddRefs(libraries));
5975  NS_ENSURE_SUCCESS(rv, rv);
5976  rv = libraries->IndexOf(0, aDefaultLibrary, &index);
5977  if (rv == NS_ERROR_FAILURE) {
5978  // Library is not in device content.
5979  rv = NS_ERROR_ILLEGAL_VALUE;
5980  }
5981  NS_ENSURE_SUCCESS(rv, rv);
5982 
5983  // Update the default library preference.
5984  nsAutoString guid;
5985  rv = aDefaultLibrary->GetGuid(guid);
5986  NS_ENSURE_SUCCESS(rv, rv);
5987  rv = SetPreference(NS_LITERAL_STRING("default_library_guid"),
5988  sbNewVariant(guid));
5989  NS_ENSURE_SUCCESS(rv, rv);
5990 
5991  // Update the default library.
5992  rv = UpdateDefaultLibrary(aDefaultLibrary);
5993  NS_ENSURE_SUCCESS(rv, rv);
5994 
5995  // Update properties for new default library.
5996  UpdateProperties();
5997 
5998  return NS_OK;
5999 }
6000 
6001 /* readonly attribute sbIDeviceLibrary primaryLibrary; */
6002 NS_IMETHODIMP
6004 {
6005  NS_ENSURE_ARG_POINTER(aPrimaryLibrary);
6006  if (!mPrimaryVolume) {
6007  *aPrimaryLibrary = nsnull;
6008  return NS_OK;
6009  }
6010  return mPrimaryVolume->GetDeviceLibrary(aPrimaryLibrary);
6011 }
6012 
6013 nsresult
6015  nsIArray **aSupportedProfiles)
6016 {
6018  aType,
6019  aSupportedProfiles);
6020 }
6021 
6022 nsresult
6024  const nsAString& aPropertyName,
6025  nsIVariant** aPropertyValue)
6026 {
6027  TRACE(("%s", __FUNCTION__));
6028 
6029  // Validate arguments.
6030  NS_ENSURE_ARG_POINTER(aPropertyValue);
6031 
6032  // Function variables.
6033  nsresult rv;
6034 
6035  // Get the device transcoding profile.
6036  nsCOMPtr<sbITranscodeProfile> transcodeProfile;
6038  (aTranscodeType,
6039  getter_AddRefs(transcodeProfile));
6040  NS_ENSURE_SUCCESS(rv, rv);
6041 
6042  // Get a property enumerator.
6043  nsCOMPtr<nsISimpleEnumerator> propEnumerator;
6044  nsCOMPtr<nsIArray> properties;
6045  rv = transcodeProfile->GetAudioProperties(getter_AddRefs(properties));
6046  NS_ENSURE_SUCCESS(rv, rv);
6047  rv = properties->Enumerate(getter_AddRefs(propEnumerator));
6048  NS_ENSURE_SUCCESS(rv, rv);
6049 
6050  // Search for property.
6051  PRBool more = PR_FALSE;
6052  rv = propEnumerator->HasMoreElements(&more);
6053  NS_ENSURE_SUCCESS(rv, rv);
6054  while (more) {
6055  // Get the next property.
6056  nsCOMPtr<sbITranscodeProfileProperty> property;
6057  rv = propEnumerator->GetNext(getter_AddRefs(property));
6058  NS_ENSURE_SUCCESS(rv, rv);
6059 
6060  // Get the property name.
6061  nsAutoString profilePropName;
6062  rv = property->GetPropertyName(profilePropName);
6063  NS_ENSURE_SUCCESS(rv, rv);
6064 
6065  // Return property value if its name matches.
6066  if (profilePropName.Equals(aPropertyName)) {
6067  rv = property->GetValue(aPropertyValue);
6068  NS_ENSURE_SUCCESS(rv, rv);
6069  return NS_OK;
6070  }
6071 
6072  // Check for more properties.
6073  rv = propEnumerator->HasMoreElements(&more);
6074  NS_ENSURE_SUCCESS(rv, rv);
6075  }
6076 
6077  // Property not found.
6078  *aPropertyValue = nsnull;
6079 
6080  return NS_OK;
6081 }
6082 
6083 nsresult
6085  const nsAString& aErrorMessage)
6086 {
6087  TRACE(("%s", __FUNCTION__));
6088  NS_ENSURE_ARG_POINTER(aMediaItem);
6089 
6090  nsresult rv;
6091 
6092  nsCOMPtr<nsIWritablePropertyBag2> bag =
6093  do_CreateInstance("@songbirdnest.com/moz/xpcom/sbpropertybag;1", &rv);
6094  NS_ENSURE_SUCCESS(rv, rv);
6095 
6096  rv = bag->SetPropertyAsAString(NS_LITERAL_STRING("message"), aErrorMessage);
6097  NS_ENSURE_SUCCESS(rv, rv);
6098  rv = bag->SetPropertyAsInterface(NS_LITERAL_STRING("item"), aMediaItem);
6099  NS_ENSURE_SUCCESS(rv, rv);
6100 
6101  nsString srcUri;
6102  rv = aMediaItem->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_CONTENTURL),
6103  srcUri);
6104  if (NS_SUCCEEDED(rv)) {
6105  nsCOMPtr<sbITranscodeError> transcodeError;
6106  rv = SB_NewTranscodeError(aErrorMessage, aErrorMessage, SBVoidString(),
6107  srcUri,
6108  aMediaItem,
6109  getter_AddRefs(transcodeError));
6110  NS_ENSURE_SUCCESS(rv, rv);
6111  rv = bag->SetPropertyAsInterface(NS_LITERAL_STRING("transcode-error"),
6112  NS_ISUPPORTS_CAST(sbITranscodeError*, transcodeError));
6113  NS_ENSURE_SUCCESS(rv, rv);
6114  }
6115 
6117  sbNewVariant(NS_GET_IID(nsIPropertyBag2), bag));
6118  NS_ENSURE_SUCCESS(rv, rv);
6119 
6120  return NS_OK;
6121 }
6122 
6123 static nsresult
6124 AddAlbumArtFormats(PRUint32 aContentType,
6125  sbIDeviceCapabilities *aCapabilities,
6126  nsIMutableArray *aArray,
6127  PRUint32 numMimeTypes,
6128  char **mimeTypes)
6129 {
6130  nsresult rv;
6131 
6132  for (PRUint32 i = 0; i < numMimeTypes; i++) {
6133  nsISupports** formatTypes;
6134  PRUint32 formatTypeCount;
6135  rv = aCapabilities->GetFormatTypes(aContentType,
6136  NS_ConvertASCIItoUTF16(mimeTypes[i]),
6137  &formatTypeCount,
6138  &formatTypes);
6139  NS_ENSURE_SUCCESS(rv, rv);
6140  sbAutoFreeXPCOMPointerArray<nsISupports> freeFormats(formatTypeCount,
6141  formatTypes);
6142  for (PRUint32 formatIndex = 0;
6143  formatIndex < formatTypeCount;
6144  formatIndex++)
6145  {
6146  nsCOMPtr<sbIImageFormatType> constraints =
6147  do_QueryInterface(formatTypes[formatIndex], &rv);
6148  NS_ENSURE_SUCCESS(rv, rv);
6149 
6150  rv = aArray->AppendElement(constraints, PR_FALSE);
6151  NS_ENSURE_SUCCESS(rv, rv);
6152  }
6153  }
6154 
6155  return NS_OK;
6156 }
6157 
6158 nsresult
6160 {
6161  TRACE(("%s", __FUNCTION__));
6162  nsresult rv;
6163  nsCOMPtr<nsIMutableArray> formatConstraints =
6164  do_CreateInstance(SB_THREADSAFE_ARRAY_CONTRACTID, &rv);
6165  NS_ENSURE_SUCCESS(rv, rv);
6166 
6167  nsCOMPtr<sbIDeviceCapabilities> capabilities;
6168  rv = GetCapabilities(getter_AddRefs(capabilities));
6169  NS_ENSURE_SUCCESS(rv, rv);
6170 
6171  char **mimeTypes;
6172  PRUint32 numMimeTypes;
6173  rv = capabilities->GetSupportedMimeTypes(sbIDeviceCapabilities::CONTENT_IMAGE,
6174  &numMimeTypes, &mimeTypes);
6175  NS_ENSURE_SUCCESS(rv, rv);
6176 
6178  capabilities,
6179  formatConstraints,
6180  numMimeTypes,
6181  mimeTypes);
6182  /* Ensure everything is freed here before potentially returning; no
6183  magic destructors for this thing */
6184  NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(numMimeTypes, mimeTypes);
6185  NS_ENSURE_SUCCESS (rv, rv);
6186 
6187  NS_ADDREF (*aFormats = formatConstraints);
6188  return NS_OK;
6189 }
6190 
6191 nsresult
6192 sbBaseDevice::GetShouldLimitMusicSpace(const nsAString & aPrefBase,
6193  PRBool *aOutShouldLimitSpace)
6194 {
6195  TRACE(("%s", __FUNCTION__));
6196  NS_ENSURE_ARG_POINTER(aOutShouldLimitSpace);
6197  *aOutShouldLimitSpace = PR_FALSE;
6198 
6199  nsresult rv;
6200  nsCOMPtr<nsIVariant> shouldEnableVar;
6201  rv = GetLibraryPreference(aPrefBase,
6202  NS_LITERAL_STRING("use_music_limit_percent"),
6203  getter_AddRefs(shouldEnableVar));
6204  NS_ENSURE_SUCCESS(rv, rv);
6205 
6206  return shouldEnableVar->GetAsBool(aOutShouldLimitSpace);
6207 }
6208 
6209 nsresult
6210 sbBaseDevice::GetMusicLimitSpacePercent(const nsAString & aPrefBase,
6211  PRUint32 *aOutLimitPercentage)
6212 {
6213  TRACE(("%s", __FUNCTION__));
6214  NS_ENSURE_ARG_POINTER(aOutLimitPercentage);
6215  *aOutLimitPercentage = 100; // always default to 100
6216 
6217  nsresult rv;
6218  nsCOMPtr<nsIVariant> prefValue;
6219  rv = GetLibraryPreference(aPrefBase,
6220  NS_LITERAL_STRING("music_limit_percent"),
6221  getter_AddRefs(prefValue));
6222  NS_ENSURE_SUCCESS(rv, rv);
6223 
6224  return prefValue->GetAsUint32(aOutLimitPercentage);
6225 }
6226 
6227 /* void Eject(); */
6228 NS_IMETHODIMP sbBaseDevice::Eject()
6229 {
6230  TRACE(("%s", __FUNCTION__));
6231 
6232  nsresult rv;
6233 
6234  // Device has no default library. Just leave.
6235  if (!mDefaultLibrary)
6236  return NS_OK;
6237 
6238  // If the playback is on for the device item, stop the playback before
6239  // ejecting.
6240  nsCOMPtr<sbIMediacoreManager> mediacoreManager =
6241  do_GetService(SB_MEDIACOREMANAGER_CONTRACTID, &rv);
6242  NS_ENSURE_SUCCESS(rv, rv);
6243 
6244  nsCOMPtr<sbIMediacoreSequencer> sequencer;
6245  rv = mediacoreManager->GetSequencer(getter_AddRefs(sequencer));
6246  NS_ENSURE_SUCCESS(rv, rv);
6247 
6248  // Get the currently playing media item.
6249  nsCOMPtr<sbIMediaItem> mediaItem;
6250  rv = sequencer->GetCurrentItem(getter_AddRefs(mediaItem));
6251  NS_ENSURE_SUCCESS(rv, rv);
6252 
6253  // No current media item. Just leave.
6254  if (!mediaItem)
6255  return NS_OK;
6256 
6257  // Get the library that the media item lives in.
6258  nsCOMPtr<sbILibrary> library;
6259  rv = mediaItem->GetLibrary(getter_AddRefs(library));
6260  NS_ENSURE_SUCCESS(rv, rv);
6261 
6262  // Is that library our device library?
6263  PRBool equal;
6264  rv = mDefaultLibrary->Equals(library, &equal);
6265  NS_ENSURE_SUCCESS(rv, rv);
6266 
6267  if (equal) {
6268  nsCOMPtr<sbIMediacoreStatus> status;
6269  rv = mediacoreManager->GetStatus(getter_AddRefs(status));
6270  NS_ENSURE_SUCCESS(rv, rv);
6271 
6272  PRUint32 state = 0;
6273  rv = status->GetState(&state);
6274  NS_ENSURE_SUCCESS(rv, rv);
6275 
6276  // Not playing, nothing to do.
6277  if (state == sbIMediacoreStatus::STATUS_STOPPED ||
6279  return NS_OK;
6280  }
6281 
6282  // Confirm with user on whether to stop the playback and eject.
6283  PRBool eject;
6285  NS_ENSURE_SUCCESS(rv, rv);
6286 
6287  if (!eject)
6288  return NS_ERROR_ABORT;
6289 
6290  nsCOMPtr<sbIMediacorePlaybackControl> playbackControl;
6291  rv = mediacoreManager->GetPlaybackControl(getter_AddRefs(playbackControl));
6292  NS_ENSURE_SUCCESS(rv, rv);
6293 
6294  rv = playbackControl->Stop();
6295  NS_ENSURE_SUCCESS(rv, rv);
6296  }
6297 
6298  return NS_OK;
6299 }
6300 
6301 /* void Format(); */
6302 NS_IMETHODIMP sbBaseDevice::Format()
6303 {
6304  TRACE(("%s", __FUNCTION__));
6305  return NS_ERROR_NOT_IMPLEMENTED;
6306 }
6307 
6308 /* readonly attribute boolean supportsReformat; */
6309 NS_IMETHODIMP sbBaseDevice::GetSupportsReformat(PRBool *_retval)
6310 {
6311  TRACE(("%s", __FUNCTION__));
6312  NS_ENSURE_ARG_POINTER(_retval);
6313  *_retval = PR_FALSE;
6314 
6315  nsresult rv;
6316  nsCOMPtr<nsIPropertyBag2> deviceProperties;
6317  rv = GetPropertyBag(this, getter_AddRefs(deviceProperties));
6318  NS_ENSURE_SUCCESS(rv, rv);
6319 
6320  rv = deviceProperties->GetPropertyAsBool(
6321  NS_LITERAL_STRING(SB_DEVICE_PROPERTY_SUPPORTS_REFORMAT),
6322  _retval);
6323  NS_ENSURE_SUCCESS(rv, rv);
6324 
6325  return NS_OK;
6326 }
6327 
6328 nsresult
6330 {
6331  TRACE(("%s", __FUNCTION__));
6332  PRBool hasKey;
6333  nsresult rv;
6334 
6335  nsCOMPtr<nsIPropertyBag2> properties;
6336  rv = GetPropertyBag(this, getter_AddRefs(properties));
6337  NS_ENSURE_SUCCESS(rv, rv);
6338 
6339  // Try using the friendly name property and exit if successful.
6340  rv = properties->HasKey(NS_LITERAL_STRING(SB_DEVICE_PROPERTY_NAME), &hasKey);
6341  NS_ENSURE_SUCCESS(rv, rv);
6342  if (hasKey) {
6343  rv = properties->GetPropertyAsAString
6344  (NS_LITERAL_STRING(SB_DEVICE_PROPERTY_NAME), aName);
6345  NS_ENSURE_SUCCESS(rv, rv);
6346  return NS_OK;
6347  }
6348 
6349  // Try using the default name property and exit if successful.
6350  rv = properties->HasKey(NS_LITERAL_STRING(SB_DEVICE_PROPERTY_DEFAULT_NAME),
6351  &hasKey);
6352  NS_ENSURE_SUCCESS(rv, rv);
6353  if (hasKey) {
6354  rv = properties->GetPropertyAsAString
6355  (NS_LITERAL_STRING(SB_DEVICE_PROPERTY_DEFAULT_NAME),
6356  aName);
6357  NS_ENSURE_SUCCESS(rv, rv);
6358  return NS_OK;
6359  }
6360 
6361  // Use the product name.
6362  return GetProductName(aName);
6363 }
6364 
6365 nsresult
6366 sbBaseDevice::GetProductNameBase(char const * aDefaultModelNumberString,
6367  nsAString& aProductName)
6368 {
6369  TRACE(("%s [%s]", __FUNCTION__, aDefaultModelNumberString));
6370  NS_ENSURE_ARG_POINTER(aDefaultModelNumberString);
6371 
6372  nsAutoString productName;
6373  PRBool hasKey;
6374  nsresult rv;
6375 
6376  nsCOMPtr<nsIPropertyBag2> properties;
6377  rv = GetPropertyBag(this, getter_AddRefs(properties));
6378  NS_ENSURE_SUCCESS(rv, rv);
6379 
6380  // Get the vendor name.
6381  nsAutoString vendorName;
6382  rv = properties->HasKey(NS_LITERAL_STRING(SB_DEVICE_PROPERTY_MANUFACTURER),
6383  &hasKey);
6384  NS_ENSURE_SUCCESS(rv, rv);
6385  if (hasKey) {
6386  // Get the vendor name.
6387  rv = properties->GetPropertyAsAString
6388  (NS_LITERAL_STRING(SB_DEVICE_PROPERTY_MANUFACTURER),
6389  vendorName);
6390  NS_ENSURE_SUCCESS(rv, rv);
6391  }
6392 
6393  // Get the device model number, using a default if one is not available.
6394  nsAutoString modelNumber;
6395  rv = properties->HasKey(NS_LITERAL_STRING(SB_DEVICE_PROPERTY_MODEL),
6396  &hasKey);
6397  NS_ENSURE_SUCCESS(rv, rv);
6398  if (hasKey) {
6399  // Get the model number.
6400  rv = properties->GetPropertyAsAString(
6401  NS_LITERAL_STRING(SB_DEVICE_PROPERTY_MODEL),
6402  modelNumber);
6403  NS_ENSURE_SUCCESS(rv, rv);
6404  }
6405  if (modelNumber.IsEmpty()) {
6406  // Get the default model number.
6407  modelNumber = SBLocalizedString(aDefaultModelNumberString);
6408  }
6409 
6410  // Produce the product name.
6411  if (!vendorName.IsEmpty() &&
6412  !StringBeginsWith(modelNumber, vendorName)) {
6413  nsTArray<nsString> params;
6414  NS_ENSURE_TRUE(params.AppendElement(vendorName), NS_ERROR_OUT_OF_MEMORY);
6415  NS_ENSURE_TRUE(params.AppendElement(modelNumber), NS_ERROR_OUT_OF_MEMORY);
6416  productName.Assign(SBLocalizedString("device.product.name", params));
6417  } else {
6418  productName.Assign(modelNumber);
6419  }
6420 
6421  // Return results.
6422  aProductName.Assign(productName);
6423 
6424  return NS_OK;
6425 }
6426 
6427 nsresult
6429  sbAutoIgnoreWatchFolderPath ** aIgnorePath)
6430 {
6431  nsresult rv;
6432  // Setup the ignore rule w/ the watch folder service.
6433  nsRefPtr<sbAutoIgnoreWatchFolderPath> autoWFPathIgnore =
6435  NS_ENSURE_TRUE(autoWFPathIgnore, NS_ERROR_OUT_OF_MEMORY);
6436 
6437  nsCOMPtr<nsIFileURL> destURL =
6438  do_QueryInterface(aURI, &rv);
6439  if (NS_FAILED(rv)) {
6440  return NS_OK;
6441  }
6442 
6443  nsCOMPtr<nsIFile> destFile;
6444  rv = destURL->GetFile(getter_AddRefs(destFile));
6445  if (NS_FAILED(rv)) {
6446  return NS_OK;
6447  }
6448 
6449  nsString destPath;
6450  rv = destFile->GetPath(destPath);
6451  NS_ENSURE_SUCCESS(rv, rv);
6452 
6453  rv = autoWFPathIgnore->Init(destPath);
6454  NS_ENSURE_SUCCESS(rv, rv);
6455 
6456  autoWFPathIgnore.forget(aIgnorePath);
6457 
6458  return NS_OK;
6459 }
6460 
6461 nsresult
6462 sbBaseDevice::GetExcludedFolders(nsTArray<nsString> & aExcludedFolders)
6463 {
6464  nsresult rv;
6465 
6466  nsCOMPtr<nsIPropertyBag2> deviceProperties;
6467  rv = GetPropertyBag(this, getter_AddRefs(deviceProperties));
6468  NS_ENSURE_SUCCESS(rv, rv);
6469 
6470  nsString excludedFolderStrings;
6471  rv = deviceProperties->GetPropertyAsAString(
6472  NS_LITERAL_STRING(SB_DEVICE_PROPERTY_EXCLUDED_FOLDERS),
6473  excludedFolderStrings);
6474  if (rv != NS_ERROR_NOT_AVAILABLE) {
6475  NS_ENSURE_SUCCESS(rv, rv);
6476  nsString_Split(excludedFolderStrings,
6477  NS_LITERAL_STRING(","),
6478  aExcludedFolders);
6479  }
6480 
6481  return NS_OK;
6482 }
6483 
6484 void
6486 {
6487 #ifdef PR_LOGGING
6488  LOG(("DEVICE FOLDERS:\n========================================\n"));
6489  mMediaFolderURLTable.EnumerateRead(LogDeviceFoldersEnum, nsnull);
6490 #endif
6491 }
6492 
6493 /* static */ PLDHashOperator
6494 sbBaseDevice::LogDeviceFoldersEnum(const unsigned int& aKey,
6495  nsString* aData,
6496  void* aUserArg)
6497 {
6498 #ifdef PR_LOGGING
6499  static const char* contentTypeNameList[] = {
6500  "CONTENT_UNKNOWN",
6501  "CONTENT_FILE",
6502  "CONTENT_FOLDER",
6503  "CONTENT_AUDIO",
6504  "CONTENT_IMAGE",
6505  "CONTENT_VIDEO",
6506  "CONTENT_PLAYLIST",
6507  "CONTENT_ALBUM"
6508  };
6509 
6510  // Get the content type name.
6511  const char* contentTypeName;
6512  char contentTypeString[32];
6513  if (aKey < NS_ARRAY_LENGTH(contentTypeNameList)) {
6514  contentTypeName = contentTypeNameList[aKey];
6515  }
6516  else {
6517  sprintf(contentTypeString, "0x%08x", aKey);
6518  contentTypeName = contentTypeString;
6519  }
6520 
6521  // Log folder.
6522  if (aData)
6523  LOG((" %s: %s\n", contentTypeName, NS_ConvertUTF16toUTF8(*aData).get()));
6524 #endif
6525 
6526  return PL_DHASH_NEXT;
6527 }
6528 
6529 PLDHashOperator
6531  nsCOMPtr<nsIMutableArray> & aItems,
6532  void * aUserArg)
6533 {
6534  NS_ENSURE_TRUE(aList, PL_DHASH_NEXT);
6535  NS_ENSURE_TRUE(aItems, PL_DHASH_NEXT);
6536 
6537  sbBaseDevice * const device =
6538  static_cast<sbBaseDevice*>(aUserArg);
6539 
6540  NS_ENSURE_TRUE(device->mLibraryListener, PL_DHASH_STOP);
6541 
6542  AutoListenerIgnore ignore(device);
6543 
6544  nsCOMPtr<nsISimpleEnumerator> enumerator;
6545  nsresult rv = aItems->Enumerate(getter_AddRefs(enumerator));
6546  NS_ENSURE_SUCCESS(rv, PL_DHASH_STOP);
6547 
6548  nsCOMPtr<sbIMediaList> list = do_QueryInterface(aList);
6549  if (list) {
6550  rv = list->RemoveSome(enumerator);
6551  NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT);
6552  }
6553 
6554  return PL_DHASH_NEXT;
6555 }
6556 
6558  mDevice(aDevice)
6559 {
6560  mDevice->SetIgnoreMediaListListeners(PR_TRUE);
6561  mDevice->mLibraryListener->SetIgnoreListener(PR_TRUE);
6562 }
6563 
6565 {
6566  mDevice->SetIgnoreMediaListListeners(PR_FALSE);
6567  mDevice->mLibraryListener->SetIgnoreListener(PR_FALSE);
6568 }
6569 
6570 nsresult
6572  sbIMediaList * aMediaList)
6573 {
6574  NS_ENSURE_ARG_POINTER(aChange);
6575  NS_ENSURE_ARG_POINTER(aMediaList);
6576 
6577  nsresult rv;
6578 
6579  nsCOMPtr<nsIArray> items;
6580  rv = aChange->GetListItems(getter_AddRefs(items));
6581  // If the change doesn't have list items then we use the source's items
6582  if (NS_FAILED(rv)) {
6583  nsCOMPtr<sbIMediaItem> srcItem;
6584  rv = aChange->GetSourceItem(getter_AddRefs(srcItem));
6585  NS_ENSURE_SUCCESS(rv, rv);
6586 
6587  nsCOMPtr<sbIMediaList> srcList = do_QueryInterface(srcItem, &rv);
6588 
6589  nsRefPtr<sbMediaListEnumArrayHelper> enumHelper =
6591  NS_ENSURE_TRUE(enumHelper, NS_ERROR_OUT_OF_MEMORY);
6592 
6593  rv = srcList->EnumerateAllItems(
6594  enumHelper,
6596  NS_ENSURE_SUCCESS(rv, rv);
6597 
6598  rv = enumHelper->GetMediaItemsArray(getter_AddRefs(items));
6599  NS_ENSURE_SUCCESS(rv, rv);
6600  }
6601  nsCOMPtr<nsISimpleEnumerator> enumerator;
6602  rv = items->Enumerate(getter_AddRefs(enumerator));
6603  NS_ENSURE_SUCCESS(rv, rv);
6604 
6605  rv = aMediaList->AddSome(enumerator);
6606  NS_ENSURE_SUCCESS(rv, rv);
6607 
6608  return NS_OK;
6609 }
6610 
6616  sbBaseDevice::Batch & aNonTranscodeItems,
6617  sbBaseDevice::Batch & aTranscodeItems,
6618  sbBaseDevice::Batch & aPlaylistItems)
6619 {
6620  const sbBaseDevice::TransferRequest::CompatibilityType NEEDS_TRANSCODING =
6622 
6623  const sbBaseDevice::Batch::const_iterator end = aInput.end();
6624  for (sbBaseDevice::Batch::const_iterator iter = aInput.begin();
6625  iter != end;
6626  ++iter)
6627  {
6628  // We only want to split out certain requests, things like mount and format
6629  // will stay in the non transcode items. This really isn't ideal, but
6630  // but with the way our current status reporting system works we have to
6631  // break things out. Typically requests like format and mount will never be
6632  // in a batch with another request.
6633  switch ((*iter)->GetType()) {
6640  sbBaseDevice::TransferRequest * request =
6641  static_cast<sbBaseDevice::TransferRequest*>(*iter);
6642  if (request->IsPlaylist()) {
6643  aPlaylistItems.push_back(*iter);
6644  }
6645  else if (request->destinationCompatibility == NEEDS_TRANSCODING) {
6646  aTranscodeItems.push_back(request);
6647  }
6648  else {
6649  aNonTranscodeItems.push_back(request);
6650  }
6651  }
6652  break;
6653  default: {
6654  aNonTranscodeItems.push_back(*iter);
6655  }
6656  break;
6657  }
6658  }
6659 }
6660 
function start(ch)
const unsigned short MANAGE_MOVE
friend class sbDeviceImages
Definition: sbBaseDevice.h:105
#define SB_DEVICE_PROPERTY_ACCESS_COMPATIBILITY_MUTABLE
nsCOMPtr< nsIWeakReference > mParentEventTarget
const unsigned short MANAGE_RENAME
nsCOMPtr< nsIFile > downloadedFile
Definition: sbBaseDevice.h:190
PRLock * mVolumeLock
Definition: sbBaseDevice.h:873
#define PREF_ORGANIZE_PREFIX
NS_IMETHOD GetPreference(const nsAString &aPrefName, nsIVariant **_retval)
nsresult GetLocalDeviceDir(nsIFile **aLocalDeviceDir)
const unsigned long DELETED
#define SB_DEVICE_PROPERTY_MUSIC_TOTAL_PLAY_TIME
nsresult UpdateVolumeNames()
nsresult HasPreference(nsAString &aPrefName, PRBool *aHasPreference)
const NS_APP_USER_PROFILE_50_DIR
#define PREF_DEVICE_LIBRARY_BASE
nsresult GetMediaInspector(sbIMediaInspector **_retval)
nsresult SyncProduceChangeset(TransferRequest *aRequest, sbILibraryChangeset **aExportChangeset, sbILibraryChangeset **aImportChangeset)
nsresult CreateAndDispatchEvent(PRUint32 aType, nsIVariant *aData, PRBool aAsync=PR_TRUE, sbIDeviceEventTarget *aTarget=nsnull)
NS_SCRIPTABLE NS_IMETHOD ResetWarningDialogs(void)
nsresult SetPreferenceInternalNoNotify(const nsAString &aPrefName, nsIVariant *aPrefValue, PRBool *aPrefChanged)
nsresult DownloadRequestItem(TransferRequest *aRequest, PRUint32 aBatchCount, sbDeviceStatusHelper *aDeviceStatusHelper)
return NS_OK
#define SB_DEVICE_PROPERTY_IMAGE_USED_SPACE
#define SB_PROPERTY_MEDIALISTNAME
static nsresult LinkCopy(sbIMediaItem *aOriginal, sbIMediaItem *aCopy)
Links a copy to its original. It will take into account the libraries the items belong to...
NS_IMETHOD Format(void)
nsresult SBGetLocalizedFormattedString(nsAString &aString, const nsAString &aKey, const nsTArray< nsString > &aParams, const nsAString &aDefault, class nsIStringBundle *aStringBundle)
nsresult GetLibraryPreferenceBase(sbIDeviceLibrary *aLibrary, nsAString &aPrefBase)
nsresult CreateDeviceLibrary(const nsAString &aId, nsIURI *aLibraryLocation, sbIDeviceLibrary **_retval)
nsresult BatchEnd()
nsAutoPtr< sbDeviceStatusHelper > mStatus
Definition: sbBaseDevice.h:689
#define SB_PROPERTY_TRACKTYPE
#define SB_DEVICE_PROPERTY_MUSIC_USED_SPACE
nsresult BatchBegin()
NS_DECL_ISUPPORTS static NS_DECL_SBIJOBPROGRESSLISTENER nsresult New(sbDeviceProgressListener **aDeviceProgressListener, PRMonitor *aCompleteNotifyMonitor=nsnull, sbDeviceStatusHelper *aDeviceStatusHelper=nsnull)
[UNIMPLEMENTED UNTIL AFTER 0.3]
nsresult DeferredSetupDevice()
nsresult GetExcludedFolders(nsTArray< nsString > &aExcludedFolders)
#define SB_PROPERTY_ORIGINURL
T find_iterator(T start, T end, T target)
NS_IMETHOD GetIsDirectTranscoding(PRBool *aIsDirect)
static TransferRequest * New(PRUint32 aType, sbIMediaItem *aItem, sbIMediaList *aList, PRUint32 aIndex, PRUint32 aOtherIndex, nsISupports *aData)
#define BYTES_PER_10MB
Interface used to enumerate the items in a media list.
nsresult SetupDevice()
nsresult CopyChangedMediaItemsToMediaList(sbILibraryChange *aChange, sbIMediaList *aMediaList)
readonly attribute sbIDeviceContent content
Definition: sbIDevice.idl:145
PRLock * mPreviousStateLock
Definition: sbBaseDevice.h:685
sbDownloadAutoComplete(sbDeviceStatusHelper *aStatus, sbDeviceStatusHelper::Operation aOperation, TransferRequest *aRequest, PRUint32 aBatchCount, sbBaseDevice *aDevice)
nsRefPtr< sbDeviceRequestThreadQueue > mRequestThreadQueue
Definition: sbBaseDevice.h:730
nsresult SyncMainLibraryFlag(sbIMediaItem *aMediaItem)
nsresult GetMusicFreeSpace(sbILibrary *aLibrary, PRInt64 *aFreeMusicSpace)
nsresult SB_NewTranscodeError(const nsAString &aMessageWithItem, const nsAString &aMessageWithoutItem, const nsAString &aDetails, const nsAString &aUri, sbIMediaItem *aMediaItem, sbITranscodeError **_retval)
#define SB_STORAGEPROPERTYUNITCONVERTER_CONTRACTID
nsIVariant * get() const
#define SB_DEFAULT_FILE_PERMISSIONS
Definition: sbFileUtils.h:123
const unsigned long EVENT_DEVICE_LIBRARY_ADDED
virtual nsresult UpdateProperty(const nsAString &aName)
const NS_PREFSERVICE_CONTRACTID
static nsresult SetLinkedSyncPartner(sbIDevice *aDevice)
NS_IMETHOD GetPrimaryLibrary(sbIDeviceLibrary **aPrimaryLibrary)
nsresult Init()
static nsRefPtr< sbBaseDeviceMediaListListener > void * aClosure
Definition: sbBaseDevice.h:441
nsresult ListenToMediaLists(sbILibrary *aLibrary)
#define PREF_ORGANIZE_ENABLED
NS_IMETHOD GetPreviousState(PRUint32 *aState)
nsresult GetDeviceWriteDestURI(sbIMediaItem *aWriteDstItem, nsIURI *aContentSrcBaseURI, nsIURI *aWriteSrcURI, nsIURI **aDestinationURI)
nsresult sbAppendnsIArray(nsIArray *aSrc, nsIMutableArray *aDest, PRBool aWeak=PR_FALSE, PRUint32 aElementsToCopy=0)
Definition: sbArrayUtils.h:87
virtual nsresult ChangeState(PRUint32 aState)
NS_SCRIPTABLE NS_IMETHOD SetWarningDialogEnabled(const nsAString &aWarning, PRBool aEnabled)
#define SB_DEVICE_PROPERTY_VIDEO_ITEM_COUNT
nsresult AddMediaLists(sbILibrary *aLibrary, nsIArray *aMediaLists)
NS_SCRIPTABLE NS_IMETHOD OpenInputStream(nsIURI *aURI, nsIInputStream **retval)