home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C / Applications / MacPerl 5.0.3 / MacPerl Source ƒ / MacPerl5 / MPCGI.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-09  |  11.2 KB  |  472 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    MacPerl            -    Real Perl Application
  3. File        :    MPCGI.c            -    CGI Scripts for MacHTTP
  4. Author    :    Matthias Neeracher
  5. Language    :    MPW C
  6.  
  7. $Log: MPCGI.c,v $
  8. Revision 1.1  1994/07/30  23:28:34  neeri
  9. Initial revision
  10.  
  11. *********************************************************************/
  12.  
  13. #include <Dialogs.h>
  14. #include <QuickDraw.h>
  15. #include <Windows.h>
  16. #include <Menus.h>
  17. #include <Fonts.h>
  18. #include <AppleEvents.h>
  19. #include <AERegistry.h>
  20. #include <Processes.h>
  21. #include <files.h>
  22. #include <StandardFile.h>
  23. #include <Aliases.h>
  24. #include <GestaltEqu.h>
  25. #include <Folders.h>
  26. #include <Errors.h>
  27. #include <Resources.h>
  28. #include <TextUtils.h>
  29. #include <SegLoad.h>
  30. #include <LowMem.h>
  31.  
  32. #if !defined(powerc) && !defined(__powerc)
  33. #pragma segment Main
  34. #endif
  35.  
  36. #define FAILOSERR(call) if (err = call) return err; else 0
  37.  
  38. #define kWWWEventClass         'WWWΩ'
  39. #define kWWWSearch            'srch'
  40. #define kWWWSearchDoc        'sdoc'
  41.  
  42. typedef struct {
  43.     AEKeyword    key;
  44.     char *        text;
  45. } ArgDesc;
  46.  
  47. #define kForKeyword         'kfor' /* search args                                */
  48. #define kUserKeyword        'user' /* authenticated user name                */
  49. #define kPasswordKeyword    'pass' /* authenticated password                */
  50. #define kFromUser           'frmu' /* "from:" username in HTTP header    */
  51. #define kAddressKeyword     'addr' /* remote client address                    */
  52. #define kPostKeyword        'post' /* arguments passed via POST            */
  53. #define kMethodKeyword      'meth' /* which method? GET, POST, HEAD        */
  54. #define kServerName         'svnm' /* address of the local server            */
  55. #define kServerPort         'svpt' /* port of the local server                */
  56. #define kScriptName         'scnm' /* URL path to the running script        */
  57. #define kContentType        'ctyp' /* type of data in POST args            */
  58. #define kRefererKeyword     'refr' /* Page that pointed to this URL        */
  59. #define kUserAgentKeyword   'Agnt' /* name of client software                */
  60.  
  61. ArgDesc    gArguments[] =
  62. {
  63.     {keyDirectObject,        "-path="                },
  64.     {kForKeyword,             "-search="            },
  65.     {kUserKeyword,         "-user="                },
  66.     {kPasswordKeyword,     "-password="        },
  67.     {kFromUser,             "-from="                },
  68.     {kAddressKeyword,     "-address="            },
  69.     {kPostKeyword,         "-post="                },
  70.     {kMethodKeyword,         "-method="            },
  71.     {kServerName,             "-server-name="    },
  72.     {kServerPort,             "-server-port="    },
  73.     {kScriptName,            "-script-name="    },
  74.     {kContentType,         "-content-type="    },
  75.     {kRefererKeyword,     "-referer="            },
  76.     {kUserAgentKeyword,     "-user-agent="        },
  77.     {0,                        0}
  78. };
  79.  
  80. const char *    gDiagPrefix    =    "\n<H1>Diagnostic Output</H1>\n<PRE>\n";
  81. const char *    gDiagSuffix    =    "\n</PRE>\n";
  82.  
  83. #define TIMEOUT    5*60*60    /* Wait up to 5 minutes */
  84.  
  85. AliasHandle    gMySelf;
  86. EventRecord    gLastEvent;
  87. long            gLastTicks;
  88. DialogPtr    gInfoDlg;
  89. Boolean        gTime2Go = false;
  90.  
  91. pascal Boolean WeAreInFront()
  92. {
  93.     ProcessSerialNumber    we;
  94.     ProcessSerialNumber    front;
  95.     Boolean                    same;
  96.     
  97.     return !GetCurrentProcess(&we) 
  98.          && !GetFrontProcess(&front) 
  99.          && !SameProcess(&we, &front, &same)
  100.          && same;
  101. }
  102.  
  103. pascal Boolean CheckEnvironment()
  104. {
  105.     long    result;
  106.     
  107.     if (Gestalt(gestaltAppleEventsAttr, &result))
  108.         return false;
  109.         
  110.     return (result & (1 << gestaltAppleEventsPresent)) != 0;
  111. }  /* CheckEnvironment */
  112.  
  113. /* The following stuff is adapted from Jens Peter Alfke's SignatureToApp code */
  114.  
  115. OSErr MacPerlRunning(ProcessSerialNumber *psn)
  116. {
  117.     OSErr err;
  118.     ProcessInfoRec info;
  119.     
  120.     psn->highLongOfPSN = 0;
  121.     psn->lowLongOfPSN  = kNoProcess;
  122.     do    {
  123.         FAILOSERR(GetNextProcess(psn));
  124.             
  125.         info.processInfoLength     = sizeof(info);
  126.         info.processName             = nil;
  127.         info.processAppSpec         = nil;
  128.         
  129.         FAILOSERR(GetProcessInformation(psn, &info));
  130.     } while(info.processSignature != 'McPL');
  131.  
  132.     *psn = info.processNumber;
  133.     
  134.     return noErr;
  135. }
  136.  
  137. OSErr GetSysVolume(short *vRefNum)
  138. {
  139.     long dir;
  140.     
  141.     return FindFolder(kOnSystemDisk, kSystemFolderType, false, vRefNum, &dir);
  142. }
  143.  
  144. OSErr GetIndVolume(short index, short *vRefNum)
  145. {
  146.     OSErr             err;
  147.     ParamBlockRec     pb;
  148.     
  149.     pb.volumeParam.ioNamePtr     = nil;
  150.     pb.volumeParam.ioVolIndex     = index;
  151.     
  152.     FAILOSERR(PBGetVInfoSync(&pb));
  153.     
  154.     *vRefNum = pb.volumeParam.ioVRefNum;
  155.     
  156.     return noErr;
  157. }
  158.  
  159. OSErr VolHasDesktopDB(short vRefNum, Boolean * hasDesktop)
  160. {
  161.     OSErr                         err;
  162.     HParamBlockRec             pb;
  163.     GetVolParmsInfoBuffer     info;
  164.     
  165.     pb.ioParam.ioNamePtr     = nil;
  166.     pb.ioParam.ioVRefNum     = vRefNum;
  167.     pb.ioParam.ioBuffer         = (Ptr)&info;
  168.     pb.ioParam.ioReqCount     = sizeof(GetVolParmsInfoBuffer);
  169.     
  170.     FAILOSERR(PBHGetVolParmsSync(&pb));
  171.  
  172.     *hasDesktop = (info.vMAttrib & (1 << bHasDesktopMgr))!=0;
  173.     
  174.     return noErr;
  175. }
  176.  
  177. OSErr FindAppOnVolume(short vRefNum, FSSpec *file)
  178. {
  179.     OSErr     err;
  180.     DTPBRec     pb;
  181.     
  182.     /* Get Acess path to Desktop database on this volume */
  183.     
  184.     pb.ioVRefNum         = vRefNum;
  185.     pb.ioNamePtr         = nil;
  186.     FAILOSERR(PBDTGetPath(&pb));
  187.     
  188.     pb.ioIndex             = 0;
  189.     pb.ioFileCreator     = 'McPL';
  190.     pb.ioNamePtr         = file->name;
  191.     switch (err = PBDTGetAPPLSync(&pb))    {
  192.     case noErr:
  193.         file->vRefNum     = vRefNum;
  194.         file->parID     = pb.ioAPPLParID;
  195.     
  196.         return noErr;
  197.     case fnfErr:
  198.         return afpItemNotFound;                        /* Bug in PBDTGetAPPL            */
  199.     default:
  200.         return err;
  201.     }
  202. }
  203.  
  204. OSErr LaunchIt(FSSpecPtr fileSpec, ProcessSerialNumber * psn )
  205. {
  206.     OSErr                     err;
  207.     LaunchParamBlockRec     pb;
  208.     
  209.     pb.launchBlockID             = extendedBlock;
  210.     pb.launchEPBLength         = extendedBlockLen;
  211.     pb.launchFileFlags         = launchNoFileFlags;
  212.     pb.launchControlFlags    = launchContinue + launchNoFileFlags;
  213.     pb.launchAppSpec             = fileSpec;
  214.     pb.launchAppParameters    = nil;
  215.     
  216.     FAILOSERR(LaunchApplication(&pb));
  217.  
  218.     *psn = pb.launchProcessSN;
  219.     
  220.     return noErr;
  221. }
  222.  
  223. /* Get the psn ofa copy of MacPerl. Launch one if necessary. Buy one. Steal one. */
  224. static OSErr LaunchMacPerl(ProcessSerialNumber *psn)
  225. {
  226.     OSErr     err;
  227.     short     vRefNum, sysVRefNum, index;
  228.     FSSpec     file;
  229.     Boolean     hasDesktopDB;
  230.     
  231.     /* See if ToolServer is already running:                    */
  232.     err    = MacPerlRunning(psn);
  233.     
  234.     if    (err != procNotFound)
  235.         return err;
  236.     
  237.     /* Not running, try to launch it */
  238.     
  239.     FAILOSERR(GetSysVolume(&sysVRefNum));
  240.     
  241.     vRefNum = sysVRefNum;
  242.     
  243.     for (index = 0; !err; err = GetIndVolume(++index,&vRefNum)) {
  244.         if (!index || vRefNum != sysVRefNum) {
  245.             if (err = VolHasDesktopDB(vRefNum,&hasDesktopDB))
  246.                 return err;
  247.                 
  248.             if (hasDesktopDB)    
  249.                 switch (err = FindAppOnVolume(vRefNum, &file))    {
  250.                 case noErr:
  251.                     return LaunchIt(&file, psn);
  252.                 case afpItemNotFound:
  253.                     break;
  254.                 default:
  255.                     return err;
  256.                 }
  257.         }
  258.     }
  259.     
  260.     switch (err) {
  261.     case nsvErr:
  262.     case afpItemNotFound:
  263.         return fnfErr;
  264.     default:
  265.         return err;
  266.     }
  267. }
  268.  
  269. void WhoAmI(AliasHandle * self)
  270. {
  271.     FSSpec        me;
  272.     FCBPBRec        fcb;
  273.     
  274.     fcb.ioNamePtr    =    &me.name;
  275.     fcb.ioRefNum    =    CurResFile();
  276.     fcb.ioFCBIndx    =    0;
  277.     
  278.     PBGetFCBInfoSync(&fcb);
  279.     
  280.     me.vRefNum    =    fcb.ioFCBVRefNum;
  281.     me.parID        =    fcb.ioFCBParID;
  282.     
  283.     NewAlias(nil, &me, self);
  284. }
  285.  
  286. pascal OSErr Ignore(const AppleEvent *message, AppleEvent *reply, long refcon)
  287. {
  288.     return noErr;
  289. }
  290.  
  291. pascal OSErr DoSearch(const AppleEvent *message, AppleEvent *reply, long refcon)
  292. {
  293.     OSErr                        err;
  294.     AppleEvent                doscript;
  295.     AppleEvent                perlSez;
  296.     ProcessSerialNumber    perl;
  297.     AEAddressDesc            perladdr;
  298.     AEDescList                searchArgs;
  299.     AEDesc                    arg;
  300.     AEDesc                    outp;
  301.     AEDesc                    diag;
  302.     Boolean                    doDebug = true;
  303.     
  304.     switch (err = LaunchMacPerl(&perl)) {
  305.     case noErr:
  306.         break;
  307.     case fnfErr:
  308.         ParamText(
  309.             (StringPtr) "\pFailed to launch MacPerl. Either you don't have MacPerl "
  310.             "or your desktop needs to be rebuilt.", (StringPtr) "\p", "\p", "\p");
  311.         Alert(4096, nil);
  312.         
  313.         return err;
  314.     default:
  315.         ParamText(
  316.             (StringPtr) "\pFailed to launch MacPerl (possibly because of "
  317.             "a memory problem).", (StringPtr) "\p", "\p", "\p");
  318.         Alert(4096, nil);
  319.         
  320.         return err;
  321.     }
  322.     
  323.     FAILOSERR(
  324.         AECreateDesc(
  325.             typeProcessSerialNumber,
  326.             (Ptr)&perl,
  327.             sizeof(ProcessSerialNumber),
  328.             &perladdr));
  329.     
  330.     FAILOSERR(
  331.         AECreateAppleEvent(
  332.             kAEMiscStandards, kAEDoScript, &perladdr, 
  333.             kAutoGenerateReturnID, kAnyTransactionID, 
  334.             &doscript));
  335.     
  336.     FAILOSERR(AECreateList(nil,0,false,&searchArgs));
  337.     
  338.     HLock((Handle) gMySelf);
  339.     FAILOSERR(AEPutPtr(&searchArgs, 0, typeAlias, (Ptr) *gMySelf, GetHandleSize((Handle) gMySelf)));
  340.     HUnlock((Handle) gMySelf);
  341.     
  342.     if (refcon) {
  343.         int     argument;
  344.         
  345.         for (argument=0; gArguments[argument].key; ++argument)
  346.             if (!AEGetParamDesc(message, gArguments[argument].key, typeChar, &arg)) {
  347.                 Munger(
  348.                     arg.dataHandle, 0, nil, 0, 
  349.                     gArguments[argument].text, strlen(gArguments[argument].text));
  350.                 FAILOSERR(AEPutDesc(&searchArgs, 0, &arg));
  351.                 AEDisposeDesc(&arg);
  352.             }
  353.     } else {
  354.         if (!AEGetParamDesc(message, keyDirectObject, typeChar, &arg)) {
  355.             Munger(arg.dataHandle, 0, nil, 0, "-search=", 8);
  356.             FAILOSERR(AEPutDesc(&searchArgs, 0, &arg));
  357.             AEDisposeDesc(&arg);
  358.         }
  359.     }
  360.     
  361.     FAILOSERR(AEPutParamDesc(&doscript, keyDirectObject, &searchArgs));
  362.     FAILOSERR(AEPutParamPtr(&doscript, 'MODE', typeEnumerated, "BATC", 4));
  363.     FAILOSERR(
  364.         AESend(
  365.             &doscript, &perlSez,
  366.             kAEWaitReply+kAENeverInteract,
  367.             kAENormalPriority, kAEDefaultTimeout,
  368.             nil, nil));
  369.     
  370.     FAILOSERR(AEGetParamDesc(&perlSez, keyDirectObject, typeWildCard, &arg));
  371.     
  372.     if (!AEGetParamDesc(&perlSez, 'OUTP', typeWildCard, &outp)) {
  373.         if (!AEGetKeyDesc(&outp, 'diag', typeWildCard, &diag)) {
  374.             PtrAndHand(gDiagPrefix, arg.dataHandle, strlen(gDiagPrefix));
  375.             HandAndHand(diag.dataHandle, arg.dataHandle);
  376.             PtrAndHand(gDiagSuffix, arg.dataHandle, strlen(gDiagSuffix));
  377.             
  378.             AEDisposeDesc(&diag);
  379.         }
  380.         AEDisposeDesc(&outp);
  381.     }
  382.         
  383.     FAILOSERR(AEPutParamDesc(reply, keyDirectObject, &arg));
  384.     
  385.     AEDisposeDesc(&arg);
  386.     AEDisposeDesc(&perlSez);
  387.     
  388.     return noErr;
  389. }
  390.  
  391. pascal void MainEvent(void)
  392. {
  393.     DialogPtr    myDialog;
  394.     short            myItemHit;
  395.     
  396.     if (WaitNextEvent(everyEvent, &gLastEvent, 60*60, nil))
  397.         switch (gLastEvent.what) {
  398.         case keyDown:
  399.         case autoKey:
  400.             switch (gLastEvent.message & charCodeMask) {
  401.             case 'Q':
  402.             case '.':
  403.                 if ((gLastEvent.modifiers & cmdKey) != cmdKey)
  404.                     break;
  405.                 /* Else fall through */
  406.             case 13:    /* Return */
  407.             case 3:  /* Enter  */
  408.             case 27: /* ESC    */
  409.                 gTime2Go = true;
  410.                 return;
  411.             }
  412.             SysBeep(0);
  413.             break;
  414.         case kHighLevelEvent:
  415.             AEProcessAppleEvent(&gLastEvent);
  416.             gLastTicks = TickCount();
  417.             break;
  418.         case osEvt:
  419.             switch (gLastEvent.message & osEvtMessageMask) { /*high byte of message*/
  420.             case 0x01000000:
  421.                 if (gLastEvent.message & resumeFlag)
  422.                     ShowWindow(gInfoDlg);
  423.                 else 
  424.                     ShowWindow(gInfoDlg);
  425.             }
  426.             break;
  427.         default:
  428.             gTime2Go = DialogSelect(&gLastEvent, &myDialog, &myItemHit);
  429.             break;
  430.         }
  431. }
  432.  
  433. void main()
  434. {
  435.     InitGraf(&qd.thePort);
  436.     InitFonts();
  437.     FlushEvents(everyEvent, 0);
  438.     InitWindows();
  439.     InitMenus();
  440.     TEInit();
  441.     InitDialogs(nil);
  442.     InitCursor();
  443.  
  444.     /*check environment checks to see if we are running 7.0*/
  445.     if (!CheckEnvironment()) {
  446.         SetCursor(&qd.arrow);
  447.         /*pose the only 7.0 alert*/
  448.         ParamText(
  449.             (StringPtr) "\pMacHTTP CGI scripts need at least System 7.0 to run.", 
  450.             (StringPtr) "\p", "\p", "\p");
  451.         Alert(4096, nil);
  452.         
  453.         ExitToShell();
  454.     }
  455.  
  456.     /* This code will not go native anytime soon */
  457.     AEInstallEventHandler( kCoreEventClass, kAEOpenApplication, (AEEventHandlerUPP)Ignore,   0, false) ;
  458.     AEInstallEventHandler( kWWWEventClass,  kWWWSearch,            (AEEventHandlerUPP)DoSearch, 0, false ) ;
  459.     AEInstallEventHandler( kWWWEventClass,  kWWWSearchDoc,        (AEEventHandlerUPP)DoSearch, 1, false ) ;
  460.  
  461.     WhoAmI(&gMySelf);
  462.     
  463.     gInfoDlg = GetNewDialog(4097, nil, (WindowPtr) -1);
  464.     SetWTitle(gInfoDlg, LMGetCurApName());
  465.     
  466.     if (WeAreInFront())
  467.         ShowWindow(gInfoDlg);
  468.     
  469.     for (gLastTicks = TickCount(); !gTime2Go && (TickCount() - gLastTicks < TIMEOUT); )
  470.         MainEvent();
  471. }
  472.