Back to index

lightning-sunbird  0.9+nobinonly
nsCommandLineServiceMac.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Simon Fraser   <sfraser@netscape.com>
00024  *   Pierre Phaneuf <pp@ludusdesign.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 // Special stuff for the Macintosh implementation of command-line service.
00041 
00042 #include "nsCommandLineServiceMac.h"
00043 
00044 // Mozilla
00045 #include "nsDebug.h"
00046 #include "nsILocalFileMac.h"
00047 #include "nsDebug.h"
00048 #include "nsNetUtil.h"
00049 #include "nsIAppStartup.h"
00050 #include "nsIServiceManager.h"
00051 #include "nsIURL.h"
00052 #include "nsIIOService.h"
00053 #include "nsIURL.h"
00054 #include "nsIServiceManager.h"
00055 #include "nsNetCID.h"
00056 #include "nsIDOMWindow.h"
00057 #include "nsXPCOM.h"
00058 #include "nsISupportsPrimitives.h"
00059 #include "nsIWindowWatcher.h"
00060 #include "jsapi.h"
00061 #include "nsReadableUtils.h"
00062 #include "nsICloseAllWindows.h"
00063 #include "nsIPrefService.h"
00064 
00065 #include "nsAEEventHandling.h"
00066 #include "nsXPFEComponentsCID.h"
00067 
00068 // NSPR
00069 #include "prmem.h"
00070 #include "plstr.h"
00071 #include "prenv.h"
00072 #ifdef XP_MAC
00073 #include "pprio.h"  // PR_Init_Log
00074 #endif
00075 
00076 // the static instance
00077 nsMacCommandLine nsMacCommandLine::sMacCommandLine;
00078 
00079 /*
00080  * ReadLine --
00081  *
00082  * Read in a line of text, terminated by CR or LF, from inStream into buf.
00083  * The terminating CR or LF is not included.  The text in buf is terminated
00084  * by a null byte.
00085  * Returns the number of bytes in buf.  If EOF and zero bytes were read, returns -1.
00086  */
00087 
00088 static PRInt32 ReadLine(FILE* inStream, char* buf, PRInt32 bufSize)
00089 {
00090   PRInt32 charsRead = 0;
00091   int c;
00092   
00093   if (bufSize < 2)
00094     return -1;
00095 
00096   while (charsRead < (bufSize-1)) {
00097     c = getc(inStream);
00098     if (c == EOF || c == '\n' || c == '\r')
00099       break;
00100     buf[charsRead++] = c;
00101   }
00102   buf[charsRead] = '\0';
00103   
00104   return (c == EOF && !charsRead) ? -1 : charsRead; 
00105 }
00106 
00107 //----------------------------------------------------------------------------------------
00108 nsMacCommandLine::nsMacCommandLine()
00109 : mArgs(NULL)
00110 , mArgsAllocated(0)
00111 , mArgsUsed(0)
00112 , mStartedUp(PR_FALSE)
00113 //----------------------------------------------------------------------------------------
00114 {
00115 }
00116 
00117 
00118 //----------------------------------------------------------------------------------------
00119 nsMacCommandLine::~nsMacCommandLine()
00120 //----------------------------------------------------------------------------------------
00121 {
00122   ShutdownAEHandlerClasses();
00123   if (mArgs) {
00124     for (PRUint32 i = 0; i < mArgsUsed; i++)
00125       free(mArgs[i]);
00126     free(mArgs);
00127   }
00128 }
00129 
00130 
00131 //----------------------------------------------------------------------------------------
00132 nsresult nsMacCommandLine::Initialize(int& argc, char**& argv)
00133 //----------------------------------------------------------------------------------------
00134 {
00135   mArgs = static_cast<char **>(malloc(kArgsGrowSize * sizeof(char *)));
00136   if (!mArgs)
00137     return NS_ERROR_FAILURE;
00138   mArgs[0] = nsnull;
00139   mArgsAllocated = kArgsGrowSize;
00140   mArgsUsed = 0;
00141   
00142 #if defined(XP_MACOSX)
00143   // Here, we may actually get useful args.
00144   // Copy them first to mArgv.
00145   for (int arg = 0; arg < argc; arg++)
00146     AddToCommandLine(argv[arg]);
00147 #else
00148   // init the args buffer with the program name
00149   AddToCommandLine("mozilla");
00150 #endif
00151 
00152   // Set up AppleEvent handling.
00153   OSErr err = CreateAEHandlerClasses(false);
00154   if (err != noErr) return NS_ERROR_FAILURE;
00155 
00156   // Snarf all the odoc and pdoc apple-events.
00157   //
00158   // 1. If they are odoc for 'CMDL' documents, read them into the buffer ready for
00159   //    parsing (concatenating multiple files).
00160   //
00161   // 2. If they are any other kind of document, convert them into -url command-line
00162   //    parameters or -print parameters, with file URLs.
00163 
00164   EventRecord anEvent;
00165   for (short i = 1; i < 5; i++)
00166     ::WaitNextEvent(0, &anEvent, 0, nsnull);
00167 
00168   while (::EventAvail(highLevelEventMask, &anEvent))
00169   {
00170     ::WaitNextEvent(highLevelEventMask, &anEvent, 0, nsnull);
00171     if (anEvent.what == kHighLevelEvent)
00172     {
00173       // here we process startup odoc/pdoc events, which can 
00174       // add items to the command line.
00175       err = ::AEProcessAppleEvent(&anEvent);
00176     }
00177   }
00178   
00179   if (GetCurrentKeyModifiers() & optionKey)
00180     AddToCommandLine("-p");
00181 
00182   // we've started up now
00183   mStartedUp = PR_TRUE;
00184   
00185   argc = mArgsUsed;
00186   argv = mArgs;
00187   
00188   return NS_OK;
00189 }
00190 
00191 //----------------------------------------------------------------------------------------
00192 nsresult nsMacCommandLine::AddToCommandLine(const char* inArgText)
00193 //----------------------------------------------------------------------------------------
00194 {
00195   if (mArgsUsed >= mArgsAllocated) {
00196     // realloc does not free the given pointer if allocation fails.
00197     char **temp = static_cast<char **>(realloc(mArgs, (mArgsAllocated + kArgsGrowSize) * sizeof(char *)));
00198     if (!temp)
00199       return NS_ERROR_OUT_OF_MEMORY;
00200     mArgs = temp;
00201     mArgsAllocated += kArgsGrowSize;
00202   }
00203   char *temp2 = strdup(inArgText);
00204   if (!temp2)
00205     return NS_ERROR_OUT_OF_MEMORY;
00206   mArgs[mArgsUsed++] = temp2;
00207   return NS_OK;
00208 }
00209 
00210 
00211 //----------------------------------------------------------------------------------------
00212 nsresult nsMacCommandLine::AddToCommandLine(const char* inOptionString, const FSSpec& inFileSpec)
00213 //----------------------------------------------------------------------------------------
00214 {
00215   // Convert the filespec to a URL
00216   FSSpec nonConstSpec = inFileSpec;
00217   nsCOMPtr<nsILocalFileMac> inFile;
00218   nsresult rv = NS_NewLocalFileWithFSSpec(&nonConstSpec, PR_TRUE, getter_AddRefs(inFile));
00219   if (NS_FAILED(rv))
00220     return rv;
00221   nsCAutoString specBuf;
00222   rv = NS_GetURLSpecFromFile(inFile, specBuf);
00223   if (NS_FAILED(rv))
00224     return rv;
00225   AddToCommandLine(inOptionString);  
00226   AddToCommandLine(specBuf.get());
00227   return NS_OK;
00228 }
00229 
00230 //----------------------------------------------------------------------------------------
00231 nsresult nsMacCommandLine::AddToEnvironmentVars(const char* inArgText)
00232 //----------------------------------------------------------------------------------------
00233 {
00234   (void)PR_SetEnv(inArgText);
00235   return NS_OK;
00236 }
00237 
00238 
00239 //----------------------------------------------------------------------------------------
00240 OSErr nsMacCommandLine::HandleOpenOneDoc(const FSSpec& inFileSpec, OSType inFileType)
00241 //----------------------------------------------------------------------------------------
00242 {
00243   nsCOMPtr<nsILocalFileMac> inFile;
00244   nsresult rv = NS_NewLocalFileWithFSSpec(&inFileSpec, PR_TRUE, getter_AddRefs(inFile));
00245   if (NS_FAILED(rv))
00246     return errAEEventNotHandled;
00247 
00248   if (!mStartedUp)
00249   {
00250     // Is it the right type to be a command-line file?
00251     if (inFileType == 'TEXT' || inFileType == 'CMDL')
00252     {
00253       // Can we open the file?
00254       FILE *fp = 0;
00255       rv = inFile->OpenANSIFileDesc("r", &fp);
00256       if (NS_SUCCEEDED(rv))
00257       {
00258         Boolean foundArgs = false;
00259         Boolean foundEnv = false;
00260         char chars[1024];
00261         static const char kCommandLinePrefix[] = "ARGS:";
00262         static const char kEnvVarLinePrefix[] = "ENV:";
00263 
00264         while (ReadLine(fp, chars, sizeof(chars)) != -1)
00265         {       // See if there are any command line or environment var settings
00266           if (PL_strstr(chars, kCommandLinePrefix) == chars)
00267           {
00268             (void)AddToCommandLine(chars + sizeof(kCommandLinePrefix) - 1);
00269             foundArgs = true;
00270           }
00271           else if (PL_strstr(chars, kEnvVarLinePrefix) == chars)
00272           {
00273             (void)AddToEnvironmentVars(chars + sizeof(kEnvVarLinePrefix) - 1);
00274             foundEnv = true;
00275           }
00276         }
00277 
00278         fclose(fp);
00279 #ifndef XP_MACOSX
00280         // If we found any environment vars we need to re-init NSPR's logging
00281         // so that it knows what the new vars are
00282         if (foundEnv)
00283           PR_Init_Log();
00284 #endif
00285         // If we found a command line or environment vars we want to return now
00286         // raather than trying to open the file as a URL
00287         if (foundArgs || foundEnv)
00288           return noErr;
00289       }
00290     }
00291     // If it's not a command-line argument, and we are starting up the application,
00292     // add a command-line "-url" argument to the global list. This means that if
00293     // the app is opened with documents on the mac, they'll be handled the same
00294     // way as if they had been typed on the command line in Unix or DOS.
00295     return AddToCommandLine("-url", inFileSpec);
00296   }
00297 
00298   // Final case: we're not just starting up. How do we handle this?
00299   nsCAutoString specBuf;
00300   rv = NS_GetURLSpecFromFile(inFile, specBuf);
00301   if (NS_FAILED(rv))
00302     return errAEEventNotHandled;
00303   
00304   return OpenURL(specBuf.get());
00305 }
00306 
00307 OSErr nsMacCommandLine::OpenURL(const char* aURL)
00308 {
00309   nsresult rv;
00310   
00311   nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
00312 
00313   nsXPIDLCString browserURL;
00314   if (NS_SUCCEEDED(rv))
00315     rv = prefBranch->GetCharPref("browser.chromeURL", getter_Copies(browserURL));
00316   
00317   if (NS_FAILED(rv)) {
00318     NS_WARNING("browser.chromeURL not supplied! How is the app supposed to know what the main window is?");
00319     browserURL.Assign("chrome://navigator/content/navigator.xul");
00320   }
00321      
00322   rv = OpenWindow(browserURL.get(), NS_ConvertASCIItoUCS2(aURL).get());
00323   if (NS_FAILED(rv))
00324     return errAEEventNotHandled;
00325     
00326   return noErr;
00327 }
00328 
00329 
00330 
00331 //----------------------------------------------------------------------------------------
00332 OSErr nsMacCommandLine::HandlePrintOneDoc(const FSSpec& inFileSpec, OSType fileType)
00333 //----------------------------------------------------------------------------------------
00334 {
00335   // If  we are starting up the application,
00336   // add a command-line "-print" argument to the global list. This means that if
00337   // the app is opened with documents on the mac, they'll be handled the same
00338   // way as if they had been typed on the command line in Unix or DOS.
00339   if (!mStartedUp)
00340     return AddToCommandLine("-print", inFileSpec);
00341   
00342   // Final case: we're not just starting up. How do we handle this?
00343   NS_NOTYETIMPLEMENTED("Write Me");
00344   return errAEEventNotHandled;
00345 }
00346 
00347 
00348 
00349 //----------------------------------------------------------------------------------------
00350 nsresult nsMacCommandLine::OpenWindow(const char *chrome, const PRUnichar *url)
00351 //----------------------------------------------------------------------------------------
00352 {
00353   nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
00354   nsCOMPtr<nsISupportsString> urlWrapper(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
00355   if (!wwatch || !urlWrapper)
00356     return NS_ERROR_FAILURE;
00357 
00358   urlWrapper->SetData(nsDependentString(url));
00359 
00360   nsCOMPtr<nsIDOMWindow> newWindow;
00361   nsresult rv;
00362   rv = wwatch->OpenWindow(0, chrome, "_blank",
00363                "chrome,dialog=no,all", urlWrapper,
00364                getter_AddRefs(newWindow));
00365 
00366   return rv;
00367 }
00368 
00369 //----------------------------------------------------------------------------------------
00370 OSErr nsMacCommandLine::DispatchURLToNewBrowser(const char* url)
00371 //----------------------------------------------------------------------------------------
00372 {
00373   OSErr err = errAEEventNotHandled;
00374   if (mStartedUp)
00375     return OpenURL(url);
00376   else {
00377     err = AddToCommandLine("-url");
00378     if (err == noErr)
00379       err = AddToCommandLine(url);
00380   }
00381   
00382   return err;
00383 }
00384 
00385 //----------------------------------------------------------------------------------------
00386 OSErr nsMacCommandLine::Quit(TAskSave askSave)
00387 //----------------------------------------------------------------------------------------
00388 {
00389   nsresult rv;
00390   
00391   nsCOMPtr<nsICloseAllWindows> closer =
00392            do_CreateInstance("@mozilla.org/appshell/closeallwindows;1", &rv);
00393   if (NS_FAILED(rv))
00394     return errAEEventNotHandled;
00395 
00396     PRBool doQuit;
00397     rv = closer->CloseAll(askSave != eSaveNo, &doQuit);
00398     if (NS_FAILED(rv) || !doQuit)
00399         return errAEEventNotHandled;
00400           
00401   nsCOMPtr<nsIAppStartup> appStartup = 
00402            (do_GetService(NS_APPSTARTUP_CONTRACTID, &rv));
00403   if (NS_FAILED(rv))
00404     return errAEEventNotHandled;
00405   
00406   (void)appStartup->Quit(nsIAppStartup::eAttemptQuit);
00407   return noErr;
00408 }
00409 
00410 
00411 //========================================================================================
00412 //      InitializeMacCommandLine
00413 //      The only external entry point to this file.
00414 //========================================================================================
00415 
00416 #pragma mark -
00417 
00418 //----------------------------------------------------------------------------------------
00419 nsresult InitializeMacCommandLine(int& argc, char**& argv)
00420 //----------------------------------------------------------------------------------------
00421 {
00422 
00423   nsMacCommandLine&  cmdLine = nsMacCommandLine::GetMacCommandLine();
00424   return cmdLine.Initialize(argc, argv);
00425 } // InitializeMac