home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / Connectivity / GateKeeper-2.1 / Coordinator.m < prev    next >
Encoding:
Text File  |  1997-06-29  |  41.6 KB  |  1,406 lines

  1. //*****************************************************************************
  2. //
  3. //    Coordinator.m  
  4. //        
  5. //        NXApp delegate, central control object for GateKeeper 
  6. // 
  7. //            by    Felipe A. Rodriguez        
  8. //
  9. //    The base for this file was:
  10. //    
  11. //            Coordinator.m
  12. //            by Joe Freeman, David LaVallee
  13. //            Subprocess Example, Release 2.0
  14. //            NeXT Computer, Inc.
  15. //
  16. //    This code is supplied "as is" the author makes no warranty as to its 
  17. //    suitability for any purpose.  This code is free and may be distributed 
  18. //    in accordance with the terms of the:
  19. //        
  20. //            GNU GENERAL PUBLIC LICENSE
  21. //            Version 2, June 1991
  22. //            copyright (C) 1989, 1991 Free Software Foundation, Inc.
  23. //             675 Mass Ave, Cambridge, MA 02139, USA
  24. //
  25. //*****************************************************************************
  26.  
  27. #import "GKdefs.h"
  28. #import "Animator.h"
  29. #import "Parse.h"
  30. #import "OptionsEditor.h"
  31. #import "options.h"
  32. #import "IconView.h"
  33. #import "ToolBar.h"
  34. #import "DOserver.h"
  35. #import "Timer.h"
  36. #import "InactivityTimer.h"
  37. #import "Coordinator.h"
  38. #import "CommandScroll.h"
  39. #import "Subprocess.h"
  40. #import "GateDocEditor.h"
  41. #import "HLRecord.h"
  42. #import "HLDelegate.h"
  43.  
  44. #import <appkit/nextstd.h>
  45. #import <appkit/Application.h>
  46. #import <dpsclient/dpsNeXT.h>
  47. #import <objc/NXStringTable.h>
  48. #import <defaults/defaults.h>
  49. #import <bsd/c.h>
  50. #import <sys/dir.h>  /* POSIX applications #include <dirent.h> */
  51.  
  52.  
  53.  
  54.  
  55. @interface Coordinator(Private)
  56.  
  57.         // preferences controls 
  58.     extern char *cList[];
  59.     extern char *rfList[];
  60.     extern char *rsList[];
  61.  
  62.         // private functions 
  63. - miscPrep2;
  64.  
  65.         // dial on demand server 
  66. #import <mach/mach_error.h>
  67. #import <servers/netname.h>
  68. #import "nsRPC_types.h"
  69.  
  70.  
  71. any_t server_loop(any_t port);
  72.  
  73.                     // defined by MiG: 
  74. boolean_t nsRPC_server(msg_header_t *in, msg_header_t *out);
  75.  
  76.                 // from Request types in nsRPCUser.c 
  77. struct message 
  78.         {                
  79.         msg_header_t    head;        /* standard header field */
  80.         msg_type_t      arg1_type;   /* first arg type */
  81.         int             arg1;        /* first arg */
  82.         msg_type_t      arg2_type;   /* second arg type */
  83.         int             arg2;        /* second arg */
  84.         };
  85.  
  86. @end
  87. @implementation Coordinator(Private)
  88.  
  89. //*****************************************************************************
  90. //
  91. //         misc to do before coordinator starts a subprocess 
  92. //
  93. //*****************************************************************************
  94.  
  95. - miscPrep2
  96. {
  97. int i = 0;
  98.  
  99.     [[theAnimator startAnimTimer] setStandbyGate:NO];
  100.  
  101.     [linkMenuButton setEnabled:NO];                // disable link button
  102.     [dial setEnabled:NO];                        // disable dial button
  103.     [theOpenButton setEnabled:NO];                // disable the open doc button
  104.     while(i < 3)                    
  105.         {                                        // erase captured str's array
  106.         if(capturedStr[i])                        
  107.             free(capturedStr[i]);
  108.         capturedStr[i++] = NULL;                // blank, for next invocation
  109.         }
  110.     linkStg = 0;    // prevent stages in link process from getting called twice
  111.                                     
  112.                     // setup and load our keyword's hashtable
  113.     if(strHashTable)
  114.         free(strHashTable);
  115.     strHashTable = [[HashTable alloc] initKeyDesc:"*" valueDesc:"i"];
  116.     for(i = 0; i < 2; i++)
  117.         {
  118.         numEntries[i] = i;
  119.         [strHashTable insertKey:NXGetDefaultValue([NXApp appName], cList[i+1]) 
  120.                                                     value:&numEntries[i]];
  121.         }
  122.     for(i = 0; i < 4; i++)
  123.         {
  124.         numEntries[i + 2] = i + 2;
  125.         [strHashTable insertKey:NXGetDefaultValue([NXApp appName], rfList[i]) 
  126.                                                     value:&numEntries[i + 2]];
  127.         }
  128.     numEntries[6] = 6;
  129.     [strHashTable insertKey:"address" value:&numEntries[6]];
  130.     numEntries[7] = 7;
  131.     [strHashTable insertKey:"remote" value:&numEntries[7]];
  132.  
  133.     return self;
  134. }
  135.  
  136. @end
  137. @implementation Coordinator
  138.  
  139. //************************ Subprocess Delegation ****************************** //*****************************************************************************
  140. //
  141. //         recieves output from subprocess
  142. //        canonicalizes output stream into lines
  143. //
  144. //*****************************************************************************
  145.  
  146. - subprocessOutput:(char *)buffer
  147. {
  148. static char strbuf[132];
  149. static int strpos = 0;
  150.  
  151.     while(*buffer)        
  152.         {            // cr/lf delimit lines and we do not exceed strbuf size        
  153.         if((*buffer != '\n' && *buffer != '\r') && strpos < 128)    
  154.             {
  155.             strbuf[strpos++] = *buffer++; 
  156.             strbuf[strpos] = '\0';
  157.             }
  158.         else 
  159.             {
  160.             while((*buffer == '\n' || *buffer == '\r') && (strpos < 130))
  161.                 strbuf[strpos++] = *buffer++;
  162.             strbuf[strpos] = '\0';
  163.             [self analyzeBuffer:strbuf];
  164.             strpos = 0; 
  165.             }
  166.         }
  167.         
  168.     return self;
  169. }
  170. //*****************************************************************************
  171. //
  172. //        - captures certain keywords as status and info markers
  173. //        - calls gotIt, displayLinkStatus methods when link is established
  174. //        - sends data stream to diagnostics window and comments to status
  175. //
  176. //*****************************************************************************
  177.  
  178. - analyzeBuffer:(char *)buffer
  179. {
  180. char *str, delim[] = {" \n\r^/"}, delim2[] = {"\n\r^"}, *argString = NULL; 
  181. int *cntr;    
  182.  
  183.     if(argString != NULL)
  184.         free(argString);
  185.     argString = NXCopyStringBuffer(buffer);
  186.     [commandView appendString:buffer];                // send buffer to diag win
  187.     str = strtok(argString, delim);                    // Parse string and test it
  188.     while(str != NULL)                                
  189.         {                                            
  190.         if(*str == '#')            // comments will be displayed in status panel
  191.             {
  192.             if(str = strtok(NULL, delim2))
  193.                 {
  194.                 if(strlen(str) > 3)
  195.                     [statusView setStringValue:[self localString:str]];
  196.                 }
  197.             }
  198.         else
  199.             {
  200.             if ([strHashTable isKey:str] == YES)     // if str is in hash table
  201.                 {                                    // we have caught a keyword
  202.                 cntr = [strHashTable valueForKey:str];
  203.                 switch(*cntr)
  204.                     {                            
  205.                     case 2:                         // redial?
  206.                     case 3:                         // Persistent connect
  207.                     case 4:                            // Fail connect
  208.                     case 5:                            // LCP terminate
  209.                         if((strcmp(NXGetDefaultValue([NXApp appName], 
  210.                                     rsList[*cntr - 2]),"YES") == 0) // sw "ON"?    
  211.                                             && (lastCall[0] != '\0'))
  212.                             [self perform:@selector(redial:) with:self 
  213.                                 afterDelay:backOffDelay cancelPrevious:YES];
  214.                         else
  215.                             [self UnLink:nil];        // if redial off, unlink
  216.                         break;
  217.                     
  218.                     case 0:                          // baud str caught
  219.                         if((str = strtok(NULL, delim)) &&
  220.                                                     (capturedStr[0] == NULL))
  221.                             [self connectedAt:str];
  222.                         break;
  223.         
  224.                     case 1:                              // the link is up
  225.                         if(linkStg < 4)                    // if ivar is >, ppp
  226.                             {
  227.                             [self gotIt];                // may be sending
  228.                             linkStg = 4;                // keyword twice
  229.                             }
  230.                         break;                                
  231.     
  232.                     case 6:                            // local address str caught
  233.                         if((str = strtok(NULL, delim)) && (linkStg < 5))    
  234.                             {        
  235.                             capturedStr[1] = NXCopyStringBuffer(str);
  236.                             linkStg = 5;    
  237.                             }
  238.                         break;
  239.                                             
  240.                     case 7:                          // display addresses
  241.                         if(linkStg < 6)
  242.                             {
  243.                             if((str = strtok(NULL, delim)) != NULL)
  244.                                 {
  245.                                 if((str = strtok(NULL, delim)) != NULL)
  246.                                     {
  247.                                     if((str = strtok(NULL, delim)) != NULL)
  248.                                         {
  249.                                         capturedStr[2] = 
  250.                                                     NXCopyStringBuffer(str);
  251.                                         [self displayLinkStatus];
  252.                                         }
  253.                                     }
  254.                                 }
  255.                             }
  256.                         break;
  257.         
  258.                     default:             
  259.                         break;
  260.                     }
  261.                 }
  262.             }
  263.         str = strtok(NULL, delim);
  264.         }
  265.         
  266.     return self;
  267. }
  268. //************************************************************************
  269. //
  270. //         Called when subprocess has terminated
  271. //
  272. //************************************************************************
  273.  
  274. - subprocessDone
  275. {
  276.     [theTimer stopTimer];
  277.     if(theGateServer)
  278.         [theGateServer free];            
  279.     theGateServer = nil;
  280.     [theSubprocess free];
  281.     theSubprocess = nil;
  282.     if(userWantsTermination)    // end only if user chose too (not subP fail)
  283.         [NXApp terminate:self];
  284.     else                                            // if not exiting    
  285.         [theAnimator startAnimTimer];                // cycle thru animation
  286.     
  287.     return self;
  288. }
  289. //*****************************************************************************
  290. //
  291. //         return our string table (contains key->value localization pairs) 
  292. //
  293. //*****************************************************************************
  294.  
  295. - stringTable;
  296. {
  297.     return stringTable;
  298. }
  299. //*****************************************************************************
  300. //
  301. //     localize error messages using stringTable as appropriate, displays
  302. //     the message in an alert panel
  303. //
  304. //*****************************************************************************
  305.  
  306. - showAlert:(const char *)errorString
  307. {
  308.     NXRunAlertPanel(0, [self localString:errorString], 
  309.                             [stringTable valueForStringKey:"OK"], NULL, NULL);
  310.  
  311.     return self;
  312. }
  313. //*****************************************************************************
  314. //
  315. //     localize string messages using stringTable as appropriate
  316. //
  317. //*****************************************************************************
  318.  
  319. - (const char *)localString:(const char *)aString
  320. {
  321. const char *returnedString;
  322.     
  323.     if (returnedString = [stringTable valueForStringKey:aString])
  324.         return returnedString;
  325.  
  326.     return aString;
  327. }
  328. //*****************************************************************************
  329. //
  330. //         Called when link is established
  331. //
  332. //*****************************************************************************
  333.  
  334. - gotIt
  335. {
  336.     [theAnimator removeTimedEntry];
  337.                             // ppp is up, play snd for me
  338.     if(strcmp(NXGetDefaultValue([NXApp appName],"sound"), "YES") == 0) 
  339.         [[[Sound findSoundFor: "majestic"] play: nil] free];
  340.     [theTimer Fire:self];
  341.     if(!onImage)
  342.         onImage = [NXImage findImageNamed:"g4"];
  343.     [theIconView setImage:onImage];
  344.     [statusView setStringValue:[self localString:"pppup"]];
  345.                     // if auto hide switch is set wait 5 sec before hiding    
  346.     if(strcmp(NXGetDefaultValue([NXApp appName], "autoHide"),"YES") == 0)    
  347.         [NXApp perform:@selector(hide:) with:self afterDelay:5000 
  348.                                                             cancelPrevious:NO];                
  349.  
  350.     return self;
  351. }
  352. //*****************************************************************************
  353. //
  354. //         registers connection speed 
  355. //
  356. //*****************************************************************************
  357.  
  358. - connectedAt:(const char *)speed  
  359. {
  360.     strncpy(Path, [stringTable valueForStringKey:"connectAt"], MAXPATHLEN);
  361.     strncat(Path, speed, MAXPATHLEN - strlen(Path));
  362.     capturedStr[0] = NXCopyStringBuffer(Path);
  363.     [connectionSpeedField setStringValue:capturedStr[0]];
  364.  
  365.     return self;
  366. }
  367. //*****************************************************************************
  368. //
  369. //         displays captured info regarding current ppp session
  370. //
  371. //*****************************************************************************
  372.  
  373. - displayLinkStatus
  374. {
  375.     if(capturedStr[0] != NULL)                // in case we man dialed
  376.         {                                    // we will not know connect speed
  377.         [commandView appendString:"\n#################################\n"];
  378.         [commandView appendString:"####\n"];
  379.         [commandView appendString:"####  "];
  380.         [commandView appendString:capturedStr[0]];
  381.         }
  382.     else
  383.         [commandView appendString:"\n#################################"];
  384.     [commandView appendString:"\n####\n"];
  385.     [commandView appendString:[stringTable valueForStringKey:"localIP"]];
  386.     [commandView appendString:capturedStr[1]];
  387.     [localIPField setStringValue:capturedStr[1]];
  388.     [commandView appendString:"\n####\n"];
  389.     [commandView appendString:[stringTable valueForStringKey:"remoteIP"]];
  390.     [commandView appendString:capturedStr[2]];
  391.     [commandView appendString:"\n####"];
  392.     [remoteIPField setStringValue:capturedStr[2]];
  393.     [commandView appendString:"\n#################################\n"];
  394.     linkStg = 6;                                    // ppp link is up, set ivar
  395.     [iTimer pppstats:commandView];                    // run pppstats w/view
  396.  
  397.     return self;
  398. }
  399. //*********************** Application Object Delegation ***********************
  400. //*****************************************************************************
  401. //
  402. //             setup defaults data base cache before app is init'd
  403. //
  404. //*****************************************************************************
  405.  
  406. - appWillInit:sender
  407. {
  408.     static NXDefaultsVector myDefaults = {        // setup defaults database
  409.         {DISPLAYD, "YES"},                        // display diagnostics window
  410.         {DISPLAYS, "YES"},                        // display status window
  411.         {"autoLaunch", "NO"},            
  412.         {"autoHide", "YES"},                    // auto hide upon link        
  413.         {"autoRedial", "YES"},            
  414.         {"PersistCon", "YES"},            
  415.         {"FailRedial", "YES"},                    // redial if a Fail occurs
  416.         {"LCPterminate", "YES"},            // redial if lcp termination occurs
  417.         {"Fail", "Exit."},            
  418.         {"reDial", "Failed"},            
  419.         {"Persist", "down"},                    // persistent connect trigger
  420.         {"LCPterm", "terminated."},                // lcp termination trigger
  421.         {"DispPPP", "YES"},                        // display pppstats
  422.         {DISPLAYT, "YES"},                        // display toolbar
  423.         {"DoD", "NO"},                            // dial on demand
  424.         {USEFIFO, "YES"},                        // use a FIFO for IPC w/pppd?
  425.         {"sound", "YES"},                        // play sound 
  426.         {AITIMER, "YES"},                        // icon displayed online time
  427.         {REDBOFF, "YES"},                        // backoff on failed redials?
  428.         {"iTimeout", "Off"},                    // inactivity unlink's us
  429.         {"preTimeout", "YES"},                    // inactivity unlink's us
  430.         {"iTimeThreshold", "0"},                // inactivity threshold 
  431.         {SELCELL, "0"},                            // cell selected in hotList
  432.         {BROWSERHT, "999.0"},                    // ht of browser in hotList
  433.         {ADDRESSHT, "999.0"},                    // ht of address in hotList
  434.         {FIRSTTIME, "YES"},                        // first time thru?
  435.         {"options", "/etc/ppp/options"},            
  436.         {"ip-down", "/etc/ppp/ip-down"},            
  437.         {"ip-up", "/etc/ppp/ip-up"},            
  438.         {"resolv", "/etc/resolv.conf"},            
  439.         {"syslog", "/etc/syslog.conf"},            
  440.         {"messages", "/usr/adm/messages"},            
  441.         {"rc", "/etc/rc.local"},            
  442.         {"remote", "/etc/remote"},            
  443.         {"locFIFO", "/usr/adm/ppp2.2.debug"},                // pref form start
  444.         {"comLine", "/usr/local/bin/pppd -detach"},            
  445.         {HLLIST, "/"},            
  446.         {"BaudStr", "CARRIER"},                                // pref form end
  447.         {"LinkUp", "local"},                        // Link is up trigger
  448.         {DIALINIT, "ATZ&D0L3"},            // modem init str for manual Dial
  449.         {"dialPrefix", "ATD"},            // modem AT command prefix for dialing
  450.         {MODEMPORT, "cufa"},            // modem port, used in releasing locks
  451.         {"path", "/"},                            // path for .Gate documents
  452.         {"lastNumDialed", "8675309"},                // default man dial number
  453.         {"savedTime", "000000000000"},            // save time used this mo
  454.         {"monthTime", "000000000000"},            // save mo,yr of this ses'n
  455.         {"preMonthTime", "000000000000"},        // save previous mo,yr 
  456.         {NULL}};                                    // make local cache of ddb
  457.     NXRegisterDefaults([NXApp appName], myDefaults);    
  458.  
  459.     return self;
  460. }
  461. //*****************************************************************************
  462. //
  463. //             standard init
  464. //
  465. //*****************************************************************************
  466.  
  467. - appDidInit:sender
  468. {
  469. time_t waitTime;            // time to delay
  470.  
  471.     time(<ime);                                // Get time and place in time_t
  472.     if(strcmp(NXGetDefaultValue([NXApp appName], USEFIFO), "YES") == 0) 
  473.         [self syslogdReset];                    // reset the syslogd daemon
  474.  
  475.                             // setup appIcon for animation
  476.     theAnimator = [[Animator alloc] init];        // get appIcon window
  477.     theIconView = [theAnimator iconView];
  478.     timeCell = [theIconView getTextCell];     // return the iconView's textCell
  479.  
  480.     if(strcmp(NXGetDefaultValue([NXApp appName], FIRSTTIME),"YES") == 0) 
  481.         {                            // if first time this version was launched
  482.         [self showInfo:self];    
  483.         if(!NXWriteDefault([NXApp appName], FIRSTTIME, "NO"))
  484.             NXRunAlertPanel(0,
  485.                     [stringTable valueForStringKey:"ddbWriteError"],
  486.                     [stringTable valueForStringKey:"OK"],
  487.                     NULL,
  488.                     NULL);
  489.         }
  490.     [NXApp loadNibSection:"StatusWindow.nib" owner:self withNames:NO];
  491.     if(strcmp("YES", NXGetDefaultValue([NXApp appName], DISPLAYS)) == 0)
  492.         [statusWin makeKeyAndOrderFront:self];        // show status panel
  493.  
  494.     [NXApp loadNibSection:"DiagWindow.nib" owner:self withNames:NO];
  495.     [diagWin setFrameUsingName:[diagWin title]];    // remem sz,loc
  496.     [diagWin setFrameAutosaveName:[diagWin title]];
  497.     
  498.     if(strcmp("YES", NXGetDefaultValue([NXApp appName], DISPLAYT)) == 0)    
  499.         [self toolBar:self];                        // show toolbar if set
  500.  
  501.     if(strcmp("YES", NXGetDefaultValue([NXApp appName], AITIMER)) == 0)    
  502.         appIconTime = YES;                    // show online time in app icon
  503.     
  504.     if(strcmp("YES", NXGetDefaultValue([NXApp appName], REDBOFF)) == 0)    
  505.         backOffDefault = backOffDelay = BDEF;        // redial delay backoff on
  506.  
  507.                         // setup Inactivity timeout and pppstats controller
  508.     iTimer = [[InactivityTimer allocFromZone:[self zone]] init];
  509.  
  510.     if(strcmp(NXGetDefaultValue([NXApp appName],"NXAutoLaunch"),"YES") == 0) 
  511.         {                        // if app was dock autoLaunched
  512.         waitTime = ltime + 2;    // delay for X sec so that syslogd can sync
  513.         while(ltime < waitTime)    // ltime ivar is set in syslogReset method 
  514.             {time(<ime);}
  515.         }
  516.     theTimer = [[Timer allocFromZone:[self zone]] init];
  517.                // If we weren't asked to open any documents at launch time, then     
  518.             // we were launched by double clicking on the application instead 
  519.             // of a document. If so check whether we should auto-launch w/def's
  520.     if(!NXGetDefaultValue([NXApp appName], "NXOpen") &&
  521.         !NXGetDefaultValue([NXApp appName], "NXOpenTemp") &&
  522.             !NXGetDefaultValue([NXApp appName], "NXServiceLaunch"))
  523.         {
  524.         if(strcmp(NXGetDefaultValue([NXApp appName], "autoLaunch"),"YES") == 0)    
  525.             [self Link:self];    
  526.         }
  527.     [self DialOnDemand];        // prepare for dial on demand if set
  528.                      
  529.     return self;
  530. }
  531. //*****************************************************************************
  532. //
  533. //         redial 
  534. //
  535. //*****************************************************************************
  536.  
  537. - redial:sender
  538. {                    // only allow a redial if user has not stopped linking
  539.     if((strcmp([[[NXApp mainMenu] findCellWithTag:2] title], 
  540.                 [[NXApp delegate] localString:"Disconnect"]) == 0) && 
  541.                 [[[NXApp mainMenu] findCellWithTag:2] isEnabled] && (sender))
  542.         {
  543.         [self UnLink:nil];         
  544.         if([self runScript:"preLink"])
  545.             {                // back off in multiples of 2
  546.             backOffDelay *= 2;
  547.             [self perform:@selector(resetDelay:) with:self 
  548.                         afterDelay:(backOffDelay + 1000) cancelPrevious:YES];                
  549.             [self linkWithFile:lastCall];
  550.             }
  551.         }
  552.                      
  553.     return self;
  554. }
  555. //*****************************************************************************
  556. //
  557. //         reset the backoff delay 
  558. //
  559. //*****************************************************************************
  560.  
  561. - resetDelay:sender
  562. {                            // eliminate any pending redials
  563.     [self perform:@selector(redial:) with:nil afterDelay:0 cancelPrevious:YES];    
  564.       if ([sender isKindOf:[Matrix class]]) 
  565.         {
  566.         if((BOOL)[[sender selectedCell] intValue])
  567.             backOffDefault = BDEF;                // redial delay backoff on
  568.         else
  569.             backOffDefault = 0;
  570.         }
  571.     backOffDelay = backOffDefault;
  572.                      
  573.     return self;
  574. }
  575. //*****************************************************************************
  576. //
  577. //         This method is performed whenever a user double-clicks on an icon in
  578. //         the Workspace Manager representing a Gate program document.  
  579. //         
  580. //         Brings up the gate doc editor which can edit or link using the doc
  581. //
  582. //*****************************************************************************
  583.  
  584. - (int)app:sender openFile:(const char *)path type:(const char *)type 
  585. {
  586.     [theGateDocEditor editGateDoc:path];
  587.                 
  588.     return 1;
  589. }
  590. //*****************************************************************************
  591. //
  592. //         invoked immediately after app is hidden and unhidden respectively
  593. //
  594. //            the following two methods are implemented to produce
  595. //            normal main window/menu app behavior when toolBar is open
  596. //
  597. //******************************************************************************
  598. - appDidHide:sender
  599. {
  600.     [[NXApp mainMenu] close];        // close the main menu  
  601.                                     
  602.     return self;
  603. }
  604.  
  605. - appDidUnhide:sender
  606. {
  607.     [[NXApp mainMenu] makeKeyAndOrderFront:self];         
  608.  
  609.     return self;
  610. }
  611. //*****************************************************************************
  612. //
  613. //         Instantantiates the subprocess object which exec's pppd
  614. //
  615. //*****************************************************************************
  616.  
  617. - linkWithFile:(const char *)path  
  618. {
  619. char commandLine[MAXPATHLEN + 1]; 
  620.  
  621.     [self miscPrep2];                            // misc initialization's
  622.     if(strcmp(NXGetDefaultValue([NXApp appName], DISPLAYD),"YES") == 0)
  623.         [diagWin makeKeyAndOrderFront:self];        // show diagnostics win
  624.  
  625.     strncpy(commandLine, NXGetDefaultValue([NXApp appName], "comLine"), 
  626.                                                                    MAXPATHLEN);
  627.     commandLine[MAXPATHLEN-1] = 0;
  628.     if(path == NULL)
  629.         {                
  630.         lastCall[0] = '\0';                        
  631.         if([hotListDelegate selGateDocOptionsPath] == NULL)
  632.             commandLine[0] = '\0';
  633.         else                                    // if hotlist points to valid
  634.             {
  635.             strncat(commandLine, " file ", MAXPATHLEN - strlen(commandLine));
  636.             strncat(commandLine, [hotListDelegate selGateDocOptionsPath], 
  637.                                             MAXPATHLEN - strlen(commandLine));
  638.             strncpy(BPath,[hotListDelegate selGateDocOptionsPath], MAXPATHLEN);            
  639.             [providerField setStringValue:[self localString:"manDial"]];
  640.             }
  641.         }
  642.     else
  643.         {
  644.         strcpy(lastCall, path);            // stores path of last invocation
  645.         if(strstr(path, "GateKeeper.app") == NULL)
  646.             [providerField setStringValue:[self extractName:path]];
  647.         else
  648.             [providerField setStringValue:[self localString:"gkDefault"]];
  649.         [statusView setStringValue:[self localString:"connecting"]];
  650.         if((strlen([[NXBundle mainBundle] directory]) + 45 + 
  651.                     (2 * strlen(path)) + strlen(commandLine)) < MAXPATHLEN)    
  652.             {                                    // if we won't overrun buffer
  653.             strcat(commandLine, " file ");
  654.             strcat(commandLine, path);
  655.             strcat(commandLine, OPTION);    // options file name wrapper
  656.             strcat(commandLine, " connect \"");                
  657.             strcat(commandLine, [[NXBundle mainBundle] directory]);
  658.             strcat(commandLine, "/chat -v -f ");
  659.             strcat(commandLine, path);
  660.             strcat(commandLine, PPPUP);    // pppup file name wrapper
  661.             strcat(commandLine, "\"");
  662.             }
  663.         else
  664.             perror("command line is longer than MAXPATHLEN");
  665.         strncpy(BPath, path , MAXPATHLEN);    
  666.         strncat(BPath, OPTION, MAXPATHLEN - strlen(BPath));    // options 
  667.         }
  668.     if(commandLine[0] != '\0')                // if we have a valid commline 
  669.         {
  670.         [linkMenuButton setEnabled:YES];            // enable unlink button
  671.         [linkMenuButton setTitle:[self localString:"Disconnect"]];
  672.         [linkMenuButton setAction:@selector(UnLink:)];
  673.         [statusButton setTitle:[self localString:"Disconnect"]];
  674.         [statusButton setAction:@selector(UnLink:)];
  675.         if([iTimer posNonInter])
  676.             [commandView appendString:
  677.                             "Dial on demand triggered ppp session\n"];
  678.         if([self debugFlag:BPath])
  679.             {                // if debug sw set in options disg commandline
  680.             [commandView appendString:commandLine];
  681.             [commandView appendString:"\n\r"];
  682.             }
  683.         theSubprocess = [[Subprocess alloc] init:commandLine withDelegate:self     
  684.                                     andStdErr:YES];
  685.         }
  686.                 
  687.     return self;
  688. }
  689. //*****************************************************************************
  690. //
  691. //         Use terminal to do a manual link 
  692. //
  693. //*****************************************************************************
  694.  
  695. - Dial:sender  
  696. {
  697.     if((strcmp([linkMenuButton title], [self localString:"Connect"]) == 0) && 
  698.                     [linkMenuButton isEnabled] && [self runScript:"preLink"])
  699.         { 
  700.         [self miscPrep2];                        // misc initialization's
  701.         [iTimer setPosNonInter:NO];                // user interactive session
  702.         if(!theGateServer)                    // create distributed Obj server
  703.             theGateServer = [[DOserver alloc] init];          
  704.         [theGateServer setDelegate:self];            
  705.         GateConnection = [NXConnection registerRoot: theGateServer
  706.                         withName:"GateKeeperServer"];    // DO name of server
  707.         [GateConnection runFromAppKit];    // listen for DO messages from appKit
  708.         if(![[NXBundle mainBundle] getPath:Path forResource:"MODEM" 
  709.                                                                 ofType:NULL])
  710.             [self showAlert:"Error getting path for MODEM file"];
  711.         [[Application workspace] openFile:Path withApplication:"Terminal"];    
  712.         }
  713.  
  714.     return self;
  715. }
  716. //*****************************************************************************
  717. //
  718. //         Called: when menu item link is pressed, when DNS triggers us.  
  719. //        Calls app:sender
  720. //
  721. //*****************************************************************************
  722.  
  723. - Link:sender  
  724. {
  725.     if((strcmp([linkMenuButton title], [self localString:"Connect"]) == 0) && 
  726.                     [linkMenuButton isEnabled] && [self runScript:"preLink"])
  727.         { 
  728.         if(!sender)                                    // DNS triggered session,
  729.             [iTimer setPosNonInter:YES];            // possibly non-interactive 
  730.         else                                        
  731.             [iTimer setPosNonInter:NO];                // user interactive session
  732.     [hotListDelegate playLink];    // selected in the HotList to launch pppd
  733.     }            
  734.  
  735.     return self;
  736. }
  737. //*****************************************************************************
  738. //
  739. //         Called when menu item Unlink is pressed.  
  740. //
  741. //*****************************************************************************
  742.  
  743. - UnLink:sender  
  744. {
  745.     if([self runScript:"preUnLink"])
  746.         { 
  747.         if(theSubprocess && [theSubprocess respondsTo:@selector(terminate:)])
  748.             [theSubprocess terminate:sender];
  749.         [[theAnimator setOpenGate:YES] setStandbyGate:YES];
  750.         [iTimer pppstatsReset];                    // disable pppstats
  751.         [timeCell setStringValue:"      "];
  752.         [linkMenuButton setEnabled:YES];            // enable unlink button
  753.         [linkMenuButton setTitle:[self localString:"Connect"]];
  754.         [linkMenuButton setAction:@selector(Link:)];
  755.         [statusButton setTitle:[self localString:"Connect"]];
  756.         [statusButton setAction:@selector(Link:)];
  757.         [theOpenButton setEnabled:YES];            // enable the open doc button
  758.         [dial setEnabled:YES];                    // enable dial button
  759.         [statusView setStringValue:[self localString:"pppdn"]];
  760.         [connectionSpeedField setStringValue:"                          "];
  761.         [timeField setStringValue:"        "];
  762.         [providerField setStringValue:"                       "];    
  763.         [localIPField setStringValue:"                "];
  764.         [remoteIPField setStringValue:"                "];
  765.         [self namedDod];                    // kill/restart named to dump cache
  766.         }
  767.     if(sender)
  768.         [self resetDelay:self];        
  769.  
  770.     return self;
  771. }
  772. //*****************************************************************************
  773. //
  774. //         run the preLink or preUnLink scripts, proceed if exit status true 
  775. //
  776. //*****************************************************************************
  777.  
  778. - runScript:(const char *)type  
  779. {
  780. id exitStatus = self;
  781. int fd;
  782.  
  783.     strncpy(Path, [[NXBundle mainBundle] directory], MAXPATHLEN);
  784.     strncat(Path, "/", MAXPATHLEN - strlen(Path));
  785.     strncat(Path, type, MAXPATHLEN - strlen(Path));
  786.     if(fd = open(Path, O_RDONLY) != -1)            //    if script exists
  787.         {
  788.         close(fd);
  789.         if(system(Path) != 0)                    // exec script, test exit
  790.             exitStatus = nil;
  791.         strcpy(Path, type);
  792.         if(!exitStatus)
  793.             strcat(Path," script exit status prevents requested action\n");
  794.         else
  795.             strcat(Path, " script executed sucessfully\n");
  796.         [commandView appendStringUseFixedFont:Path];
  797.         }
  798.  
  799.     return exitStatus;
  800. }
  801. //*****************************************************************************
  802. //
  803. //         we can always edit another gate doc
  804. //
  805. //*****************************************************************************
  806.  
  807. - (BOOL)appAcceptsAnotherFile:sender 
  808. {
  809.     return YES;
  810. }
  811. //****************************************************************************
  812. //
  813. //        termination is allowed only if the user has selected it, subprocess 
  814. //        failure should not cause GateKeeper to terminate
  815. //
  816. //****************************************************************************
  817.  
  818. - terminate:sender
  819. {
  820.     userWantsTermination = YES;
  821.  
  822.     return self;
  823. }
  824. //****************************************************************************
  825. //
  826. //        termination is imminent 
  827. //
  828. //****************************************************************************
  829.  
  830. - appWillTerminate:sender
  831. {
  832.     [theSubprocess terminate:sender];
  833.     [theAnimator removeTimedEntry];
  834.     [self namedReset:"/usr/etc/named"];        // replace our named with system's
  835.     [hotListDelegate appWillTerminate];
  836.     
  837.     return self;
  838. }
  839. //*****************************************************************************
  840. //
  841. //         show the info panel 
  842. //
  843. //*****************************************************************************
  844.  
  845. - showInfo:sender
  846. {
  847.     if(!infoPanel)
  848.         [NXApp loadNibSection:"InfoPanel.nib" owner:self withNames:NO];
  849.     [infoPanel center];
  850.     [infoPanel makeKeyAndOrderFront:self];
  851.     
  852.     return self;
  853. }
  854. //****************************************************************************
  855. //
  856. //        show preferences panel   
  857. //
  858. //****************************************************************************
  859.  
  860. - preferences:sender
  861. {
  862.     if(!prefPanel) 
  863.         [NXApp loadNibSection:"Preferences.nib" owner:self withNames:NO];
  864.     [prefPanel makeKeyAndOrderFront:self];
  865.         
  866.     return self;
  867. }
  868. //************************************************************************
  869. //
  870. //        show NXHelpPanel 
  871. //
  872. //************************************************************************
  873.  
  874. - showHelpPanel:sender 
  875. {
  876.     if(!helpPanel)
  877.         helpPanel = [NXHelpPanel new];
  878.     [helpPanel display];
  879.     [helpPanel makeKeyAndOrderFront:self];
  880.     
  881.     return self;
  882. }
  883. //************************************************************************
  884. //
  885. //        display the Status panel 
  886. //
  887. //************************************************************************
  888.  
  889. - showStatusPanel:sender 
  890. {
  891.     if(!NXWriteDefault([NXApp appName], DISPLAYS, "YES"))
  892.         [self showAlert:"ddbWriteError"];
  893.  
  894.     return [statusWin makeKeyAndOrderFront:self];
  895. }
  896. //*****************************************************************************
  897. //
  898. //         display the Diagnostics window 
  899. //
  900. //*****************************************************************************
  901.  
  902. - showDiagWin:sender
  903. {
  904.     if(!NXWriteDefault([NXApp appName], DISPLAYD, "YES"))
  905.         [self showAlert:"ddbWriteError"];
  906.  
  907.     return [diagWin makeKeyAndOrderFront:self];
  908. }
  909. //************************************************************************
  910. //
  911. //        show the timer 
  912. //
  913. //************************************************************************
  914.  
  915. - showTimerPanel:sender 
  916. {
  917.     return [theTimer showTimerPanel:self];
  918. }
  919. //*****************************************************************************
  920. //
  921. //         called by timer in order to pass us appIcon time string 
  922. //
  923. //        also used in determining inactivity timeout (since this is called
  924. //        once per minute during ppp sessions).
  925. //
  926. //*****************************************************************************
  927.  
  928. - showMenuTimer:(char *)buffer 
  929. {
  930.     if(appIconTime)
  931.         [timeCell setStringValue:buffer];
  932.     [timeField setStringValue:buffer];
  933.     [theIconView setImage:onImage];
  934.     [iTimer inactivityTimeout];
  935.  
  936.     return self; 
  937. }
  938. //*****************************************************************************
  939. //
  940. //         set inactivity timer's timeout Ivar and write its value to ddb 
  941. //
  942. //*****************************************************************************
  943.  
  944. - setTimeout:(int)minTillTimeout 
  945. {
  946.     [iTimer setTimeout:minTillTimeout];
  947.  
  948.     return self; 
  949. }
  950. //*****************************************************************************
  951. //
  952. //         enable/disable display of online time in app icon 
  953. //
  954. //*****************************************************************************
  955.  
  956. - setAppIconTimer:(BOOL)onOff 
  957. {
  958.     appIconTime = onOff;
  959.  
  960.     return self; 
  961. }
  962. //*****************************************************************************
  963. //
  964. //         return a pointer to the hotlist window's delegate 
  965. //
  966. //*****************************************************************************
  967.  
  968. - hotListDelegate 
  969. {
  970.     return hotListDelegate; 
  971. }
  972. //*****************************************************************************
  973. //
  974. //         tell browser to update its data from its delegate 
  975. //
  976. //*****************************************************************************
  977.  
  978. - updateBrowser:sender
  979. {
  980.     return [hotListDelegate loadBrowser];
  981. }
  982. //************************************************************************
  983. //
  984. //        extracts the Gate doc name from its path 
  985. //
  986. //************************************************************************
  987.  
  988. - (const char *)extractName:(const char *)aPath
  989. {
  990. char *ptr;
  991.  
  992.     strcpy(Path, aPath);
  993.     ptr = Path + strlen(Path) - 1;        
  994.     while(*ptr != '.' && *ptr)
  995.         ptr--;
  996.     *ptr-- = '\0';
  997.     while(*ptr != '/' && *ptr)
  998.         ptr--;
  999.     ++ptr;
  1000.  
  1001.     return ptr;
  1002. }
  1003. //************************************************************************
  1004. //
  1005. //        returns whether a Gate doc may be opened or edited by real user
  1006. //
  1007. //************************************************************************
  1008.  
  1009. - readable:(const char *)nameOfFile
  1010. {
  1011. FILE *fp;
  1012.  
  1013.     if ((fp = fopen(nameOfFile, "r+")) == NULL)
  1014.         [self showAlert:"Unable to open Gate doc"];
  1015.     else
  1016.         {
  1017.         if(readable(fileno(fp)))
  1018.             {
  1019.             fclose(fp);
  1020.               return self;                // we have permission
  1021.             }
  1022.         [self showAlert:"Access to Gate doc denied"];
  1023.         fclose(fp);
  1024.         }
  1025.  
  1026.        return nil;                        // we do not have permission
  1027. }
  1028. //*****************************************************************************
  1029. //
  1030. //         returns the Gate doc options editor
  1031. //
  1032. //*****************************************************************************
  1033.  
  1034. - optionsEditor
  1035. {
  1036.     if(!theOptionsEditor)
  1037.         theOptionsEditor = [[OptionsEditor alloc] init];
  1038.  
  1039.     return theOptionsEditor;
  1040. }
  1041. //*****************************************************************************
  1042. //
  1043. //         returns the state of the debug flag in an options file
  1044. //
  1045. //*****************************************************************************
  1046.  
  1047. - (BOOL)debugFlag:(const char *)optionFile
  1048. {
  1049.       return [[[self optionsEditor] parseOptions:optionFile] debug];
  1050. }
  1051. //*****************************************************************************
  1052. //
  1053. //             show the Tool Bar
  1054. //
  1055. //*****************************************************************************
  1056.  
  1057. - toolBar:sender
  1058. {
  1059.     if(!NXWriteDefault([NXApp appName], DISPLAYT, "YES"))
  1060.         [self showAlert:"ddbWriteError"];
  1061.     if(!toolBar) 
  1062.         [NXApp loadNibSection:"ToolBar.nib" owner:self withNames:NO];
  1063.     [toolBar makeKeyAndOrderFront:self];
  1064.  
  1065.     return toolBar;
  1066. }
  1067. //************************************************************************
  1068. //
  1069. //         return the app icons view
  1070. //
  1071. //************************************************************************
  1072.  
  1073. - appIconView
  1074. {
  1075.     return     theIconView;                    // enable link button
  1076. }
  1077. //************************************************************************
  1078. //
  1079. //         called by DO server when remote manual Dial Tool's ports are 
  1080. //        invalidated
  1081. //
  1082. //************************************************************************
  1083.  
  1084. - DOFinished
  1085. {
  1086.     return     [self UnLink:self];                    // enable link button
  1087. }
  1088. //************************************************************************
  1089. //
  1090. //     free simply gets rid of everything we created
  1091. //     This is how nice objects clean up.
  1092. //
  1093. //************************************************************************
  1094.  
  1095. - free
  1096. {
  1097.     [timeCell free];
  1098.     if(onImage)
  1099.         [onImage free];
  1100.     if(toolBar) 
  1101.         [toolBar free];
  1102.     if(iTimer) 
  1103.         [iTimer free];
  1104.  
  1105.     return [super free];
  1106. }
  1107. //*****************************************************************************
  1108. //
  1109. //         Attempt to reset syslogd daemon.  Failing that, try starting it. 
  1110. //
  1111. //*****************************************************************************
  1112.  
  1113. - syslogdReset
  1114. {
  1115. FILE *ff; 
  1116. int pid;
  1117.                     
  1118.     if((ff = fopen( "/etc/syslog.pid", "r")) != NULL)
  1119.         {
  1120.         if( fscanf( ff, "%d", &pid) < 1)
  1121.             perror("Unable to read pid from etc/syslog.pid\n");
  1122.         else
  1123.             {
  1124.             if( kill( pid, SIGHUP) != -1)         // tell syslogd to reconfigure
  1125.                 {
  1126.                 fclose( ff);
  1127.  
  1128.                 return self;                    // report success
  1129.                 }
  1130.             else            // if app was not dock autoLaunched
  1131.                 if(strcmp(NXGetDefaultValue(
  1132.                                 [NXApp appName],"NXAutoLaunch"),"NO") == 0) 
  1133.                     perror("error reconfiguring syslogd");
  1134.             }
  1135.         }
  1136.     else
  1137.         perror("Unable to open /etc/syslog.pid\n");
  1138.     
  1139.     return [self syslogdRun];        // failed to reconfig so restart syslogd
  1140. }
  1141. //*****************************************************************************
  1142. //
  1143. //         Terminante and then run the syslogd daemon 
  1144. //
  1145. //*****************************************************************************
  1146.  
  1147. - syslogdRun
  1148. {
  1149. int pid;
  1150. FILE *ff; 
  1151.                     
  1152.     if((ff = fopen( "/etc/syslog.pid", "r")) != NULL)
  1153.         {
  1154.         if( fscanf( ff, "%d", &pid) < 1)
  1155.             perror("Unable to read pid from etc/syslog.pid\n");
  1156.         else
  1157.             if( kill( pid, SIGTERM) == -1)
  1158.                 {
  1159.                 if(strcmp(NXGetDefaultValue(    
  1160.                                 [NXApp appName],"NXAutoLaunch"),"NO") == 0) 
  1161.                     perror("error killing syslogd");
  1162.                 }
  1163.         }
  1164.     switch (pid = vfork())    // create new process 
  1165.         {                            
  1166.         case -1:            // error
  1167.         
  1168.             perror("Error during vfork syslogdReset.");
  1169.             return self;
  1170.             
  1171.         case 0:              // child -- Vfork returns 0 in the child's context
  1172.  
  1173.             execl("/usr/etc/syslogd", "syslogd", 0);
  1174.             perror("vfork error restarting syslogd"); 
  1175.             exit(1);
  1176.  
  1177.         default:            // parent --  vfork returns pid of the child          
  1178.             
  1179.             break;    
  1180.         }        
  1181.     
  1182.     return self;
  1183. }
  1184. //*****************************************************************************
  1185. //
  1186. //         prepare ourself to be triggered by named when dial on demand is
  1187. //        necessary 
  1188. //
  1189. //*****************************************************************************
  1190.  
  1191. - DialOnDemand                    
  1192. {
  1193. port_t    server_port;
  1194. kern_return_t    r;
  1195.  
  1196.                              // if dial on demand is "ON"
  1197.     if(strcmp("YES", NXGetDefaultValue([NXApp appName], "DoD")) == 0)    
  1198.         {            
  1199.                             // allocate a port for this task, ret in arg 2
  1200.         r = port_allocate(task_self(), &server_port);
  1201.         if (r != KERN_SUCCESS) 
  1202.             {
  1203.             mach_error("port_allocate failed", r);
  1204.             exit(1);
  1205.             }                // Register with the Network Name Server.
  1206.         r = netname_check_in(name_server_port, GK_DNS_SERVER, PORT_NULL, 
  1207.                                                                 server_port);
  1208.         if (r != KERN_SUCCESS) 
  1209.             {
  1210.             mach_error("netname_check_in failed", r);
  1211.             exit(1);
  1212.             }
  1213.                         // create dial on demand server thread and detach it
  1214.             cthread_detach(cthread_fork((cthread_fn_t)server_loop, 
  1215.                                                         (any_t)server_port));
  1216.         [self namedDod];    // replace named with dial on demand trigger named
  1217.         }
  1218.     
  1219.     return self;
  1220. }
  1221. //*****************************************************************************
  1222. //
  1223. //         Attempt to kill and restart named daemon.  Resets RR's cache.
  1224. //
  1225. //*****************************************************************************
  1226.  
  1227. - namedReset:(const char *)buffer
  1228. {
  1229. FILE *ff; 
  1230. int pid;
  1231.                              // if dial on demand is "ON"
  1232.     if(strcmp("YES", NXGetDefaultValue([NXApp appName], "DoD")) == 0)
  1233.         {    
  1234.         if((ff = fopen( "/etc/named.pid", "r")) != NULL)
  1235.             {
  1236.             if( fscanf( ff, "%d", &pid) < 1)
  1237.                 perror("Unable to read pid from etc/named.pid\n");
  1238.             else
  1239.                 {
  1240.                 if( kill( pid, SIGTERM) == -1)             // kill named
  1241.                     perror("error killing named");
  1242.                 }
  1243.             }
  1244.         else
  1245.             perror("Unable to open /etc/named.pid\n");
  1246.         fclose( ff);
  1247.         system(buffer);                // start GateKeeper named 
  1248.         }
  1249.     
  1250.     return self;
  1251. }
  1252. //*****************************************************************************
  1253. //
  1254. //         replace the system named with our own which will inform us when a
  1255. //        dial on demand is necessary 
  1256. //
  1257. //*****************************************************************************
  1258.  
  1259. - namedDod
  1260. {                    
  1261.     if(!strcpy(Path, [[NXBundle mainBundle] directory]))    // app's home dir
  1262.         [self showAlert:"Error getting mainbundle path"];
  1263.     else
  1264.         {
  1265.         strcat(Path,"/named");
  1266.         [self namedReset:Path];        // kill named and replace with our own
  1267.         }
  1268.     
  1269.     return self;
  1270. }
  1271. //*****************************************************************************
  1272. //
  1273. //         search /etc/syslog.conf to find the location of the named pipe used 
  1274. //        in recieving the output from pppd/syslog 
  1275. //
  1276. //*****************************************************************************
  1277.  
  1278. - fifo
  1279. {
  1280. static char del1[] = {". =:|\t\r\n"}, del2[] = {" \t\r\n"};
  1281. char *fifoName = NULL;
  1282.  
  1283.     if(!Parser)                                    
  1284.         Parser = [[Parse alloc] init];            // create parser to find port
  1285.     [[Parser setKey1:"local2"] setKey2:"debug"];        // set search pattern  
  1286.     [[Parser setDelim1:del1] setDelim2:del2];            // and delimiters
  1287.  
  1288.     if(fifoName = [Parser parseFile:"/etc/syslog.conf"])
  1289.         {
  1290.         if(!NXWriteDefault([NXApp appName], "locFIFO", fifoName))
  1291.             NXRunAlertPanel(0,
  1292.                     [stringTable valueForStringKey:"ddbWriteError"],
  1293.                     [stringTable valueForStringKey:"OK"],
  1294.                     NULL,
  1295.                     NULL);
  1296.         free(fifoName);
  1297.         }
  1298.     else
  1299.         [self showAlert:"FIFO Path Error"];
  1300.  
  1301.     return self;
  1302. }
  1303. //*****************************************************************************
  1304. //
  1305. //         checks the mail queue for mail awaiting delivery 
  1306. //
  1307. //*****************************************************************************
  1308.  
  1309. - (BOOL)mailInQueue 
  1310. {
  1311. int    eCntr = 0;
  1312. struct direct *dirp;
  1313. DIR *dp;
  1314. BOOL mail = NO;
  1315.  
  1316.     if ((dp = opendir("/usr/spool/mqueue")) != NULL)
  1317.         {
  1318.         while ((dirp = readdir(dp)) && eCntr < 3)     // read dir and cnt entries
  1319.             {
  1320.             if(*dirp->d_name != '.')                // don't count if sys file
  1321.                 eCntr++;
  1322.             }
  1323.         if(eCntr > 2)
  1324.             mail = YES;
  1325.         closedir(dp);
  1326.         }
  1327.     else
  1328.         [self showAlert:"Error opening Mail queue directory"];
  1329.  
  1330.     return mail;
  1331. }
  1332. //************** Diagnostics Window delegate methods **************************
  1333. //*****************************************************************************
  1334. //
  1335. //         called whenever the user minituriazes our Diagnostics window.
  1336. //
  1337. //*****************************************************************************
  1338.  
  1339. - windowWillMiniaturize:sender toMiniwindow:miniwindow 
  1340. {
  1341.     return [sender setMiniwindowIcon:"miniWinIcon"];
  1342. }
  1343. //*****************************************************************************
  1344. //
  1345. //         called whenever the user closes our Diagnostics window.
  1346. //
  1347. //*****************************************************************************
  1348.  
  1349. - windowWillClose:sender  
  1350. {
  1351.     if(![sender isKindOf:[Panel class]])    // simple test to see if diag
  1352.         {                                    // win is what is being closed
  1353.         if(!NXWriteDefault([NXApp appName], DISPLAYD, "NO"))
  1354.             [self showAlert:"ddbWriteError"];
  1355.         }
  1356.  
  1357.     return self;
  1358. }
  1359.  
  1360. @end
  1361.  
  1362. //*****************************************************************************
  1363. //
  1364. //         c thread loop which listens for RPC telling us to link 
  1365. //
  1366. //*****************************************************************************
  1367.  
  1368. any_t server_loop(any_t port)
  1369. {
  1370. struct message msg, reply;
  1371. kern_return_t ret;
  1372.         
  1373.     while (TRUE)
  1374.         {        
  1375.                 /* Receive a request from a client. */
  1376.         msg.head.msg_local_port = (port_t)port;
  1377.         msg.head.msg_size = sizeof(struct message);
  1378.         ret = msg_receive(&msg.head, MSG_OPTION_NONE, 0);
  1379.         if (ret != RCV_SUCCESS)                            /* ignore errors */
  1380.             continue; 
  1381.     
  1382.                     /* Feed the request into the server. */
  1383.             (void)nsRPC_server((msg_header_t *)&msg, (msg_header_t *)&reply);
  1384.     
  1385.                 /* Send a reply to the client. */
  1386.         reply.head.msg_local_port = (port_t)port;
  1387.         ret = msg_send(&reply.head, MSG_OPTION_NONE, 0);
  1388.         if (ret != SEND_SUCCESS)                         /* ignore errors */
  1389.             continue; 
  1390.         }
  1391.     return 0;
  1392. }
  1393. //*****************************************************************************
  1394. //
  1395. // This function is called by nsRPC_server, which was created by MiG.
  1396. // It is NOT directly called by any client process.
  1397. //
  1398. //*****************************************************************************
  1399.  
  1400. kern_return_t pppUp(port_t server)
  1401. {
  1402.     [[NXApp delegate] Link:nil];    
  1403.  
  1404.     return KERN_SUCCESS;
  1405. }
  1406.