1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is the new Mozilla toolkit.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Benjamin Smedberg <bsmedberg@covad.net>
19 : * Portions created by the Initial Developer are Copyright (C) 2004
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "mozilla/Util.h"
39 :
40 : #include <stdio.h>
41 : #include <stdlib.h>
42 : #include "nsProfileLock.h"
43 :
44 : #ifdef XP_WIN
45 : #include <windows.h>
46 : #include <shlobj.h>
47 : #endif
48 : #ifdef XP_UNIX
49 : #include <unistd.h>
50 : #endif
51 :
52 : #include "nsIToolkitProfileService.h"
53 : #include "nsIToolkitProfile.h"
54 : #include "nsIFactory.h"
55 : #include "nsILocalFile.h"
56 : #include "nsISimpleEnumerator.h"
57 :
58 : #ifdef XP_MACOSX
59 : #include <CoreFoundation/CoreFoundation.h>
60 : #include "nsILocalFileMac.h"
61 : #endif
62 :
63 : #include "nsAppDirectoryServiceDefs.h"
64 : #include "nsXULAppAPI.h"
65 :
66 : #include "nsINIParser.h"
67 : #include "nsXREDirProvider.h"
68 : #include "nsAppRunner.h"
69 : #include "nsString.h"
70 : #include "nsReadableUtils.h"
71 : #include "nsNativeCharsetUtils.h"
72 :
73 : using namespace mozilla;
74 :
75 : class nsToolkitProfile : public nsIToolkitProfile
76 : {
77 : public:
78 : NS_DECL_ISUPPORTS
79 : NS_DECL_NSITOOLKITPROFILE
80 :
81 : friend class nsToolkitProfileService;
82 : nsCOMPtr<nsToolkitProfile> mNext;
83 : nsToolkitProfile *mPrev;
84 :
85 0 : ~nsToolkitProfile() { }
86 :
87 : private:
88 : nsToolkitProfile(const nsACString& aName,
89 : nsILocalFile* aRootDir,
90 : nsILocalFile* aLocalDir,
91 : nsToolkitProfile* aPrev);
92 :
93 : friend class nsToolkitProfileLock;
94 :
95 : nsCString mName;
96 : nsCOMPtr<nsILocalFile> mRootDir;
97 : nsCOMPtr<nsILocalFile> mLocalDir;
98 : nsIProfileLock* mLock;
99 : };
100 :
101 : class nsToolkitProfileLock : public nsIProfileLock
102 : {
103 : public:
104 : NS_DECL_ISUPPORTS
105 : NS_DECL_NSIPROFILELOCK
106 :
107 : nsresult Init(nsToolkitProfile* aProfile, nsIProfileUnlocker* *aUnlocker);
108 : nsresult Init(nsILocalFile* aDirectory, nsILocalFile* aLocalDirectory,
109 : nsIProfileUnlocker* *aUnlocker);
110 :
111 0 : nsToolkitProfileLock() { }
112 : ~nsToolkitProfileLock();
113 :
114 : private:
115 : nsCOMPtr<nsToolkitProfile> mProfile;
116 : nsCOMPtr<nsILocalFile> mDirectory;
117 : nsCOMPtr<nsILocalFile> mLocalDirectory;
118 :
119 : nsProfileLock mLock;
120 : };
121 :
122 : class nsToolkitProfileFactory : public nsIFactory
123 0 : {
124 : public:
125 : NS_DECL_ISUPPORTS
126 : NS_DECL_NSIFACTORY
127 : };
128 :
129 : class nsToolkitProfileService : public nsIToolkitProfileService
130 : {
131 : public:
132 : NS_DECL_ISUPPORTS
133 : NS_DECL_NSITOOLKITPROFILESERVICE
134 :
135 : private:
136 : friend class nsToolkitProfile;
137 : friend class nsToolkitProfileFactory;
138 : friend nsresult NS_NewToolkitProfileService(nsIToolkitProfileService**);
139 :
140 0 : nsToolkitProfileService() :
141 : mDirty(false),
142 : mStartWithLast(true),
143 0 : mStartOffline(false)
144 : {
145 0 : gService = this;
146 0 : }
147 0 : ~nsToolkitProfileService()
148 0 : {
149 0 : gService = nsnull;
150 0 : }
151 :
152 : NS_HIDDEN_(nsresult) Init();
153 :
154 : nsRefPtr<nsToolkitProfile> mFirst;
155 : nsCOMPtr<nsIToolkitProfile> mChosen;
156 : nsCOMPtr<nsILocalFile> mAppData;
157 : nsCOMPtr<nsILocalFile> mTempData;
158 : nsCOMPtr<nsILocalFile> mListFile;
159 : bool mDirty;
160 : bool mStartWithLast;
161 : bool mStartOffline;
162 :
163 : static nsToolkitProfileService *gService;
164 :
165 : class ProfileEnumerator : public nsISimpleEnumerator
166 : {
167 : public:
168 : NS_DECL_ISUPPORTS
169 : NS_DECL_NSISIMPLEENUMERATOR
170 :
171 0 : ProfileEnumerator(nsToolkitProfile *first)
172 0 : { mCurrent = first; }
173 : private:
174 0 : ~ProfileEnumerator() { }
175 : nsCOMPtr<nsToolkitProfile> mCurrent;
176 : };
177 : };
178 :
179 0 : nsToolkitProfile::nsToolkitProfile(const nsACString& aName,
180 : nsILocalFile* aRootDir,
181 : nsILocalFile* aLocalDir,
182 : nsToolkitProfile* aPrev) :
183 : mPrev(aPrev),
184 : mName(aName),
185 : mRootDir(aRootDir),
186 : mLocalDir(aLocalDir),
187 0 : mLock(nsnull)
188 : {
189 0 : NS_ASSERTION(aRootDir, "No file!");
190 :
191 0 : if (aPrev)
192 0 : aPrev->mNext = this;
193 : else
194 0 : nsToolkitProfileService::gService->mFirst = this;
195 0 : }
196 :
197 0 : NS_IMPL_ISUPPORTS1(nsToolkitProfile, nsIToolkitProfile)
198 :
199 : NS_IMETHODIMP
200 0 : nsToolkitProfile::GetRootDir(nsILocalFile* *aResult)
201 : {
202 0 : NS_ADDREF(*aResult = mRootDir);
203 0 : return NS_OK;
204 : }
205 :
206 : NS_IMETHODIMP
207 0 : nsToolkitProfile::GetLocalDir(nsILocalFile* *aResult)
208 : {
209 0 : NS_ADDREF(*aResult = mLocalDir);
210 0 : return NS_OK;
211 : }
212 :
213 : NS_IMETHODIMP
214 0 : nsToolkitProfile::GetName(nsACString& aResult)
215 : {
216 0 : aResult = mName;
217 0 : return NS_OK;
218 : }
219 :
220 : NS_IMETHODIMP
221 0 : nsToolkitProfile::SetName(const nsACString& aName)
222 : {
223 0 : NS_ASSERTION(nsToolkitProfileService::gService,
224 : "Where did my service go?");
225 :
226 0 : mName = aName;
227 0 : nsToolkitProfileService::gService->mDirty = true;
228 :
229 0 : return NS_OK;
230 : }
231 :
232 : NS_IMETHODIMP
233 0 : nsToolkitProfile::Remove(bool removeFiles)
234 : {
235 0 : NS_ASSERTION(nsToolkitProfileService::gService,
236 : "Whoa, my service is gone.");
237 :
238 0 : if (mLock)
239 0 : return NS_ERROR_FILE_IS_LOCKED;
240 :
241 0 : if (removeFiles) {
242 : bool equals;
243 0 : nsresult rv = mRootDir->Equals(mLocalDir, &equals);
244 0 : if (NS_FAILED(rv))
245 0 : return rv;
246 :
247 : // The root dir might contain the temp dir, so remove
248 : // the temp dir first.
249 0 : if (!equals)
250 0 : mLocalDir->Remove(true);
251 :
252 0 : mRootDir->Remove(true);
253 : }
254 :
255 0 : if (mPrev)
256 0 : mPrev->mNext = mNext;
257 : else
258 0 : nsToolkitProfileService::gService->mFirst = mNext;
259 :
260 0 : if (mNext)
261 0 : mNext->mPrev = mPrev;
262 :
263 0 : mPrev = nsnull;
264 0 : mNext = nsnull;
265 :
266 0 : if (nsToolkitProfileService::gService->mChosen == this)
267 0 : nsToolkitProfileService::gService->mChosen = nsnull;
268 :
269 0 : nsToolkitProfileService::gService->mDirty = true;
270 :
271 0 : return NS_OK;
272 : }
273 :
274 : NS_IMETHODIMP
275 0 : nsToolkitProfile::Lock(nsIProfileUnlocker* *aUnlocker, nsIProfileLock* *aResult)
276 : {
277 0 : if (mLock) {
278 0 : NS_ADDREF(*aResult = mLock);
279 0 : return NS_OK;
280 : }
281 :
282 0 : nsCOMPtr<nsToolkitProfileLock> lock = new nsToolkitProfileLock();
283 0 : if (!lock) return NS_ERROR_OUT_OF_MEMORY;
284 :
285 0 : nsresult rv = lock->Init(this, aUnlocker);
286 0 : if (NS_FAILED(rv)) return rv;
287 :
288 0 : NS_ADDREF(*aResult = lock);
289 0 : return NS_OK;
290 : }
291 :
292 0 : NS_IMPL_ISUPPORTS1(nsToolkitProfileLock, nsIProfileLock)
293 :
294 : nsresult
295 0 : nsToolkitProfileLock::Init(nsToolkitProfile* aProfile, nsIProfileUnlocker* *aUnlocker)
296 : {
297 : nsresult rv;
298 0 : rv = Init(aProfile->mRootDir, aProfile->mLocalDir, aUnlocker);
299 0 : if (NS_SUCCEEDED(rv))
300 0 : mProfile = aProfile;
301 :
302 0 : return rv;
303 : }
304 :
305 : nsresult
306 0 : nsToolkitProfileLock::Init(nsILocalFile* aDirectory, nsILocalFile* aLocalDirectory,
307 : nsIProfileUnlocker* *aUnlocker)
308 : {
309 : nsresult rv;
310 :
311 0 : rv = mLock.Lock(aDirectory, aUnlocker);
312 :
313 0 : if (NS_SUCCEEDED(rv)) {
314 0 : mDirectory = aDirectory;
315 0 : mLocalDirectory = aLocalDirectory;
316 : }
317 :
318 0 : return rv;
319 : }
320 :
321 : NS_IMETHODIMP
322 0 : nsToolkitProfileLock::GetDirectory(nsILocalFile* *aResult)
323 : {
324 0 : if (!mDirectory) {
325 0 : NS_ERROR("Not initialized, or unlocked!");
326 0 : return NS_ERROR_NOT_INITIALIZED;
327 : }
328 :
329 0 : NS_ADDREF(*aResult = mDirectory);
330 0 : return NS_OK;
331 : }
332 :
333 : NS_IMETHODIMP
334 0 : nsToolkitProfileLock::GetLocalDirectory(nsILocalFile* *aResult)
335 : {
336 0 : if (!mLocalDirectory) {
337 0 : NS_ERROR("Not initialized, or unlocked!");
338 0 : return NS_ERROR_NOT_INITIALIZED;
339 : }
340 :
341 0 : NS_ADDREF(*aResult = mLocalDirectory);
342 0 : return NS_OK;
343 : }
344 :
345 : NS_IMETHODIMP
346 0 : nsToolkitProfileLock::Unlock()
347 : {
348 0 : if (!mDirectory) {
349 0 : NS_ERROR("Unlocking a never-locked nsToolkitProfileLock!");
350 0 : return NS_ERROR_UNEXPECTED;
351 : }
352 :
353 0 : mLock.Unlock();
354 :
355 0 : if (mProfile) {
356 0 : mProfile->mLock = nsnull;
357 0 : mProfile = nsnull;
358 : }
359 0 : mDirectory = nsnull;
360 0 : mLocalDirectory = nsnull;
361 :
362 0 : return NS_OK;
363 : }
364 :
365 : NS_IMETHODIMP
366 0 : nsToolkitProfileLock::GetReplacedLockTime(PRInt64 *aResult)
367 : {
368 0 : mLock.GetReplacedLockTime(aResult);
369 0 : return NS_OK;
370 : }
371 :
372 0 : nsToolkitProfileLock::~nsToolkitProfileLock()
373 : {
374 0 : if (mDirectory) {
375 0 : Unlock();
376 : }
377 0 : }
378 :
379 : nsToolkitProfileService*
380 : nsToolkitProfileService::gService = nsnull;
381 :
382 0 : NS_IMPL_ISUPPORTS1(nsToolkitProfileService,
383 : nsIToolkitProfileService)
384 :
385 : nsresult
386 0 : nsToolkitProfileService::Init()
387 : {
388 0 : NS_ASSERTION(gDirServiceProvider, "No dirserviceprovider!");
389 : nsresult rv;
390 :
391 0 : rv = gDirServiceProvider->GetUserAppDataDirectory(getter_AddRefs(mAppData));
392 0 : NS_ENSURE_SUCCESS(rv, rv);
393 :
394 0 : rv = gDirServiceProvider->GetUserLocalDataDirectory(getter_AddRefs(mTempData));
395 0 : NS_ENSURE_SUCCESS(rv, rv);
396 :
397 0 : nsCOMPtr<nsIFile> listFile;
398 0 : rv = mAppData->Clone(getter_AddRefs(listFile));
399 0 : NS_ENSURE_SUCCESS(rv, rv);
400 :
401 0 : mListFile = do_QueryInterface(listFile);
402 0 : NS_ENSURE_TRUE(listFile, NS_ERROR_NO_INTERFACE);
403 :
404 0 : rv = mListFile->AppendNative(NS_LITERAL_CSTRING("profiles.ini"));
405 0 : NS_ENSURE_SUCCESS(rv, rv);
406 :
407 : bool exists;
408 0 : rv = mListFile->IsFile(&exists);
409 0 : if (NS_FAILED(rv) || !exists) {
410 0 : return NS_OK;
411 : }
412 :
413 : PRInt64 size;
414 0 : rv = listFile->GetFileSize(&size);
415 0 : if (NS_FAILED(rv) || !size) {
416 0 : return NS_OK;
417 : }
418 :
419 0 : nsINIParser parser;
420 0 : rv = parser.Init(mListFile);
421 : // Init does not fail on parsing errors, only on OOM/really unexpected
422 : // conditions.
423 0 : if (NS_FAILED(rv))
424 0 : return rv;
425 :
426 0 : nsCAutoString buffer;
427 0 : rv = parser.GetString("General", "StartWithLastProfile", buffer);
428 0 : if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("0"))
429 0 : mStartWithLast = false;
430 :
431 0 : nsToolkitProfile* currentProfile = nsnull;
432 :
433 0 : unsigned int c = 0;
434 0 : for (c = 0; true; ++c) {
435 0 : nsCAutoString profileID("Profile");
436 0 : profileID.AppendInt(c);
437 :
438 0 : rv = parser.GetString(profileID.get(), "IsRelative", buffer);
439 0 : if (NS_FAILED(rv)) break;
440 :
441 0 : bool isRelative = buffer.EqualsLiteral("1");
442 :
443 0 : nsCAutoString filePath;
444 :
445 0 : rv = parser.GetString(profileID.get(), "Path", filePath);
446 0 : if (NS_FAILED(rv)) {
447 0 : NS_ERROR("Malformed profiles.ini: Path= not found");
448 0 : continue;
449 : }
450 :
451 0 : rv = parser.GetString(profileID.get(), "Name", buffer);
452 0 : if (NS_FAILED(rv)) {
453 0 : NS_ERROR("Malformed profiles.ini: Name= not found");
454 0 : continue;
455 : }
456 :
457 0 : nsCOMPtr<nsILocalFile> rootDir;
458 0 : rv = NS_NewNativeLocalFile(EmptyCString(), true,
459 0 : getter_AddRefs(rootDir));
460 0 : NS_ENSURE_SUCCESS(rv, rv);
461 :
462 0 : if (isRelative) {
463 0 : rv = rootDir->SetRelativeDescriptor(mAppData, filePath);
464 : } else {
465 0 : rv = rootDir->SetPersistentDescriptor(filePath);
466 : }
467 0 : if (NS_FAILED(rv)) continue;
468 :
469 0 : nsCOMPtr<nsILocalFile> localDir;
470 0 : if (isRelative) {
471 0 : rv = NS_NewNativeLocalFile(EmptyCString(), true,
472 0 : getter_AddRefs(localDir));
473 0 : NS_ENSURE_SUCCESS(rv, rv);
474 :
475 0 : rv = localDir->SetRelativeDescriptor(mTempData, filePath);
476 : } else {
477 0 : localDir = rootDir;
478 : }
479 :
480 : currentProfile = new nsToolkitProfile(buffer,
481 : rootDir, localDir,
482 0 : currentProfile);
483 0 : NS_ENSURE_TRUE(currentProfile, NS_ERROR_OUT_OF_MEMORY);
484 :
485 0 : rv = parser.GetString(profileID.get(), "Default", buffer);
486 0 : if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("1"))
487 0 : mChosen = currentProfile;
488 : }
489 0 : if (!mChosen && mFirst && !mFirst->mNext) // only one profile
490 0 : mChosen = mFirst;
491 0 : return NS_OK;
492 : }
493 :
494 : NS_IMETHODIMP
495 0 : nsToolkitProfileService::SetStartWithLastProfile(bool aValue)
496 : {
497 0 : if (mStartWithLast != aValue) {
498 0 : mStartWithLast = aValue;
499 0 : mDirty = true;
500 : }
501 0 : return NS_OK;
502 : }
503 :
504 : NS_IMETHODIMP
505 0 : nsToolkitProfileService::GetStartWithLastProfile(bool *aResult)
506 : {
507 0 : *aResult = mStartWithLast;
508 0 : return NS_OK;
509 : }
510 :
511 : NS_IMETHODIMP
512 0 : nsToolkitProfileService::GetStartOffline(bool *aResult)
513 : {
514 0 : *aResult = mStartOffline;
515 0 : return NS_OK;
516 : }
517 :
518 : NS_IMETHODIMP
519 0 : nsToolkitProfileService::SetStartOffline(bool aValue)
520 : {
521 0 : mStartOffline = aValue;
522 0 : return NS_OK;
523 : }
524 :
525 : NS_IMETHODIMP
526 0 : nsToolkitProfileService::GetProfiles(nsISimpleEnumerator* *aResult)
527 : {
528 0 : *aResult = new ProfileEnumerator(this->mFirst);
529 0 : if (!*aResult)
530 0 : return NS_ERROR_OUT_OF_MEMORY;
531 :
532 0 : NS_ADDREF(*aResult);
533 0 : return NS_OK;
534 : }
535 :
536 0 : NS_IMPL_ISUPPORTS1(nsToolkitProfileService::ProfileEnumerator,
537 : nsISimpleEnumerator)
538 :
539 : NS_IMETHODIMP
540 0 : nsToolkitProfileService::ProfileEnumerator::HasMoreElements(bool* aResult)
541 : {
542 0 : *aResult = mCurrent ? true : false;
543 0 : return NS_OK;
544 : }
545 :
546 : NS_IMETHODIMP
547 0 : nsToolkitProfileService::ProfileEnumerator::GetNext(nsISupports* *aResult)
548 : {
549 0 : if (!mCurrent) return NS_ERROR_FAILURE;
550 :
551 0 : NS_ADDREF(*aResult = mCurrent);
552 :
553 0 : mCurrent = mCurrent->mNext;
554 0 : return NS_OK;
555 : }
556 :
557 : NS_IMETHODIMP
558 0 : nsToolkitProfileService::GetSelectedProfile(nsIToolkitProfile* *aResult)
559 : {
560 0 : if (!mChosen && mFirst && !mFirst->mNext) // only one profile
561 0 : mChosen = mFirst;
562 :
563 0 : if (!mChosen) return NS_ERROR_FAILURE;
564 :
565 0 : NS_ADDREF(*aResult = mChosen);
566 0 : return NS_OK;
567 : }
568 :
569 : NS_IMETHODIMP
570 0 : nsToolkitProfileService::SetSelectedProfile(nsIToolkitProfile* aProfile)
571 : {
572 0 : if (mChosen != aProfile) {
573 0 : mChosen = aProfile;
574 0 : mDirty = true;
575 : }
576 0 : return NS_OK;
577 : }
578 :
579 : NS_IMETHODIMP
580 0 : nsToolkitProfileService::GetProfileByName(const nsACString& aName,
581 : nsIToolkitProfile* *aResult)
582 : {
583 0 : nsToolkitProfile* curP = mFirst;
584 0 : while (curP) {
585 0 : if (curP->mName.Equals(aName)) {
586 0 : NS_ADDREF(*aResult = curP);
587 0 : return NS_OK;
588 : }
589 0 : curP = curP->mNext;
590 : }
591 :
592 0 : return NS_ERROR_FAILURE;
593 : }
594 :
595 : NS_IMETHODIMP
596 0 : nsToolkitProfileService::LockProfilePath(nsILocalFile* aDirectory,
597 : nsILocalFile* aLocalDirectory,
598 : nsIProfileLock* *aResult)
599 : {
600 0 : return NS_LockProfilePath(aDirectory, aLocalDirectory, nsnull, aResult);
601 : }
602 :
603 : nsresult
604 0 : NS_LockProfilePath(nsILocalFile* aPath, nsILocalFile* aTempPath,
605 : nsIProfileUnlocker* *aUnlocker, nsIProfileLock* *aResult)
606 : {
607 0 : nsCOMPtr<nsToolkitProfileLock> lock = new nsToolkitProfileLock();
608 0 : if (!lock) return NS_ERROR_OUT_OF_MEMORY;
609 :
610 0 : nsresult rv = lock->Init(aPath, aTempPath, aUnlocker);
611 0 : if (NS_FAILED(rv)) return rv;
612 :
613 0 : NS_ADDREF(*aResult = lock);
614 0 : return NS_OK;
615 : }
616 :
617 : static const char kTable[] =
618 : { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
619 : 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
620 : '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' };
621 :
622 0 : static void SaltProfileName(nsACString& aName)
623 : {
624 : double fpTime;
625 0 : LL_L2D(fpTime, PR_Now());
626 :
627 : // use 1e-6, granularity of PR_Now() on the mac is seconds
628 0 : srand((uint)(fpTime * 1e-6 + 0.5));
629 :
630 : char salt[9];
631 :
632 : int i;
633 0 : for (i = 0; i < 8; ++i)
634 0 : salt[i] = kTable[rand() % ArrayLength(kTable)];
635 :
636 0 : salt[8] = '.';
637 :
638 0 : aName.Insert(salt, 0, 9);
639 0 : }
640 :
641 : NS_IMETHODIMP
642 0 : nsToolkitProfileService::CreateProfile(nsILocalFile* aRootDir,
643 : nsILocalFile* aLocalDir,
644 : const nsACString& aName,
645 : nsIToolkitProfile* *aResult)
646 : {
647 : nsresult rv;
648 :
649 0 : rv = GetProfileByName(aName, aResult);
650 0 : if (NS_SUCCEEDED(rv)) return rv;
651 :
652 0 : nsCOMPtr<nsILocalFile> rootDir (aRootDir);
653 :
654 0 : nsCAutoString dirName;
655 0 : if (!rootDir) {
656 0 : nsCOMPtr<nsIFile> file;
657 : bool dummy;
658 : rv = gDirServiceProvider->GetFile(NS_APP_USER_PROFILES_ROOT_DIR, &dummy,
659 0 : getter_AddRefs(file));
660 0 : NS_ENSURE_SUCCESS(rv, rv);
661 :
662 0 : rootDir = do_QueryInterface(file);
663 0 : NS_ENSURE_TRUE(rootDir, NS_ERROR_UNEXPECTED);
664 :
665 0 : dirName = aName;
666 0 : SaltProfileName(dirName);
667 :
668 0 : if (NS_IsNativeUTF8()) {
669 0 : rootDir->AppendNative(dirName);
670 : } else {
671 0 : rootDir->Append(NS_ConvertUTF8toUTF16(dirName));
672 : }
673 : }
674 :
675 0 : nsCOMPtr<nsILocalFile> localDir (aLocalDir);
676 :
677 0 : if (!localDir) {
678 0 : if (aRootDir) {
679 0 : localDir = aRootDir;
680 : }
681 : else {
682 0 : nsCOMPtr<nsIFile> file;
683 : bool dummy;
684 : rv = gDirServiceProvider->GetFile(NS_APP_USER_PROFILES_LOCAL_ROOT_DIR,
685 0 : &dummy, getter_AddRefs(file));
686 0 : NS_ENSURE_SUCCESS(rv, rv);
687 :
688 0 : localDir = do_QueryInterface(file);
689 0 : NS_ENSURE_TRUE(localDir, NS_ERROR_UNEXPECTED);
690 :
691 : // use same salting
692 0 : if (NS_IsNativeUTF8()) {
693 0 : localDir->AppendNative(dirName);
694 : } else {
695 0 : localDir->Append(NS_ConvertUTF8toUTF16(dirName));
696 : }
697 : }
698 : }
699 :
700 : bool exists;
701 0 : rv = rootDir->Exists(&exists);
702 0 : NS_ENSURE_SUCCESS(rv, rv);
703 :
704 0 : if (exists) {
705 0 : rv = rootDir->IsDirectory(&exists);
706 0 : NS_ENSURE_SUCCESS(rv, rv);
707 :
708 0 : if (!exists)
709 0 : return NS_ERROR_FILE_NOT_DIRECTORY;
710 : }
711 : else {
712 0 : nsCOMPtr<nsIFile> profileDefaultsDir;
713 0 : nsCOMPtr<nsIFile> profileDirParent;
714 0 : nsAutoString profileDirName;
715 :
716 0 : rv = rootDir->GetParent(getter_AddRefs(profileDirParent));
717 0 : NS_ENSURE_SUCCESS(rv, rv);
718 :
719 0 : rv = rootDir->GetLeafName(profileDirName);
720 0 : NS_ENSURE_SUCCESS(rv, rv);
721 :
722 : bool dummy;
723 : rv = gDirServiceProvider->GetFile(NS_APP_PROFILE_DEFAULTS_50_DIR, &dummy,
724 0 : getter_AddRefs(profileDefaultsDir));
725 :
726 0 : if (NS_SUCCEEDED(rv))
727 0 : rv = profileDefaultsDir->CopyTo(profileDirParent,
728 0 : profileDirName);
729 0 : if (NS_FAILED(rv)) {
730 : // if copying failed, lets just ensure that the profile directory exists.
731 0 : rv = rootDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
732 0 : NS_ENSURE_SUCCESS(rv, rv);
733 : }
734 0 : rv = rootDir->SetPermissions(0700);
735 : #ifndef ANDROID
736 : // If the profile is on the sdcard, this will fail but its non-fatal
737 0 : NS_ENSURE_SUCCESS(rv, rv);
738 : #endif
739 : }
740 :
741 0 : rv = localDir->Exists(&exists);
742 0 : NS_ENSURE_SUCCESS(rv, rv);
743 :
744 0 : if (!exists) {
745 0 : rv = localDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
746 0 : NS_ENSURE_SUCCESS(rv, rv);
747 : }
748 :
749 0 : nsToolkitProfile* last = mFirst;
750 0 : if (last) {
751 0 : while (last->mNext)
752 0 : last = last->mNext;
753 : }
754 :
755 : nsCOMPtr<nsIToolkitProfile> profile =
756 0 : new nsToolkitProfile(aName, rootDir, localDir, last);
757 0 : if (!profile) return NS_ERROR_OUT_OF_MEMORY;
758 :
759 0 : NS_ADDREF(*aResult = profile);
760 0 : return NS_OK;
761 : }
762 :
763 : NS_IMETHODIMP
764 0 : nsToolkitProfileService::GetProfileCount(PRUint32 *aResult)
765 : {
766 0 : if (!mFirst)
767 0 : *aResult = 0;
768 0 : else if (! mFirst->mNext)
769 0 : *aResult = 1;
770 : else
771 0 : *aResult = 2;
772 :
773 0 : return NS_OK;
774 : }
775 :
776 : NS_IMETHODIMP
777 0 : nsToolkitProfileService::Flush()
778 : {
779 : // Errors during writing might cause unhappy semi-written files.
780 : // To avoid this, write the entire thing to a buffer, then write
781 : // that buffer to disk.
782 :
783 : nsresult rv;
784 0 : PRUint32 pCount = 0;
785 : nsToolkitProfile *cur;
786 :
787 0 : for (cur = mFirst; cur != nsnull; cur = cur->mNext)
788 0 : ++pCount;
789 :
790 : PRUint32 length;
791 0 : nsAutoArrayPtr<char> buffer (new char[100+MAXPATHLEN*pCount]);
792 :
793 0 : NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY);
794 :
795 0 : char *end = buffer;
796 :
797 : end += sprintf(end,
798 : "[General]\n"
799 : "StartWithLastProfile=%s\n\n",
800 0 : mStartWithLast ? "1" : "0");
801 :
802 0 : nsCAutoString path;
803 0 : cur = mFirst;
804 0 : pCount = 0;
805 :
806 0 : while (cur) {
807 : // if the profile dir is relative to appdir...
808 : bool isRelative;
809 0 : rv = mAppData->Contains(cur->mRootDir, true, &isRelative);
810 0 : if (NS_SUCCEEDED(rv) && isRelative) {
811 : // we use a relative descriptor
812 0 : rv = cur->mRootDir->GetRelativeDescriptor(mAppData, path);
813 : } else {
814 : // otherwise, a persistent descriptor
815 0 : rv = cur->mRootDir->GetPersistentDescriptor(path);
816 0 : NS_ENSURE_SUCCESS(rv, rv);
817 : }
818 :
819 : end += sprintf(end,
820 : "[Profile%u]\n"
821 : "Name=%s\n"
822 : "IsRelative=%s\n"
823 : "Path=%s\n",
824 : pCount, cur->mName.get(),
825 0 : isRelative ? "1" : "0", path.get());
826 :
827 0 : if (mChosen == cur) {
828 0 : end += sprintf(end, "Default=1\n");
829 : }
830 :
831 0 : end += sprintf(end, "\n");
832 :
833 0 : cur = cur->mNext;
834 0 : ++pCount;
835 : }
836 :
837 : FILE* writeFile;
838 0 : rv = mListFile->OpenANSIFileDesc("w", &writeFile);
839 0 : NS_ENSURE_SUCCESS(rv, rv);
840 :
841 0 : if (buffer) {
842 0 : length = end - buffer;
843 :
844 0 : if (fwrite(buffer, sizeof(char), length, writeFile) != length) {
845 0 : fclose(writeFile);
846 0 : return NS_ERROR_UNEXPECTED;
847 : }
848 : }
849 :
850 0 : fclose(writeFile);
851 0 : return NS_OK;
852 : }
853 :
854 0 : NS_IMPL_ISUPPORTS1(nsToolkitProfileFactory, nsIFactory)
855 :
856 : NS_IMETHODIMP
857 0 : nsToolkitProfileFactory::CreateInstance(nsISupports* aOuter, const nsID& aIID,
858 : void** aResult)
859 : {
860 0 : if (aOuter)
861 0 : return NS_ERROR_NO_AGGREGATION;
862 :
863 : nsCOMPtr<nsIToolkitProfileService> profileService =
864 0 : nsToolkitProfileService::gService;
865 0 : if (!profileService) {
866 0 : nsresult rv = NS_NewToolkitProfileService(getter_AddRefs(profileService));
867 0 : if (NS_FAILED(rv))
868 0 : return rv;
869 : }
870 0 : return profileService->QueryInterface(aIID, aResult);
871 : }
872 :
873 : NS_IMETHODIMP
874 0 : nsToolkitProfileFactory::LockFactory(bool aVal)
875 : {
876 0 : return NS_OK;
877 : }
878 :
879 : nsresult
880 0 : NS_NewToolkitProfileFactory(nsIFactory* *aResult)
881 : {
882 0 : *aResult = new nsToolkitProfileFactory();
883 0 : if (!*aResult)
884 0 : return NS_ERROR_OUT_OF_MEMORY;
885 :
886 0 : NS_ADDREF(*aResult);
887 0 : return NS_OK;
888 : }
889 :
890 : nsresult
891 0 : NS_NewToolkitProfileService(nsIToolkitProfileService* *aResult)
892 : {
893 0 : nsToolkitProfileService* profileService = new nsToolkitProfileService();
894 0 : if (!profileService)
895 0 : return NS_ERROR_OUT_OF_MEMORY;
896 0 : nsresult rv = profileService->Init();
897 0 : if (NS_FAILED(rv)) {
898 0 : NS_ERROR("nsToolkitProfileService::Init failed!");
899 0 : delete profileService;
900 0 : return rv;
901 : }
902 :
903 0 : NS_ADDREF(*aResult = profileService);
904 0 : return NS_OK;
905 : }
906 :
907 : nsresult
908 4158 : XRE_GetFileFromPath(const char *aPath, nsILocalFile* *aResult)
909 : {
910 : #if defined(XP_MACOSX)
911 : PRInt32 pathLen = strlen(aPath);
912 : if (pathLen > MAXPATHLEN)
913 : return NS_ERROR_INVALID_ARG;
914 :
915 : CFURLRef fullPath =
916 : CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8 *) aPath,
917 : pathLen, true);
918 : if (!fullPath)
919 : return NS_ERROR_FAILURE;
920 :
921 : nsCOMPtr<nsILocalFile> lf;
922 : nsresult rv = NS_NewNativeLocalFile(EmptyCString(), true,
923 : getter_AddRefs(lf));
924 : if (NS_SUCCEEDED(rv)) {
925 : nsCOMPtr<nsILocalFileMac> lfMac = do_QueryInterface(lf, &rv);
926 : if (NS_SUCCEEDED(rv)) {
927 : rv = lfMac->InitWithCFURL(fullPath);
928 : if (NS_SUCCEEDED(rv))
929 : NS_ADDREF(*aResult = lf);
930 : }
931 : }
932 : CFRelease(fullPath);
933 : return rv;
934 :
935 : #elif defined(XP_UNIX)
936 : char fullPath[MAXPATHLEN];
937 :
938 4158 : if (!realpath(aPath, fullPath))
939 0 : return NS_ERROR_FAILURE;
940 :
941 4158 : return NS_NewNativeLocalFile(nsDependentCString(fullPath), true,
942 4158 : aResult);
943 : #elif defined(XP_OS2)
944 : char fullPath[MAXPATHLEN];
945 :
946 : if (!realpath(aPath, fullPath))
947 : return NS_ERROR_FAILURE;
948 :
949 : // realpath on OS/2 returns a unix-ized path, so re-native-ize
950 : for (char* ptr = strchr(fullPath, '/'); ptr; ptr = strchr(ptr, '/'))
951 : *ptr = '\\';
952 :
953 : return NS_NewNativeLocalFile(nsDependentCString(fullPath), true,
954 : aResult);
955 :
956 : #elif defined(XP_WIN)
957 : WCHAR fullPath[MAXPATHLEN];
958 :
959 : if (!_wfullpath(fullPath, NS_ConvertUTF8toUTF16(aPath).get(), MAXPATHLEN))
960 : return NS_ERROR_FAILURE;
961 :
962 : return NS_NewLocalFile(nsDependentString(fullPath), true,
963 : aResult);
964 :
965 : #else
966 : #error Platform-specific logic needed here.
967 : #endif
968 : }
|