home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / applevnt / mregistr.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  16.7 KB  |  540 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. // mregistr.cp
  20. // Registry for AppleEvent notifiers
  21. // Pretty clumsy right now, but separating this functionality out of uapp seems
  22. // to be the right thing.
  23. // It is just a collection of routines
  24.  
  25. // MacNetscape
  26. #include "mregistr.h"
  27. #include "macutil.h"
  28. #include "CAppleEventHandler.h"
  29. #include "resae.h"
  30. #include "resgui.h"
  31. #include "ufilemgr.h"
  32. #include "uprefd.h"
  33. #include "CNSContext.h"
  34.  
  35. #ifndef MOZ_MAIL_NEWS
  36. #include "InternetConfig.h"
  37. #endif
  38.  
  39. // xp
  40. #include "client.h"
  41.  
  42. static LArray sURLEchoHandlers(sizeof(ProcessSerialNumber));
  43. static LArray sProtocolHandlers;
  44.  
  45. /************************************************************************************
  46.  * class CProtocolHelper
  47.  * Holds the information about protocol helpers, and knows how to launch them
  48.  ************************************************************************************/
  49.  
  50. class CProtocolHelper    {
  51. public:
  52.     char * fProtocolInfo;    // String that specifies the protocol
  53.     OSType fApplSig;        // Application to launch. Do not use these unless in saving/restoring
  54.     
  55.     // ÑÑ constructors
  56.     CProtocolHelper(char * protocolInfo, OSType applSig);
  57.     virtual ~CProtocolHelper();
  58.     // ÑÑ access
  59.     Boolean    AttemptLaunch(URL_Struct *url, MWContext *context);
  60.     Boolean EqualTo(char * protocolInfo, OSType applSig);
  61.     Boolean operator==(CProtocolHelper * p);
  62.     static void AddNewHelper(CProtocolHelper * helper);
  63.     
  64. };
  65.  
  66. CProtocolHelper::CProtocolHelper(char * protocolInfo, OSType applSig)
  67. {
  68.     fProtocolInfo = protocolInfo;
  69.     fApplSig = applSig;
  70. }
  71.  
  72. CProtocolHelper::~CProtocolHelper()
  73. {
  74.     if (fProtocolInfo)
  75.         XP_FREE(fProtocolInfo);
  76. }
  77.  
  78. Boolean CProtocolHelper::operator==(CProtocolHelper * p)
  79. {
  80.     if (fProtocolInfo && p->fProtocolInfo)
  81.         return (strcmp(fProtocolInfo, p->fProtocolInfo) == 0);
  82.     return false;
  83. }
  84.  
  85. // This is used for the helper removal
  86. // It returns true if we do not have the protocol info
  87. Boolean CProtocolHelper::EqualTo(char * protocolInfo, OSType applSig)
  88. {
  89.     if (applSig != fApplSig)
  90.         return false;
  91.     if (protocolInfo && fProtocolInfo)
  92.         if (strcmp(protocolInfo, fProtocolInfo) == 0)
  93.             return true;
  94.         else
  95.             return false;
  96.     else
  97.         return true;
  98.     return false;
  99. }
  100.  
  101. // Finds the running helper application
  102. // Tries to send a OpenURL event to the registered protocol handler
  103. // If this does not work, sends the standard GetURL event
  104. Boolean CProtocolHelper::AttemptLaunch(URL_Struct *url, MWContext */*context*/)
  105. {
  106.     if (!url->address)
  107.         return false;
  108.     if (strncasecomp(url->address, fProtocolInfo, strlen(fProtocolInfo)) != 0)
  109.         return false;
  110.  
  111.     ProcessSerialNumber psn;
  112.     FSSpec dummy;
  113.     OSErr err = FindProcessBySignature(fApplSig,'APPL',psn,&dummy);
  114.     if (err != noErr)
  115.     {
  116.         FSSpec appSpec;
  117.         err = CFileMgr::FindApplication(fApplSig, appSpec);
  118.         if (err != noErr)
  119.             return false;
  120.     
  121.         LaunchParamBlockRec launchParams;
  122.         launchParams.launchBlockID = extendedBlock;
  123.         launchParams.launchEPBLength = extendedBlockLen;
  124.         launchParams.launchFileFlags = 0;
  125.         launchParams.launchControlFlags = launchContinue + launchNoFileFlags;
  126.         launchParams.launchAppSpec = &appSpec;
  127.         launchParams.launchAppParameters = NULL;
  128.         err = LaunchApplication(&launchParams);
  129.         if (err != noErr)
  130.             return false;
  131.         err = FindProcessBySignature(fApplSig,'APPL',psn,&dummy);
  132.         if (err != noErr)
  133.             return false;
  134.     }
  135.     Try_    // Try the old Spyglass AE suite way first
  136.     {
  137.         AppleEvent event;
  138.         
  139.         err = AEUtilities::CreateAppleEvent(AE_spy_send_suite, AE_spy_openURL, event, psn);
  140.         ThrowIfOSErr_(err);
  141.         // put in the URL
  142.         StAEDescriptor urlDesc(typeChar, url->address, url->address ? strlen(url->address) : 0);
  143.         err = ::AEPutParamDesc(&event,keyDirectObject,&urlDesc.mDesc);
  144.         ThrowIfOSErr_(err);
  145.         // Send it
  146.         AppleEvent reply;
  147.         Try_
  148.         {
  149.             err = ::AESend(&event, &reply, kAEWaitReply,kAENormalPriority,60,nil, nil);
  150.             AEDisposeDesc(&event);
  151.             err = AEUtilities::EventHasErrorReply(reply);
  152.             ThrowIfOSErr_(err);
  153.             AEDisposeDesc(&reply);
  154.         }
  155.         Catch_(inErr)
  156.         {
  157.             AEDisposeDesc(&reply);
  158.             
  159.             // Bug #86055
  160.             // A -1 means the handler didn't want the event, not that it didn't handle it.
  161.             // In this case we should just return that the helper can't handle the protocol
  162.             // and Communicator/Navigator should handle it rather than also sending a GURL
  163.             // event to the helper app.  This works around a problem under MacOS 8 where
  164.             // sending a GURL event to an app that didn't handle it could result in an infinite
  165.             // loop when the OS decided to re-direct the GURL back to us and we promptly sent
  166.             // it back to the handler that didn't handle it.
  167.             if (err == -1)
  168.                 return false;
  169.             else
  170.                 Throw_(inErr);            
  171.         }
  172.         EndCatch_
  173.     }
  174.     Catch_(inErr)    // old Spyglass AE suite way failed, try the standard event
  175.     {
  176.         AppleEvent reply;
  177.         Try_
  178.         {
  179.             AppleEvent event;
  180.             err = AEUtilities::CreateAppleEvent(AE_url_suite, AE_url_getURL, event, psn);
  181.             // put in the URL
  182.             StAEDescriptor urlDesc(typeChar, url->address, url->address ? strlen(url->address) : 0);
  183.             err = ::AEPutParamDesc(&event,keyDirectObject,&urlDesc.mDesc);
  184.             ThrowIfOSErr_(err);
  185.             err = ::AESend(&event, &reply, kAEWaitReply,kAENormalPriority,60,nil, nil);
  186.             AEDisposeDesc(&event);
  187.             ThrowIfOSErr_(AEUtilities::EventHasErrorReply(reply));
  188.             AEDisposeDesc(&reply);
  189.         }
  190.         Catch_(inErr)
  191.         {
  192.             AEDisposeDesc(&reply);
  193.             return false;
  194.         }
  195.         EndCatch_
  196.     }
  197.     EndCatch_
  198.     return true;
  199. }
  200.  
  201. void CProtocolHelper::AddNewHelper(CProtocolHelper* helper)
  202. {
  203.     if (helper == NULL)
  204.         return;
  205.  
  206.     LArrayIterator iter(sProtocolHandlers);
  207.     CProtocolHelper * otherHelper;
  208.     while (iter.Next(&otherHelper))    // Delete duplicate registration for this protocol
  209.         if (*helper == otherHelper)
  210.         {
  211.             delete otherHelper;
  212.             sProtocolHandlers.Remove(&otherHelper);
  213.         }
  214.     sProtocolHandlers.InsertItemsAt(1,1, &helper);
  215.     NET_AddExternalURLType(helper->fProtocolInfo);
  216.     CPrefs::SetModified();
  217. }
  218.  
  219. // Called from preferences, saves all the protocol  handlers
  220. void CNotifierRegistry::ReadProtocolHandlers()
  221. {    
  222.     // Add the bolo handler
  223.     CProtocolHelper *helper = new CProtocolHelper(strdup("bolo"), 'BOLO');
  224.     
  225.     CProtocolHelper::AddNewHelper(helper);
  226.     CPrefs::UsePreferencesResFile();
  227.     
  228.     Handle stringListHandle = ::Get1Resource('STR#', PROT_HANDLER_PREFS_RESID);
  229.     
  230.     if (stringListHandle && *stringListHandle)
  231.     {
  232.         if (::GetHandleSize(stringListHandle) < sizeof(short))
  233.         {
  234.             ::RemoveResource(stringListHandle);
  235.             ::DisposeHandle(stringListHandle);
  236.             return;
  237.         }
  238.     }
  239.     
  240.     CStringListRsrc        stringRsrc(PROT_HANDLER_PREFS_RESID);
  241.     Int16 howMany = stringRsrc.CountStrings();
  242.     if (howMany == 0)
  243.         return;
  244.     //  Each protocol handler is represented by 2 strings
  245.     // 1 - the application sig
  246.     // 2 - the protocol string
  247.     for (int i=1; i < howMany; i=i+2)    // Increment by 2.
  248.     {
  249.         CStr255 applSigStr, protocol;
  250.         stringRsrc.GetString(i, applSigStr);
  251.         if (ResError()) return;
  252.         stringRsrc.GetString(i+1, protocol);
  253.         if (ResError()) return;
  254.  
  255.         OSType appSig;
  256.         LString::PStrToFourCharCode(applSigStr, appSig);
  257.         CProtocolHelper * newHelper = new CProtocolHelper(XP_STRDUP((char*)protocol), appSig);
  258.         CProtocolHelper::AddNewHelper(newHelper);
  259.     }
  260. }
  261.  
  262. // Called from preferences, writes all the protocol  handlers
  263. void CNotifierRegistry::WriteProtocolHandlers()
  264. {
  265.     Int32 howMany = sProtocolHandlers.GetCount();
  266.     if (howMany <= 1)
  267.         return;
  268.     
  269.     Handle stringListHandle = ::Get1Resource('STR#', PROT_HANDLER_PREFS_RESID);
  270.  
  271.     if (!stringListHandle) {
  272.         stringListHandle = ::NewHandle(0);
  273.         ::AddResource(stringListHandle, 'STR#',
  274.             PROT_HANDLER_PREFS_RESID, CStr255::sEmptyString);
  275.     }
  276.     
  277.     if (stringListHandle && *stringListHandle)
  278.     {
  279.         SInt8 flags = ::HGetState(stringListHandle);
  280.         ::HNoPurge(stringListHandle);
  281.         
  282.         CStringListRsrc        stringRsrc(PROT_HANDLER_PREFS_RESID);
  283.         stringRsrc.ClearAll();
  284.         for (int i=1; i<=howMany - 1; i++)
  285.         {
  286.             CProtocolHelper * helper = NULL;
  287.             if (sProtocolHandlers.FetchItemAt(i, &helper))
  288.             {
  289.                 CStr255 protocol(helper->fProtocolInfo);
  290.                 Str255 sig;
  291.                 LString::FourCharCodeToPStr(helper->fApplSig, sig);
  292.                 stringRsrc.AppendString(sig);
  293.                 stringRsrc.AppendString(protocol);
  294.             }
  295.         }
  296.         ::WriteResource(stringListHandle);
  297.         ::HSetState(stringListHandle, flags);
  298.     }
  299. }
  300.  
  301. void CNotifierRegistry::HandleAppleEvent(const AppleEvent &inAppleEvent, AppleEvent &outAEReply,
  302.                                     AEDesc &outResult, long    inAENumber)
  303. {
  304.     switch(inAENumber)    {
  305.         case AE_RegisterURLEcho:
  306.             HandleRegisterURLEcho(inAppleEvent, outAEReply, outResult, inAENumber);
  307.             break;
  308.         case AE_UnregisterURLEcho:
  309.             HandleUnregisterURLEcho(inAppleEvent, outAEReply, outResult, inAENumber);
  310.             break;
  311.         case AE_RegisterProtocol:
  312.             HandleRegisterProtocol(inAppleEvent, outAEReply, outResult, inAENumber);
  313.             break;            
  314.         case AE_UnregisterProtocol:
  315.             HandleUnregisterProtocol(inAppleEvent, outAEReply, outResult, inAENumber);
  316.             break;
  317.         default:
  318.             ThrowOSErr_(errAEEventNotHandled);
  319.     }
  320. }
  321.  
  322. // Always save the PSN
  323. void CNotifierRegistry::HandleRegisterURLEcho(const AppleEvent &inAppleEvent, AppleEvent &outAEReply,
  324.                                     AEDesc &/*outResult*/, long    /*inAENumber*/)
  325. {
  326.     OSType appSignature;
  327.     ProcessSerialNumber psn;
  328.     
  329.     Size     realSize;
  330.     OSType    realType;
  331.     
  332.     OSErr err = ::AEGetParamPtr(&inAppleEvent, keyDirectObject, typeApplSignature, &realType,
  333.                         &appSignature, sizeof(appSignature), &realSize);
  334.     if (err == noErr)    // No parameters, extract the signature from the Apple Event
  335.         psn = GetPSNBySig(appSignature);
  336.     else
  337.         psn = MoreExtractFromAEDesc::ExtractAESender(inAppleEvent);
  338.     // Each application can register only once
  339.     LArrayIterator iter(sURLEchoHandlers);
  340.     ProcessSerialNumber newPSN;
  341.     while (iter.Next(&newPSN))    // If we are already registered, returns 
  342.         if ((newPSN.highLongOfPSN == psn.highLongOfPSN) && (newPSN.lowLongOfPSN == psn.lowLongOfPSN))
  343.             ThrowOSErr_(errAECoercionFail);
  344.     sURLEchoHandlers.InsertItemsAt(1,1, &psn);
  345.     {
  346.         Boolean success = true;
  347.         StAEDescriptor    replyDesc(success);
  348.         err = ::AEPutParamDesc(&outAEReply, keyAEResult, &replyDesc.mDesc);
  349.     }
  350. }
  351.  
  352.  
  353.  
  354. void CNotifierRegistry::HandleUnregisterURLEcho(const AppleEvent &inAppleEvent,
  355.     AppleEvent &/*outAEReply*/, AEDesc &/*outResult*/, long    /*inAENumber*/)
  356. {
  357.     OSType appSignature;
  358.     ProcessSerialNumber psn;
  359.     
  360.     Size     realSize;
  361.     OSType    realType;
  362.  
  363.     OSErr err = ::AEGetParamPtr(&inAppleEvent, keyDirectObject, typeApplSignature, &realType,
  364.                         &appSignature, sizeof(appSignature), &realSize);
  365.     if (err == noErr)    // No parameters, extract the signature from the Apple Event
  366.         psn = GetPSNBySig(appSignature);
  367.     else
  368.         psn = MoreExtractFromAEDesc::ExtractAESender(inAppleEvent);
  369.     LArrayIterator    iter(::sURLEchoHandlers);
  370.     ProcessSerialNumber newPSN;
  371.     while (iter.Next(&newPSN))
  372.         if ((newPSN.highLongOfPSN == psn.highLongOfPSN) && (newPSN.lowLongOfPSN == psn.lowLongOfPSN))
  373.             sURLEchoHandlers.Remove(&newPSN);
  374. }
  375.  
  376. // Echoing of the URLs. For each registered application, send them the URLEcho AE
  377. void FE_URLEcho(URL_Struct *url, int /*iStatus*/, MWContext *context)
  378. {
  379.     ProcessSerialNumber psn;
  380.     OSErr err;
  381.     LArrayIterator    iter(sURLEchoHandlers);
  382.     while (iter.Next(&psn))
  383.     Try_
  384.     {
  385.     // Create the event, fill in all the arguments, and send it
  386.         AEAddressDesc    target;    // Target the event
  387.         err = AECreateDesc(typeProcessSerialNumber, &psn,sizeof(psn), &target);
  388.         ThrowIfOSErr_(err);
  389.         AppleEvent    echoEvent;
  390.         err = ::AECreateAppleEvent(AE_spy_send_suite, AE_spy_URLecho,
  391.                                     &target,
  392.                                     kAutoGenerateReturnID,
  393.                                     kAnyTransactionID,
  394.                                     &echoEvent);
  395.         ThrowIfOSErr_(err);
  396.         AEDisposeDesc(&target);
  397.     // Add the URL
  398.         if (url->address)
  399.         {
  400.             err = ::AEPutParamPtr(&echoEvent, keyDirectObject, typeChar, url->address, strlen(url->address)); 
  401.             ThrowIfOSErr_(err);
  402.         }
  403.     // Add the MIME type
  404.         if (url->content_type)
  405.         {
  406.             err = ::AEPutParamPtr(&echoEvent, AE_spy_URLecho_mime, typeChar, url->content_type, strlen(url->content_type)); 
  407.             ThrowIfOSErr_(err);
  408.         }
  409.     // Add the refererer
  410.         if (url->referer)
  411.         {
  412.             err = ::AEPutParamPtr(&echoEvent, AE_spy_URLecho_referer, typeChar, url->referer, strlen(url->referer)); 
  413.             ThrowIfOSErr_(err);
  414.         }    
  415.     // Add the window ID
  416.         CNSContext* nsContext = ExtractNSContext(context);
  417.         ThrowIfNil_(context);
  418.         Int32 windowID = nsContext->GetContextUniqueID();
  419.         err = ::AEPutParamPtr(&echoEvent, AE_spy_URLecho_win, typeLongInteger, &windowID, sizeof(windowID)); 
  420.         ThrowIfOSErr_(err);
  421.         AppleEvent reply;
  422.         err = ::AESend(&echoEvent, &reply, kAENoReply,kAENormalPriority,0,nil, nil);
  423.         AEDisposeDesc(&echoEvent);
  424.         ThrowIfOSErr_(err);
  425.     }
  426.     Catch_(inErr){}
  427.     EndCatch_
  428. }
  429.  
  430. // Registering the protocol
  431. // The protocol is registered by application signature
  432. void CNotifierRegistry::HandleRegisterProtocol(const AppleEvent &inAppleEvent,
  433.     AppleEvent &/*outAEReply*/, AEDesc &/*outResult*/, long    /*inAENumber*/)
  434. {
  435.     Size realSize;
  436.     DescType realType;
  437.     OSType appSignature;
  438.     char * protocol = nil;
  439.     CProtocolHelper * volatile helper;
  440.     
  441.     Try_
  442.     {
  443.         OSErr err = ::AEGetParamPtr(&inAppleEvent, keyDirectObject, typeApplSignature, &realType,
  444.                             &appSignature, sizeof(appSignature), &realSize);
  445.         if (err != noErr)    // Signature was not passed appropriately typed, try as type
  446.         {
  447.             OSErr err = ::AEGetParamPtr(&inAppleEvent, keyDirectObject, typeType, &realType,
  448.                             &appSignature, sizeof(appSignature), &realSize);
  449.             if (err != noErr)    // No signature passed, extract it from the Apple Event
  450.             {
  451.                 ProcessSerialNumber psn = MoreExtractFromAEDesc::ExtractAESender(inAppleEvent);
  452.                 ProcessInfoRec pir;
  453.                 FSSpec dummy;
  454.                 pir.processAppSpec = &dummy;
  455.                 err = ::GetProcessInformation(&psn, &pir);
  456.                 ThrowIfOSErr_(err);
  457.                 appSignature = pir.processSignature;
  458.             }
  459.         }
  460.         // Extract the protocol
  461.         MoreExtractFromAEDesc::GetCString(inAppleEvent, AE_spy_register_protocol_pro, protocol);
  462.         // Have app signature, and protocol, add them to the list
  463.         helper = new CProtocolHelper(protocol, appSignature);
  464.         CProtocolHelper::AddNewHelper(helper);
  465.     }
  466.     Catch_(inErr){}
  467.     EndCatch_
  468. }
  469.  
  470. void CNotifierRegistry::HandleUnregisterProtocol(const AppleEvent &inAppleEvent,
  471.     AppleEvent &/*outAEReply*/, AEDesc &/*outResult*/, long    /*inAENumber*/)
  472. {
  473.     Size realSize;
  474.     DescType realType;
  475.     OSType appSignature;
  476.     char * protocol = nil;
  477.     
  478.     Try_
  479.     {
  480.         OSErr err = ::AEGetParamPtr(&inAppleEvent, keyDirectObject, typeApplSignature, &realType,
  481.                             &appSignature, sizeof(appSignature), &realSize);
  482.         if (err != noErr)
  483.             err = ::AEGetParamPtr(&inAppleEvent, keyDirectObject, typeType, &realType,
  484.                             &appSignature, sizeof(appSignature), &realSize);
  485.         if (err != noErr)    // No signature passed, extract it from the Apple Event
  486.         {
  487.             ProcessSerialNumber psn = MoreExtractFromAEDesc::ExtractAESender(inAppleEvent);
  488.             ProcessInfoRec pir;
  489.             FSSpec dummy;
  490.             pir.processAppSpec = &dummy;
  491.             err = ::GetProcessInformation(&psn, &pir);
  492.             ThrowIfOSErr_(err);
  493.             appSignature = pir.processSignature;
  494.         }
  495.         // Extract the protocol. Not necessary. If we only have the sig, remove all the registered protocols
  496.         Try_
  497.         {
  498.             MoreExtractFromAEDesc::GetCString(inAppleEvent, AE_spy_register_protocol_pro, protocol);
  499.         }
  500.         Catch_(inErr){}
  501.         EndCatch_
  502.         // Delete it from the list
  503.         LArrayIterator iter(sProtocolHandlers);
  504.         CProtocolHelper * helper;
  505.         while (iter.Next(&helper))    // Delete duplicate registration for this protocol
  506.             if (helper->EqualTo(protocol, appSignature))
  507.             {
  508.                 delete helper;
  509.                 sProtocolHandlers.Remove(&helper);
  510.             }
  511.         if (protocol)
  512.             NET_DelExternalURLType(protocol);
  513.     }
  514.     Catch_(inErr){}
  515.     EndCatch_
  516. }
  517.  
  518.  
  519. XP_Bool FE_UseExternalProtocolModule(MWContext *context,
  520.     FO_Present_Types /*iFormatOut*/, URL_Struct *url,
  521.     Net_GetUrlExitFunc */*pExitFunc*/)
  522. {
  523.  
  524. #ifndef MOZ_MAIL_NEWS    
  525.     if (url->address && CInternetConfigInterface::CurrentlyUsingIC()) {
  526.         ICError err = CInternetConfigInterface::SendInternetConfigURL(url->address);
  527.         if (err == noErr)
  528.             return true;
  529.     }
  530. #endif
  531.  
  532.     LArrayIterator iter(sProtocolHandlers);
  533.     CProtocolHelper * helper;
  534.     while (iter.Next(&helper))
  535.         if (helper->AttemptLaunch(url, context))
  536.             return true;
  537.     return false;
  538. }
  539.  
  540.