bug 393626. fixing a bug causing us to always append the system default font to the...
[mozilla-central.git] / xpinstall / src / nsRegisterItem.cpp
blob5ea2431a51a79bff3f2b7f8128cba1f8ba329b47
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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.
15 * The Original Code is Mozilla Communicator client code, released
16 * March 31, 1998.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 2000
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Daniel Veditz <dveditz@netscape.com>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "prprf.h"
41 #include "nsCRT.h"
42 #include "nsRegisterItem.h"
43 #include "nsInstallResources.h"
44 #include "nsNetUtil.h"
45 #include "nsXPIDLString.h"
46 #include "nsReadableUtils.h"
47 #include "nsInstallTrigger.h"
48 #include "nsIChromeRegistry.h"
49 #include "nsIDirectoryService.h"
50 #include "nsDirectoryServiceDefs.h"
51 #include "nsAppDirectoryServiceDefs.h"
52 #include "nsNativeCharsetUtils.h"
54 nsRegisterItem:: nsRegisterItem( nsInstall* inInstall,
55 nsIFile* chrome,
56 PRUint32 chromeType,
57 const char* path )
58 : nsInstallObject(inInstall), mChrome(chrome), mChromeType(chromeType), mPath(path)
60 MOZ_COUNT_CTOR(nsRegisterItem);
64 nsRegisterItem::~nsRegisterItem()
66 MOZ_COUNT_DTOR(nsRegisterItem);
69 #if defined(XP_WIN)
70 #include <windows.h>
71 #endif
73 static nsresult
74 hack_nsIFile2URL(nsIFile* file, char * *aURL)
76 nsresult rv;
77 nsCAutoString ePath;
78 rv = file->GetNativePath(ePath);
79 if (NS_FAILED(rv)) return rv;
80 #if defined(XP_WIN) || defined(XP_OS2)
81 // Replace \ with / to convert to an url
82 char* s;
83 ePath.BeginWriting(s);
84 while (*s) {
85 #ifndef XP_OS2
86 // We need to call IsDBCSLeadByte because
87 // Japanese windows can have 0x5C in the sencond byte
88 // of a Japanese character, for example 0x8F 0x5C is
89 // one Japanese character
90 if(::IsDBCSLeadByte(*s) && *(s+1) != nsnull) {
91 s++;
92 } else
93 #endif
94 if (*s == '\\')
95 *s = '/';
96 s++;
98 #endif
99 // Escape the path with the directory mask
100 nsCAutoString tmp(ePath);
101 tmp.ReplaceChar(":", '|');
102 nsCAutoString escPath("file://");
103 escPath += tmp;
104 // rv = nsURLEscape(ePath,nsIIOService::url_Directory + nsIIOService::url_Forced, escPath);
105 // if (NS_SUCCEEDED(rv)) {
106 PRBool dir;
107 rv = file->IsDirectory(&dir);
108 if (NS_SUCCEEDED(rv) && dir && escPath[escPath.Length() - 1] != '/') {
109 // make sure we have a trailing slash
110 escPath += "/";
112 *aURL = ToNewCString(escPath);
113 if (*aURL == nsnull) {
114 return NS_ERROR_OUT_OF_MEMORY;
116 // }
117 return rv;
120 void nsRegisterItem::LogErrorWithFilename(const nsAString& aMessage, nsresult code, nsILocalFile* localFile)
122 nsCAutoString path;
123 nsAutoString unipath;
125 LogError(aMessage, code);
126 localFile->GetNativePath(path);
127 if(NS_SUCCEEDED(NS_CopyNativeToUnicode(path, unipath)))
128 mInstall->LogComment(unipath);
131 void nsRegisterItem::LogError(const nsAString& aMessage, nsresult code)
133 char resultString[12];
135 PR_snprintf(resultString, 12, "0x%lx", code);
136 mInstall->LogComment(aMessage + NS_LITERAL_STRING(" - nsresult code: ") +
137 NS_ConvertASCIItoUTF16(resultString));
140 PRInt32 nsRegisterItem::Prepare()
142 // The chrome must exist
143 PRBool exists;
144 nsresult rv = mChrome->Exists(&exists);
145 if (NS_FAILED(rv))
146 return nsInstall::UNEXPECTED_ERROR;
147 if (!exists)
148 return nsInstall::DOES_NOT_EXIST;
151 // Are we dealing with a directory (flat chrome) or an archive?
152 PRBool isDir;
153 rv = mChrome->IsDirectory(&isDir);
154 if (NS_FAILED(rv))
155 return nsInstall::UNEXPECTED_ERROR;
158 // Can we construct a resource: URL or do we need a file: URL instead?
159 // find the xpcom directory and see if mChrome is a child
160 PRBool isChild = PR_FALSE;
161 mProgDir = nsSoftwareUpdate::GetProgramDirectory();
162 if (!mProgDir)
164 // not in the wizard, so ask the directory service where it is
165 nsCOMPtr<nsIProperties> dirService(
166 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
167 if(NS_SUCCEEDED(rv))
169 NS_ASSERTION(dirService,"directory service lied to us");
170 rv = dirService->Get(NS_XPCOM_CURRENT_PROCESS_DIR,
171 NS_GET_IID(nsIFile), getter_AddRefs(mProgDir));
174 if (NS_SUCCEEDED(rv))
176 NS_ASSERTION(mProgDir,"NS_SUCCESS but no mProgDir");
177 rv = mProgDir->Contains(mChrome, PR_TRUE, &isChild);
178 if (NS_FAILED(rv))
179 return nsInstall::UNEXPECTED_ERROR;
181 else
182 return nsInstall::UNEXPECTED_ERROR;
185 // Either way we need the file: URL to the chrome
186 nsXPIDLCString localURL;
187 rv = GetURLFromIFile( mChrome, getter_Copies(localURL) );
188 if (NS_FAILED(rv))
189 return nsInstall::UNEXPECTED_ERROR;
191 // see what kind of URL we have to construct
192 if (!isChild)
194 // Not relative so use the file:// URL we got above
195 PRInt32 urlLen = strlen(localURL) + mPath.Length();
197 if (isDir)
199 // "flat" chrome, urlLen is suffient
200 mURL.SetCapacity( urlLen );
202 else
204 // archive, add room for jar: syntax (over by one, but harmless)
205 mURL.SetCapacity( urlLen + sizeof("jar:") + sizeof('!') );
206 mURL = "jar:";
208 mURL.Append(localURL);
210 else
212 // we can construct a resource: URL to chrome in a subdir
213 nsXPIDLCString binURL;
214 rv = GetURLFromIFile( mProgDir, getter_Copies(binURL) );
215 if (NS_FAILED(rv))
216 return nsInstall::UNEXPECTED_ERROR;
218 PRInt32 binLen = strlen(binURL);
219 const char *subURL = localURL + binLen;
220 PRInt32 padding = sizeof("resource:/") + sizeof("jar:!/");
222 mURL.SetCapacity( strlen(subURL) + mPath.Length() + padding );
224 if (!isDir)
225 mURL = "jar:";
227 mURL.Append("resource:/");
228 mURL.Append(subURL);
232 if (!isDir)
234 // need jar: URL closing bang-slash
235 mURL.Append("!/");
237 else
239 // Necko should already slash-terminate directory file:// URLs
240 NS_ASSERTION(mURL[mURL.Length()-1] == '/', "Necko changed the rules");
243 // add on "extra" subpath to new content.rdf
244 mURL.Append(mPath);
246 return nsInstall::SUCCESS;
249 PRInt32 nsRegisterItem::Complete()
251 nsresult rv = NS_OK;
252 PRInt32 result = nsInstall::SUCCESS;
253 CHROMEREG_IFACE* reg = mInstall->GetChromeRegistry();
254 #ifndef MOZ_XUL_APP
255 PRBool isProfile = mChromeType & CHROME_PROFILE;
256 #endif
258 if ( reg && !(mChromeType & CHROME_DELAYED) )
260 #ifdef MOZ_XUL_APP
261 nsCOMPtr<nsIURI> baseuri;
262 rv = NS_NewURI(getter_AddRefs(baseuri), mURL);
263 if (NS_FAILED(rv)) {
264 LogError(NS_LITERAL_STRING("NS_NewURI failed."), rv);
266 else {
267 nsCOMPtr<nsIURI> manifesturi;
268 rv = NS_NewURI(getter_AddRefs(manifesturi),
269 NS_LITERAL_CSTRING("resource:///chrome/xpinstall.manifest"));
270 if (NS_FAILED(rv)) {
271 LogError(NS_LITERAL_STRING("NS_NewURI failed."), rv);
273 else {
274 PRBool skinOnly = (mChromeType & CHROME_ALL) == CHROME_SKIN;
275 rv = reg->ProcessContentsManifest(baseuri, manifesturi,
276 baseuri, PR_TRUE,
277 skinOnly);
278 if (NS_FAILED(rv)) {
279 LogError(NS_LITERAL_STRING("ProcessContentsManifest failed."), rv);
281 reg->CheckForNewChrome();
284 #else
285 // We can register right away
286 if (mChromeType & CHROME_SKIN)
287 rv = reg->InstallSkin(mURL.get(), isProfile, PR_TRUE);
288 if (NS_FAILED(rv)) {
289 LogError(NS_LITERAL_STRING("InstallSkin() failed."), rv);
292 if (NS_SUCCEEDED(rv) && (mChromeType & CHROME_LOCALE))
293 rv = reg->InstallLocale(mURL.get(), isProfile);
294 if (NS_FAILED(rv)) {
295 LogError(NS_LITERAL_STRING("InstallLocale() failed."), rv);
298 if (NS_SUCCEEDED(rv) && (mChromeType & CHROME_CONTENT))
299 rv = reg->InstallPackage(mURL.get(), isProfile);
300 if (NS_FAILED(rv)) {
301 LogError(NS_LITERAL_STRING("InstallPackage() failed."), rv);
303 #endif
305 else
307 // Either script asked for delayed chrome or we can't find
308 // the chrome registry to do it now.
310 // construct a reference to the magic file
311 PRFileDesc* fd = nsnull;
312 nsCOMPtr<nsIFile> tmp;
313 PRBool bExists = PR_FALSE;
314 if (!nsSoftwareUpdate::GetProgramDirectory()) // not in the stub installer
316 nsCOMPtr<nsIProperties> directoryService =
317 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
318 if (NS_FAILED(rv)) {
319 LogError(NS_LITERAL_STRING("failed to get directory service."), rv);
321 if (NS_SUCCEEDED(rv) && directoryService)
323 rv = directoryService->Get(NS_APP_CHROME_DIR,
324 NS_GET_IID(nsIFile),
325 getter_AddRefs(tmp));
326 if(NS_FAILED(rv))
328 LogError(NS_LITERAL_STRING("failed get application chrome directory."), rv);
329 result = nsInstall::CHROME_REGISTRY_ERROR;
330 return result;
334 else
336 rv = nsSoftwareUpdate::GetProgramDirectory()->Clone(getter_AddRefs(tmp));
338 if (NS_SUCCEEDED(rv))
340 tmp->AppendNative(INSTALL_CHROME_DIR);
341 } else {
342 LogError(NS_LITERAL_STRING("failed to clone program directory. (not critical)"), rv);
345 nsCOMPtr<nsILocalFile> startupFile( do_QueryInterface(tmp, &rv) );
347 if (NS_SUCCEEDED(rv))
349 rv = startupFile->Exists(&bExists);
350 if(NS_FAILED(rv))
352 LogErrorWithFilename(NS_LITERAL_STRING("directory existance check failed."), rv, startupFile);
354 if (NS_SUCCEEDED(rv) && !bExists)
355 rv = startupFile->Create(nsIFile::DIRECTORY_TYPE, 0755);
356 if (NS_SUCCEEDED(rv))
358 rv = startupFile->AppendNative(NS_LITERAL_CSTRING("installed-chrome.txt"));
359 if (NS_SUCCEEDED(rv))
361 rv = startupFile->OpenNSPRFileDesc(
362 PR_CREATE_FILE | PR_WRONLY,
363 0744,
364 &fd);
365 if(NS_FAILED(rv))
367 LogErrorWithFilename(NS_LITERAL_STRING("opening of installed-chrome.txt failed."), rv, startupFile);
369 } else {
370 LogError(NS_LITERAL_STRING("String append failed."), rv);
372 } else {
373 LogErrorWithFilename(NS_LITERAL_STRING("startup directory creation failed."), rv, startupFile);
377 if ( NS_SUCCEEDED(rv) && fd )
379 PR_Seek(fd, 0, PR_SEEK_END);
380 const char* location = (mChromeType & CHROME_PROFILE) ? "profile" : "install";
382 if (NS_SUCCEEDED(rv)/* && path*/)
384 PRInt32 written, actual;
385 char* installStr = nsnull;
387 // this looks redundant, but a single registerChrome()
388 // call can register all three types.
389 if (mChromeType & CHROME_SKIN)
391 installStr = PR_smprintf("skin,%s,url,%s\n",
392 location, mURL.get());
393 if (installStr)
395 actual = strlen(installStr);
396 written = PR_Write(fd, installStr, actual);
397 if ( written != actual )
399 LogErrorWithFilename(NS_LITERAL_STRING("writing to installed-chrome.txt failed."), rv, startupFile);
400 result = nsInstall::CHROME_REGISTRY_ERROR;
402 PR_smprintf_free(installStr);
404 else
405 result = nsInstall::OUT_OF_MEMORY;
408 if (mChromeType & CHROME_LOCALE)
410 installStr = PR_smprintf("locale,%s,url,%s\n",
411 location, mURL.get());
412 if (installStr)
414 actual = strlen(installStr);
415 written = PR_Write(fd, installStr, actual);
416 if ( written != actual )
418 LogErrorWithFilename(NS_LITERAL_STRING("writing to installed-chrome.txt failed."), rv, startupFile);
419 result = nsInstall::CHROME_REGISTRY_ERROR;
421 PR_smprintf_free(installStr);
423 else
424 result = nsInstall::OUT_OF_MEMORY;
427 if (mChromeType & CHROME_CONTENT)
429 installStr = PR_smprintf("content,%s,url,%s\n",
430 location, mURL.get());
431 if (installStr)
433 actual = strlen(installStr);
434 written = PR_Write(fd, installStr, actual);
435 if ( written != actual )
437 LogErrorWithFilename(NS_LITERAL_STRING("writing to installed-chrome.txt failed."), rv, startupFile);
438 result = nsInstall::CHROME_REGISTRY_ERROR;
440 PR_smprintf_free(installStr);
442 else
443 result = nsInstall::OUT_OF_MEMORY;
446 PR_Close(fd);
448 #ifdef MOZ_XUL_APP
449 // app-chrome.manifest is not regenerated if it exists
450 rv = startupFile->SetNativeLeafName(NS_LITERAL_CSTRING("app-chrome.manifest"));
451 if (NS_SUCCEEDED(rv))
452 startupFile->Remove(PR_FALSE);
453 #endif
455 else
457 LogError(NS_LITERAL_STRING("opening of installed-chrome.txt failed."), rv);
458 result = nsInstall::CHROME_REGISTRY_ERROR;
462 if (NS_FAILED(rv))
464 LogError(NS_LITERAL_STRING("Failed to register chrome."), rv);
465 result = nsInstall::CHROME_REGISTRY_ERROR;
468 return result;
471 void nsRegisterItem::Abort()
473 // nothing to undo
476 char* nsRegisterItem::toString()
478 char* rsrcVal = nsnull;
480 if (!mInstall)
481 return nsnull;
483 char* buffer = new char[1024];
484 if (!buffer)
485 return nsnull;
487 buffer[0] = '\0';
488 switch (mChromeType & CHROME_ALL)
490 case CHROME_SKIN:
491 rsrcVal = mInstall->GetResourcedString(
492 NS_LITERAL_STRING("RegSkin"));
493 break;
494 case CHROME_LOCALE:
495 rsrcVal = mInstall->GetResourcedString(
496 NS_LITERAL_STRING("RegLocale"));
497 break;
498 case CHROME_CONTENT:
499 rsrcVal = mInstall->GetResourcedString(
500 NS_LITERAL_STRING("RegContent"));
501 break;
502 default:
503 rsrcVal = mInstall->GetResourcedString(
504 NS_LITERAL_STRING("RegPackage"));
505 break;
508 if (rsrcVal)
510 PR_snprintf(buffer, 1024, rsrcVal, mURL.get());
511 nsCRT::free(rsrcVal);
514 return buffer;
518 PRBool
519 nsRegisterItem::CanUninstall()
521 return PR_FALSE;
524 PRBool
525 nsRegisterItem::RegisterPackageNode()
527 return PR_FALSE;
530 nsresult
531 nsRegisterItem::GetURLFromIFile(nsIFile* aFile, char** aOutURL)
533 if (!aFile || !aOutURL)
535 NS_WARNING("bogus arg passed to nsRegisterItem::GetURLFromIFile()");
536 return NS_ERROR_NULL_POINTER;
538 *aOutURL = nsnull;
540 // try to use Necko to create the URL; if that fails (as
541 // it will for the install wizards which don't have Necko)
542 // then use warren's local hack.
544 nsCAutoString spec;
545 nsresult rv = NS_GetURLSpecFromFile(aFile, spec);
546 if (NS_FAILED(rv))
547 rv = hack_nsIFile2URL(aFile, aOutURL);
548 else {
549 *aOutURL = ToNewCString(spec);
550 if (!*aOutURL)
551 rv = NS_ERROR_OUT_OF_MEMORY;
554 return rv;