home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Libraries / GUSI / GUSIDispatch.cp < prev    next >
Encoding:
Text File  |  1993-12-07  |  22.9 KB  |  1,114 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    GUSI                -    Grand Unified Socket Interface
  3. File        :    GUSIDispatch.cp-    Dispatch calls to their correct recipient
  4. Author    :    Matthias Neeracher
  5. Started    :    24Mar92                                Language    :    MPW C/C++
  6. Modified    :    31Mar92    MN    unix domain socket calls
  7.                 16Apr92    MN    User interrupt stuff
  8.                 17Apr92    MN    Spin routines
  9.                 18Apr92    MN    Changed read/write/send/recv dispatchers
  10.                 19Apr92    MN    C++ Rewrite
  11.                 06Jun92    MN    Feature
  12.                 27Jun92    MN    choose(), hasNewSF
  13.                 13Jul92    MN    hasProcessMgr
  14.                 30Jul92    MN    Features with initializers
  15.                 03Aug92    MN    Move Scatter/Gather to GUSIBuffer.cp
  16.                 05Aug92    MN    Change the way standard I/O channels are opened
  17.                 30Aug92    MN    Move hasPPC to GUSIPPC.cp, AppleTalkIdentity
  18.                 12Sep92    MN    getdtablesize()
  19.                 05Oct92    MN    Small fix in event dispatching
  20.                 25Nov92    MN    Still trying to get standard descriptors for standalone programs right. sigh.
  21.                 03Jan93    MN    GUSIConfiguration
  22.                 17Jan93    MN    Be more careful about user aborts.
  23.                 31Jan93    MN    Introducing daemons (pleased to meet you, hope you guess my name)
  24.                 13May93    MN    Limit Search for configuration resource to application
  25.                 15May93    MN    Try to keep errno always set on error returns
  26.                 21May93    MN    Suffixes
  27.                 20Jun93    MN    Further subtleties in console handling 
  28.                 27Jun93    MN    ftruncate
  29.                 27Jun93    MN    {pre,post}_select
  30.                 12Nov93    MN    Two time loser workaround for flush bug
  31.                 22Nov93    MN    Extend two time loser for EBADF
  32.                 24Nov93    MN    Flush stdio before closing
  33. Last        :    24Nov93
  34. *********************************************************************/
  35.  
  36. #include "GUSI_P.h"
  37. #include "SetJmp.h"
  38. #include "Signal.h"
  39. #include "CursorCtl.h"
  40. #include "Resources.h"
  41. #include "Events.h" 
  42. #include "Windows.h"
  43. #include "Desk.h"
  44. #include "Script.h"
  45. #include "OSEvents.h"
  46. #include "Traps.h"
  47. #include "CommResources.h"
  48. #include "CTBUtilities.h"
  49. #include "Connections.h"
  50. #include "FileTransfers.h"
  51. #include "Terminals.h"
  52. #include "EPPC.h"
  53. #include "PLStringFuncs.h"
  54.  
  55. /***************************** Globals ******************************/
  56.  
  57. const GUSIConfiguration GUSIConfig;        // Change the order of these two declarations
  58. SocketTable                    Sockets;            //     and you'll regret it (ARM §12.6.1)
  59. GUSISpinFn                     GUSISpin     = GUSIDefaultSpin;
  60. static GUSIEvtHandler *    evtHandler    = nil;
  61. static short                evtMask        = 0;
  62. static int                    lastShutdown= -1;
  63.  
  64. Feature     hasMakeFSSpec(
  65.                 gestaltFSAttr,
  66.                 (1<<gestaltHasFSSpecCalls),
  67.                 (1<<gestaltHasFSSpecCalls));
  68. Feature     hasAlias(
  69.                 gestaltAliasMgrAttr,
  70.                 (1<<gestaltAliasMgrPresent),
  71.                 (1<<gestaltAliasMgrPresent));
  72. Feature    hasWNE(_WaitNextEvent, ToolTrap);
  73. Feature    hasNewSF(
  74.                 gestaltStandardFileAttr,
  75.                 (1<<gestaltStandardFile58),
  76.                 (1<<gestaltStandardFile58));
  77. Feature     hasProcessMgr(
  78.                 gestaltOSAttr,
  79.                 (1<<gestaltLaunchControl),
  80.                 (1<<gestaltLaunchControl));
  81. Feature hasCRM_P(
  82.                 gestaltCRMAttr,
  83.                 (1<<gestaltCRMPresent),
  84.                 (1<<gestaltCRMPresent));
  85. Feature hasCRM(hasCRM_P, InitCRM);
  86. Feature hasCTB(hasCRM, InitCTBUtilities);
  87. Feature hasStdNBP_P(
  88.                 gestaltStdNBPAttr,
  89.                 (1<<gestaltStdNBPPresent),
  90.                 (1<<gestaltStdNBPPresent));
  91. Feature hasStdNBP(hasCTB, hasStdNBP_P);
  92. Feature hasCM(hasCTB, InitCM);
  93. Feature hasFT(hasCTB, InitFT);
  94. Feature hasTM(hasCTB, InitTM);
  95. Feature hasAppleEvents(
  96.                 gestaltAppleEventsAttr,
  97.                 (1<<gestaltAppleEventsPresent),
  98.                 (1<<gestaltAppleEventsPresent));
  99. Feature hasRevisedTimeMgr(
  100.             gestaltTimeMgrVersion,
  101.             2L);
  102.  
  103. /*********************** GUSIConfiguration members ************************/
  104.  
  105. Boolean     GUSIConfiguration::firstTime = false;
  106. short        GUSIConfiguration::we;
  107.  
  108. pascal OSErr 
  109. GetOffMyCloud(AppleEvent* /*messagein*/, AppleEvent* /*reply*/, long /*refIn*/)
  110. {
  111.     return errAEEventNotHandled;
  112. }
  113.  
  114. GUSIConfiguration::GUSIConfiguration()
  115. {
  116.     typedef GUSIConfiguration **    GUSIConfHdl;
  117.     short    oldResFile = CurResFile();
  118.     
  119.     if (!firstTime)
  120.         we = oldResFile;
  121.     else
  122.         UseResFile(we);
  123.         
  124.     GUSIConfHdl config     =    GUSIConfHdl(Get1Resource('GU∑I', GUSIRsrcID));
  125.     long            confSize    =    config ? GetHandleSize(Handle(config)) : 0;
  126.     const long    stdEvt[]    =    {
  127.         kAEOpenApplication,
  128.         kAEOpenDocuments,
  129.         kAEQuitApplication,
  130.         kAEPrintDocuments
  131.     };
  132.     
  133.     if (confSize)
  134.         *this = **config;
  135.     
  136.     if (confSize < 4 || !defaultType)
  137.         defaultType    =    'TEXT';
  138.     if (confSize < 8 || !defaultCreator)
  139.         defaultCreator    =    'MPS ';
  140.     if (confSize < 9) 
  141.         autoSpin    =    1;            // do automatic spin on read/write
  142.     if (confSize < 10) {
  143.         noChdir    =    false;    // Use chdir()
  144.         accurStat=    false;    // st_nlink = # of entries + 2
  145.         tcpDaemon=    false;
  146.         udpDaemon=    false;
  147.     }
  148.     if (confSize < 14)
  149.         version = '0102';
  150.     if (version < '0120')
  151.         numSuffices = 0;
  152.     
  153.     if (!numSuffices)
  154.         suffices = nil;
  155.     else if (suffices = new GUSISuffix[numSuffices]) {
  156.         memcpy(suffices, &(*config)->numSuffices+1, numSuffices*sizeof(GUSISuffix));
  157.         for (int i=0; i<numSuffices; i++)
  158.             for (int j=0; j<4; j++)
  159.                 if (((char *) (suffices+i))[j] == ' ')
  160.                     ((char *) (suffices+i))[j] = 0;
  161.     }
  162.     
  163.     if (!firstTime) {
  164.         firstTime    =    true;
  165.         
  166.         if (!noChdir)
  167.             chdir(":");
  168.         
  169.         if (IsDaemon()) 
  170.             for (int i = 0; i < sizeof(stdEvt); i++) 
  171.                 AEInstallEventHandler(
  172.                     kCoreEventClass, 
  173.                     stdEvt[i], 
  174.                     EventHandlerProcPtr(GetOffMyCloud), 
  175.                     0, 
  176.                     false);
  177.     } else
  178.         UseResFile(oldResFile);
  179. }
  180.  
  181. void GUSIConfiguration::SetDefaultFType(const TFileSpec & name) const
  182. {
  183.     FInfo    info;    
  184.  
  185.     if (HGetFInfo(name.vRefNum, name.parID, name.name, &info))
  186.         return;
  187.  
  188.     Ptr dot = PLstrrchr(name.name, '.');
  189.     
  190.     if (dot && (name.name[0] - (dot-Ptr(name.name))) <= 4) {
  191.         char searchsuffix[5];
  192.         
  193.         strncpy(searchsuffix, dot+1, name.name[0] - (dot-Ptr(name.name)));
  194.         
  195.         for (int i = 0; i<numSuffices; i++)
  196.             if (!strncmp(suffices[i].suffix, searchsuffix, 4)) {
  197.                 info.fdType     =    suffices[i].suffType;
  198.                 info.fdCreator    =    suffices[i].suffCreator;
  199.                 
  200.                 goto determined;
  201.             }
  202.     }
  203.  
  204.     info.fdType     =    defaultType;
  205.     info.fdCreator    =    defaultCreator;
  206.  
  207. determined:    
  208.     HSetFInfo(name.vRefNum, name.parID, name.name, &info);
  209. }
  210.  
  211. inline void GUSIConfiguration::DoAutoSpin() const 
  212. {
  213.     if (autoSpin)
  214.         SAFESPIN(0, SP_AUTO_SPIN, autoSpin);
  215. }
  216.  
  217. Boolean GUSIConfiguration::IsDaemon() const
  218. {
  219.     return tcpDaemon || udpDaemon;
  220. }
  221.  
  222. /************************ External routines *************************/
  223.  
  224. int getdtablesize()
  225. {
  226.     return GUSI_MAX_FD;
  227. }
  228.  
  229. int socket(int domain, int type, int protocol)
  230. {
  231.     SocketDomain *    dom;
  232.     Socket *         sock;
  233.     int                fd;
  234.  
  235.     if (dom = SocketDomain::Domain(domain))
  236.         if (sock = dom->socket(type, protocol))
  237.             if ((fd = Sockets.Install(sock)) != -1)
  238.                 return fd;
  239.             else
  240.                 delete sock;
  241.  
  242.     if (!errno)
  243.         return GUSI_error(ENOMEM);
  244.     else
  245.         return -1;
  246. }
  247.  
  248. extern "C" int file_open(const char * name, int flags);
  249. extern Boolean IsDevice(const char * fn);
  250.  
  251. int open(const char * filename, int oflag)
  252. {
  253.     extern int     StandAlone;
  254.     static int     ignore = 3;
  255.     Socket *     sock;
  256.     int            fd;
  257.  
  258.     if (StandAlone && ignore && IsDevice(filename)) {        // Standalone programs open console manually
  259.         if (GUSIConfig.IsDaemon())
  260.             return 3 - (ignore--);
  261.             
  262.         close(3 - ignore);
  263.         
  264.         --ignore;
  265.     }
  266.  
  267.     if (sock = FileSockets.open(filename, oflag))    {
  268.         if ((fd = Sockets.Install(sock)) != -1)
  269.             return fd;
  270.         else
  271.             delete sock;
  272.     }
  273.  
  274.     if (!errno)
  275.         return GUSI_error(ENOMEM);
  276.     else
  277.         return -1;
  278. }
  279.  
  280. int choose(int domain, int type, char * prompt, void * constraint, int flags, void * name, int * namelen)
  281. {
  282.     SocketDomain *    dom;
  283.  
  284.     if (dom = SocketDomain::Domain(domain))
  285.         return dom->choose(type, prompt, constraint, flags, name, namelen);
  286.  
  287.     return -1;
  288. }
  289.  
  290. int bind(int s, const struct sockaddr *name, int namelen)
  291. {
  292.     Socket *    sock    =    Sockets[s];
  293.  
  294.     return sock ? sock->bind((void *) name, namelen) : -1;
  295. }
  296.  
  297. int connect(int s, const struct sockaddr *addr, int addrlen)
  298. {
  299.     Socket *    sock    =    Sockets[s];
  300.  
  301.     return sock ? sock->connect((void *) addr, addrlen) : -1;
  302. }
  303.  
  304. int listen(int s, int qlen)
  305. {
  306.     Socket *    sock    =    Sockets[s];
  307.  
  308.     return sock ? sock->listen(qlen) : -1;
  309. }
  310.  
  311. int accept(int s, struct sockaddr *addr, int *addrlen)
  312. {
  313.     Socket *    sock    =    Sockets[s];
  314.  
  315.     if (sock)
  316.         if (sock    = sock->accept(addr, addrlen))
  317.             if ((s = Sockets.Install(sock)) != -1)
  318.                 return s;
  319.             else
  320.                 delete sock;
  321.  
  322.     return -1;
  323. }
  324.  
  325. int close(int s)
  326. {
  327.     lastShutdown    =    -1;
  328.     
  329.     return Sockets.Remove(s);
  330. }
  331.  
  332. int read(int s, char *buffer, unsigned buflen)
  333. {
  334.     GUSIConfig.DoAutoSpin();
  335.     
  336.     Socket *    sock    =    Sockets[s];
  337.  
  338.     return sock ? sock->read(buffer, buflen) : -1;
  339. }
  340.  
  341. int readv(int s, const struct iovec *iov, int count)
  342. {
  343.     GUSIConfig.DoAutoSpin();
  344.     
  345.     Socket *    sock    =    Sockets[s];
  346.  
  347.     if (sock)    {
  348.         Scatterer    scatt(iov, count);
  349.  
  350.         if (scatt)
  351.             return scatt.length(sock->read(scatt.buffer(), scatt.buflen()));
  352.         else
  353.             return GUSI_error(ENOMEM);
  354.     } else
  355.         return -1;
  356. }
  357.  
  358. int recv(int s, void *buffer, int buflen, int flags)
  359. {
  360.     GUSIConfig.DoAutoSpin();
  361.     
  362.     int         fromlen     =    0;
  363.     Socket *    sock        =    Sockets[s];
  364.  
  365.     return sock ? sock->recvfrom(buffer, buflen, flags, nil, &fromlen) : -1;
  366. }
  367.  
  368. int recvfrom(int s, void *buffer, int buflen, int flags, struct sockaddr *from, int *fromlen)
  369. {
  370.     GUSIConfig.DoAutoSpin();
  371.     
  372.     Socket *    sock    =    Sockets[s];
  373.  
  374.     return sock ? sock->recvfrom(buffer, buflen, flags, from, fromlen) : -1;
  375. }
  376.  
  377. int recvmsg(int s, struct msghdr *msg, int flags)
  378. {
  379.     GUSIConfig.DoAutoSpin();
  380.     
  381.     Socket *    sock    =    Sockets[s];
  382.  
  383.     if (sock)    {
  384.         Scatterer    scatt(msg->msg_iov, msg->msg_iovlen);
  385.  
  386.         if (scatt)
  387.             return
  388.                 scatt.length(
  389.                     sock->recvfrom(
  390.                         scatt.buffer(),
  391.                         scatt.buflen(),
  392.                         flags,
  393.                         msg->msg_name,
  394.                         (int *)&msg->msg_namelen));
  395.         else
  396.             return GUSI_error(ENOMEM);
  397.     } else
  398.         return -1;
  399. }
  400.  
  401. int write(int s, const char *buffer, unsigned buflen)
  402. {
  403.     /* fflush() in the MPW stdio library doesn't take no for an answer.
  404.         Our workaround is to treat a second subsequent ESHUTDOWN or EBADF as 
  405.         an invitation to lie by pretending the write worked.
  406.     */
  407.     
  408.     int    len;
  409.     
  410.     GUSIConfig.DoAutoSpin();
  411.     
  412.     Socket *    sock    =    Sockets[s];
  413.  
  414.     if (sock && (len = sock->write((char *) buffer, buflen)) != -1)
  415.         return len;
  416.         
  417.     switch (errno) {
  418.     case ESHUTDOWN:
  419.     case EBADF:
  420.         if (lastShutdown == s) {
  421.             lastShutdown = -1;
  422.             
  423.             return buflen;
  424.         } else {
  425.             lastShutdown = s;
  426.             
  427.             return -1;
  428.         }
  429.     default:
  430.         return -1;
  431.     }
  432. }
  433.  
  434. int writev(int s, const struct iovec *iov, int count)
  435. {
  436.     GUSIConfig.DoAutoSpin();
  437.     
  438.     Socket *    sock    =    Sockets[s];
  439.  
  440.     if (sock)    {
  441.         Gatherer    gath(iov, count);
  442.  
  443.         if (gath)
  444.             return gath.length(sock->write(gath.buffer(), gath.buflen()));
  445.         else
  446.             return GUSI_error(ENOMEM);
  447.     } else
  448.         return -1;
  449. }
  450.  
  451. int send(int s, void *buffer, int buflen, int flags)
  452. {
  453.     GUSIConfig.DoAutoSpin();
  454.     
  455.     Socket *    sock    =    Sockets[s];
  456.  
  457.     return sock ? sock->sendto(buffer, buflen, flags, nil, 0) : -1;
  458. }
  459.  
  460. int sendto(int s, void *buffer, int buflen, int flags, const struct sockaddr *to, int tolen)
  461. {
  462.     GUSIConfig.DoAutoSpin();
  463.     
  464.     Socket *    sock    =    Sockets[s];
  465.  
  466.     return sock ? sock->sendto(buffer, buflen, flags, (void *) to, tolen) : -1;
  467. }
  468.  
  469. int sendmsg(int s, const struct msghdr *msg,int flags)
  470. {
  471.     GUSIConfig.DoAutoSpin();
  472.     
  473.     Socket *    sock    =    Sockets[s];
  474.  
  475.     if (sock)    {
  476.         Gatherer    gath(msg->msg_iov, msg->msg_iovlen);
  477.  
  478.         if (gath)
  479.             return
  480.                 gath.length(
  481.                     sock->sendto(
  482.                         gath.buffer(),
  483.                         gath.buflen(),
  484.                         flags,
  485.                         msg->msg_name,
  486.                         msg->msg_namelen));
  487.         else
  488.             return GUSI_error(ENOMEM);
  489.     } else
  490.         return -1;
  491. }
  492.  
  493. int select(int width, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
  494. {
  495.     Socket    *    sock;
  496.     long             count;
  497.     int             s;
  498.     long             starttime, waittime;
  499.     fd_set         rd, wd, ed;
  500.     Boolean        r,w,e;
  501.     Boolean *    canRead;
  502.     Boolean *    canWrite;
  503.     Boolean *    exception;
  504.  
  505.     count = 0;
  506.     FD_ZERO(&rd);
  507.     FD_ZERO(&wd);
  508.     FD_ZERO(&ed);
  509.  
  510.     if (timeout) {
  511.         waittime =  timeout->tv_sec*60 + timeout->tv_usec/16666;
  512.         starttime = TickCount();
  513.     }
  514.  
  515.     // Check files for kosherness
  516.  
  517.     for (s = 0; s < width ; ++s)
  518.         if (    (readfds && FD_ISSET(s,readfds))
  519.             ||    (writefds && FD_ISSET(s,writefds))
  520.             ||    (exceptfds && FD_ISSET(s,exceptfds))
  521.         )
  522.             if (!Sockets[s])
  523.                 return GUSI_error(EBADF);
  524.     
  525.     for (s = 0; s < width ; ++s)
  526.         if (sock = Sockets[s]) {
  527.             r = readfds && FD_ISSET(s,readfds);
  528.             w = writefds && FD_ISSET(s,writefds);
  529.             e = exceptfds && FD_ISSET(s,exceptfds);
  530.  
  531.             if (r || w || e)
  532.                 sock->pre_select(r, w, e);
  533.         }
  534.         
  535.     do {
  536.         for (s = 0; s < width ; ++s)  {
  537.             if (sock = Sockets[s]) {
  538.                 r = false;
  539.                 w = false;
  540.                 e = false;
  541.  
  542.                 canRead = (readfds && FD_ISSET(s,readfds)) ? &r : nil;
  543.                 canWrite = (writefds && FD_ISSET(s,writefds)) ? &w : nil;
  544.                 exception = (exceptfds && FD_ISSET(s,exceptfds)) ? &e : nil;
  545.  
  546.                 if (canRead || canWrite || exception)    {
  547.                     count    += sock->select(canRead, canWrite, exception);
  548.  
  549.                     if (r)
  550.                         FD_SET(s,&rd);
  551.                     if (w)
  552.                         FD_SET(s,&wd);
  553.                     if (e)
  554.                         FD_SET(s,&ed);
  555.                 }
  556.             }
  557.         }
  558.         SPIN(false, SP_SELECT, 0);
  559.     }  while(!count &&(!timeout || TickCount() - starttime < waittime));
  560.  
  561.     for (s = 0; s < width ; ++s)
  562.         if (sock = Sockets[s]) {
  563.             r = readfds && FD_ISSET(s,readfds);
  564.             w = writefds && FD_ISSET(s,writefds);
  565.             e = exceptfds && FD_ISSET(s,exceptfds);
  566.  
  567.             if (r || w || e)
  568.                 sock->post_select(r, w, e);
  569.         }
  570.         
  571.  
  572.     if (readfds)
  573.         *readfds = rd;
  574.     if (writefds)
  575.         *writefds = wd;
  576.     if (exceptfds)
  577.         *exceptfds = ed;
  578.  
  579.     return count;
  580. }
  581.  
  582. int getsockname(int s, struct sockaddr *name, int *namelen)
  583. {
  584.     Socket *    sock    =    Sockets[s];
  585.  
  586.     return sock ? sock->getsockname(name, namelen) : -1;
  587. }
  588.  
  589. int getpeername(int s, struct sockaddr *name, int *namelen)
  590. {
  591.     Socket *    sock    =    Sockets[s];
  592.  
  593.     return sock ? sock->getpeername(name, namelen) : -1;
  594. }
  595.  
  596. int shutdown(int s, int how)
  597. {
  598.     Socket *    sock    =    Sockets[s];
  599.  
  600.     return sock ? sock->shutdown(how) : -1;
  601. }
  602.  
  603. int fcntl(int s, unsigned int cmd, int arg)
  604. {
  605.     Socket *    sock    =    Sockets[s];
  606.  
  607.     if (sock)
  608.         return (cmd == F_DUPFD) ? Sockets.Install(sock, arg) : sock->fcntl(cmd, arg);
  609.     else
  610.         return -1;
  611. }
  612.  
  613. int dup(int s)
  614. {
  615.     Socket *    sock    =    Sockets[s];
  616.  
  617.     return sock ? Sockets.Install(sock) : -1;
  618. }
  619.  
  620. int dup2(int s, int s1)
  621. {
  622.     Socket *    sock    =    Sockets[s];
  623.  
  624.     if (!sock)
  625.         return -1;
  626.  
  627.     if (Sockets[s1])
  628.         Sockets.Remove(s1);
  629.  
  630.     return Sockets.Install(sock, s1);
  631. }
  632.  
  633. int ioctl(int s, unsigned int request, long *argp)
  634. {
  635.     Socket *    sock    =    Sockets[s];
  636.  
  637.     return sock ? sock->ioctl(request, argp) : -1;
  638. }
  639.  
  640. int getsockopt(int s, int level, int optname, void *optval, int * optlen)
  641. {
  642.     Socket *    sock    =    Sockets[s];
  643.  
  644.     return sock ? sock->getsockopt(level, optname, optval, optlen) : -1;
  645. }
  646.  
  647. int setsockopt(int s, int level, int optname, void *optval, int optlen)
  648. {
  649.     Socket *    sock    =    Sockets[s];
  650.  
  651.     return sock ? sock->setsockopt(level, optname, optval, optlen) : -1;
  652. }
  653.  
  654. int fstat(int s, struct stat * buf)
  655. {
  656.     Socket *    sock    =    Sockets[s];
  657.  
  658.     return sock ? sock->fstat(buf) : -1;
  659. }
  660.  
  661. long lseek(int s, long offset, int whence)
  662. {
  663.     Socket *    sock    =    Sockets[s];
  664.  
  665.     return sock ? sock->lseek(offset, whence) : -1;
  666. }
  667.  
  668. int ftruncate(int s, long offset)
  669. {
  670.     Socket *    sock    =    Sockets[s];
  671.  
  672.     return sock ? sock->ftruncate(offset) : -1;
  673. }
  674.  
  675. int isatty(int s)
  676. {
  677.     Socket *    sock    =    Sockets[s];
  678.  
  679.     return sock ? sock->isatty() : -1;
  680. }
  681.  
  682. int GUSI_error(int err)
  683. {
  684.     errno =    err;
  685.  
  686.     return -1;
  687. }
  688.  
  689. void * GUSI_error_nil(int err)
  690. {
  691.     errno =    err;
  692.  
  693.     return nil;
  694. }
  695.  
  696. void GUSISetSpin(GUSISpinFn routine)
  697. {
  698.     GUSISpin = routine;
  699. }
  700.  
  701. GUSISpinFn GUSIGetSpin()
  702. {
  703.     return GUSISpin;
  704. }
  705.  
  706. int GUSISetEvents(GUSIEvtTable table)
  707. {
  708.     short    evt;
  709.  
  710.     evtHandler    =    table;
  711.     evtMask        =    0;
  712.  
  713.     for (evt = 0; evt<16; ++evt)
  714.         if (evtHandler[evt])
  715.             evtMask    |=    1 << evt;
  716.  
  717.     return 0;
  718. }
  719.  
  720. GUSIEvtHandler * GUSIGetEvents(void)
  721. {
  722.     return evtHandler;
  723. }
  724.  
  725. /*********************** SocketDomain members ***********************/
  726.  
  727. SocketDomain *    SocketDomain::domains[GUSI_MAX_DOMAIN];
  728.  
  729. SocketDomain * SocketDomain::Domain(int domain)
  730. {
  731.     if (domain < 0 || domain >= GUSI_MAX_DOMAIN || !domains[domain])    {
  732.         GUSI_error(EINVAL);
  733.  
  734.         return nil;
  735.     } else
  736.         return domains[domain];
  737. }
  738.  
  739. SocketDomain::SocketDomain(int domain)
  740. {
  741.     if (domains[domain])    {
  742.         Str63    msg;
  743.  
  744.         sprintf((char *) msg+1, "Duplicate declaration for domain %d\n", domain);
  745.         msg[0] = strlen((char *) msg+1);
  746.  
  747.         DebugStr(msg);
  748.     }
  749.  
  750.     domains[domain]    =    this;
  751. }
  752.  
  753. SocketDomain::~SocketDomain()
  754. {
  755. }
  756.  
  757. // Default implementations of socket() and open() just returns an error
  758.  
  759. Socket * SocketDomain::open(const char *, int)
  760. {
  761.     GUSI_error(EOPNOTSUPP);
  762.  
  763.     return nil;
  764. }
  765.  
  766. Socket * SocketDomain::socket(int, short)
  767. {
  768.     GUSI_error(EOPNOTSUPP);
  769.  
  770.     return nil;
  771. }
  772.  
  773. int SocketDomain::choose(int, char *, void *, int, void *, int *)
  774. {
  775.     return GUSI_error(EOPNOTSUPP);
  776. }
  777.  
  778. void SocketDomain::DontStrip()
  779. {
  780. }
  781.  
  782. /******************** DeviceSocketDomain member ********************/
  783.  
  784. DeviceSocketDomain * DeviceSocketDomain::firstDev            =    nil;
  785. const    Socket *            DeviceSocketDomain::TryNextDevice    =    (Socket *) -1;
  786.  
  787. DeviceSocketDomain::DeviceSocketDomain(int domain)
  788.     :    SocketDomain(domain)
  789. {
  790.     nextDev    =    firstDev;
  791.     firstDev    =    this;
  792. }
  793.  
  794. /*********************** LurkSocket members ************************/
  795.  
  796. class LurkSocket : public Socket {
  797. public:
  798.     LurkSocket(int descr);
  799. };
  800.  
  801. LurkSocket::LurkSocket(int descr)
  802.     : Socket()
  803. {
  804.     lurking    =    true;
  805.     lurkDescr=    char(descr);
  806. }
  807.  
  808. /*********************** SocketTable members ************************/
  809.  
  810. SocketTable::SocketTable()
  811. {
  812.     for (int i = 0; i < 3; i++) {
  813.         if (GUSIConfig.IsDaemon())
  814.             sockets[i]    =    new LurkSocket(i);
  815.         else
  816.             sockets[i]    =     FileSockets.stdopen(i);
  817.  
  818.         ++sockets[i]->refCount;
  819.     }
  820. }
  821.  
  822. int SocketTable::Install(Socket * sock, int start)
  823. {
  824.     short    fd;
  825.  
  826.     if (start<0 || start >= GUSI_MAX_FD)
  827.         return GUSI_error(EINVAL);
  828.  
  829.     for (fd=start; fd<GUSI_MAX_FD; ++fd)
  830.         if (!sockets[fd])    {
  831.             sockets[fd] = sock;
  832.             
  833.             ++sock->refCount;
  834.  
  835.             return fd;
  836.         }
  837.  
  838.     return GUSI_error(EMFILE);
  839. }
  840.  
  841. void SocketTable::Possess(int descr, Socket * sock)
  842. {
  843.     int i;
  844.     
  845.     for (i = 0; i<GUSI_MAX_FD; ++i)
  846.         if (sockets[i]->lurking && sockets[i]->lurkDescr == descr) {
  847.             close(i);
  848.             if (sockets[i] = sock)
  849.                 ++sock->refCount;
  850.         }
  851. }
  852.  
  853. int SocketTable::Remove(int fd)
  854. {
  855.     Socket *    sock;
  856.  
  857.     if (fd<0 || fd >= GUSI_MAX_FD || !(sock = sockets[fd]))
  858.         return GUSI_error(EBADF);
  859.  
  860.     sockets[fd]     =    nil;
  861.  
  862.     if (!--sock->refCount)
  863.         delete sock;
  864.  
  865.     return 0;
  866. }
  867.  
  868. Socket * SocketTable::operator[](int fd)
  869. {
  870.     Socket * sock;
  871.  
  872. restart:
  873.     if (fd<0 || fd >= GUSI_MAX_FD || !(sock = sockets[fd]))    {
  874.         GUSI_error(EBADF);
  875.  
  876.         return nil;
  877.     } else if (sock->lurking) {
  878.         SPINP(sockets[fd]->lurking, SP_MISC, 0);
  879.         
  880.         goto restart; 
  881.     } else
  882.         return sock;
  883. }
  884.  
  885. SocketTable::~SocketTable()
  886. {
  887.     int i;
  888.     extern FILE * _lastbuf;
  889.  
  890.     // Flush & vclose stdio files (necessary to flush buffers)
  891.     // This implementation is not nice, but who cares ?
  892.     // In case you wonder, _iob is defined in <stdio.h>
  893.  
  894.     for (i = 0; _iob+i<_lastbuf; i++)
  895.         fflush(_iob+i);
  896.  
  897.     for (i = 0; _iob+i<_lastbuf; i++)
  898.         fclose(_iob+i);
  899.  
  900.     // Close all files
  901.  
  902.     for (i = 0; i<GUSI_MAX_FD; ++i)
  903.         if (sockets[i])
  904.             close(i);
  905. }
  906.  
  907. /********************** Default spin function ***********************/
  908.  
  909. /* Borrowed from tech note 263 */
  910.  
  911. #define kMaskModifiers      0xFE00         // we need the modifiers without the
  912.                                            // command key for KeyTrans
  913. #define kMaskVirtualKey     0x0000FF00     // get virtual key from event message
  914.                                            // for KeyTrans
  915. #define kUpKeyMask          0x0080
  916. #define kShiftWord          8              // we shift the virtual key to mask it
  917.                                            // into the keyCode for KeyTrans
  918. #define kMaskASCII1         0x00FF0000     // get the key out of the ASCII1 byte
  919. #define kMaskASCII2         0x000000FF     // get the key out of the ASCII2 byte
  920. #define kPeriod             0x2E           // ascii for a period
  921.  
  922. static Boolean CmdPeriod(EventRecord *theEvent)
  923. {
  924.       Boolean  fTimeToQuit;
  925.       short    keyCode;
  926.       long     virtualKey, keyInfo, lowChar, highChar, state, keyCId;
  927.       Handle   hKCHR;
  928.     Ptr         KCHRPtr;
  929.  
  930.     fTimeToQuit = false;
  931.  
  932.     if (((*theEvent).what == keyDown) || ((*theEvent).what == autoKey)) {
  933.  
  934.         // see if the command key is down.  If it is, find out the ASCII
  935.         // equivalent for the accompanying key.
  936.  
  937.         if ((*theEvent).modifiers & cmdKey ) {
  938.  
  939.             virtualKey = ((*theEvent).message & kMaskVirtualKey) >> kShiftWord;
  940.             // And out the command key and Or in the virtualKey
  941.             keyCode    = short(((*theEvent).modifiers & kMaskModifiers) | virtualKey);
  942.             state      = 0;
  943.  
  944.             hKCHR = nil;  /* set this to nil before starting */
  945.              KCHRPtr = (Ptr)GetEnvirons(smKCHRCache);
  946.  
  947.             if ( !KCHRPtr ) {
  948.                 keyCId = GetScript(short(GetEnvirons(smKeyScript)), smScriptKeys);
  949.  
  950.                 hKCHR   = GetResource('KCHR',short(keyCId));
  951.                 KCHRPtr = *hKCHR;
  952.             }
  953.  
  954.             if (KCHRPtr) {
  955.                 keyInfo = KeyTrans(KCHRPtr, keyCode, &state);
  956.                 if (hKCHR)
  957.                     ReleaseResource(hKCHR);
  958.             } else
  959.                 keyInfo = (*theEvent).message;
  960.  
  961.             lowChar =  keyInfo &  kMaskASCII2;
  962.             highChar = (keyInfo & kMaskASCII1) >> 16;
  963.             if (lowChar == kPeriod || highChar == kPeriod)
  964.                 fTimeToQuit = true;
  965.  
  966.         }  // end the command key is down
  967.     }  // end key down event
  968.  
  969.     return( fTimeToQuit );
  970. }
  971.  
  972. Boolean GUSIInterrupt()
  973. {
  974.     EvQElPtr        eventQ;
  975.  
  976.     for (eventQ = (EvQElPtr) GetEvQHdr()->qHead; eventQ; )
  977.         if (CmdPeriod((EventRecord *) &eventQ->evtQWhat))
  978.             return true;
  979.         else
  980.             eventQ = (EvQElPtr)eventQ->qLink;
  981.     
  982.     return false;
  983. }
  984.  
  985. int GUSIDefaultSpin(spin_msg msg, long arg)
  986. {
  987.     static Boolean            inForeground    =    true;
  988.     extern int                StandAlone;
  989.     WindowPtr                win;
  990.     EventRecord                ev;
  991.  
  992.     if (inForeground)
  993.         SpinCursor(msg == SP_AUTO_SPIN ? short(arg) : 1);
  994.  
  995.     if (!inForeground || StandAlone)    {
  996.         if (GUSIInterrupt())
  997.             goto interrupt;
  998.             
  999.         if (hasWNE)    {
  1000.             if (WaitNextEvent(osMask|highLevelEventMask|mDownMask|evtMask, &ev, 1, nil))
  1001.                 switch (ev.what) {
  1002.                 case mouseDown:
  1003.                     if (!evtHandler || !evtHandler[mouseDown])
  1004.                         if (FindWindow(ev.where, &win) == inSysWindow)
  1005.                             SystemClick(&ev, win);
  1006.  
  1007.                     break;
  1008.                 case osEvt:
  1009.                     if (ev.message & 1)
  1010.                         inForeground    =    true;
  1011.                     else
  1012.                         inForeground    =    false;
  1013.                     break;
  1014.                 case kHighLevelEvent:
  1015.                     if (!evtHandler || !evtHandler[kHighLevelEvent])
  1016.                         if (hasAppleEvents)    // actually pretty likely, if we get HL Events
  1017.                             if (AEProcessAppleEvent(&ev))
  1018.                                 return -1;
  1019.                     break;
  1020.                 default:
  1021.                     break;
  1022.                 }
  1023.  
  1024.             if (ev.what >= 0 && ev.what < 24 && evtHandler && evtHandler[ev.what])
  1025.                 evtHandler[ev.what](&ev);
  1026.         } else {
  1027.             long     endTicks;
  1028.  
  1029.             SystemTask();
  1030.             GetNextEvent(evtMask, &ev);
  1031.  
  1032.             if (ev.what >= 0 && ev.what < 24 && evtHandler && evtHandler[ev.what])
  1033.                 evtHandler[ev.what](&ev);
  1034.  
  1035.             Delay(1, &endTicks);
  1036.         }
  1037.     }
  1038.  
  1039.     return 0;
  1040.  
  1041. interrupt:
  1042.     FlushEvents(-1, 0);
  1043.  
  1044.     return -1;
  1045. }
  1046.  
  1047. /************************** Feature members **************************/
  1048.  
  1049. Feature::Feature(short trapNum, TrapType tTyp)
  1050. {
  1051.     good =
  1052.         NGetTrapAddress(trapNum, tTyp) != NGetTrapAddress(_Unimplemented, ToolTrap);
  1053. }
  1054.  
  1055. Feature::Feature(OSType type, long value)
  1056. {
  1057.     long        attr;
  1058.  
  1059.     good = (!Gestalt(type, &attr) && (attr >= value));
  1060. }
  1061.  
  1062. Feature::Feature(OSType type, long mask, long value)
  1063. {
  1064.     long        attr;
  1065.  
  1066.     good = (!Gestalt(type, &attr) && ((attr & mask) == value));
  1067. }
  1068.  
  1069. Feature::Feature(const Feature & precondition, OSErrInitializer init)
  1070. {
  1071.     good    =    precondition && !init();
  1072. }
  1073.  
  1074. Feature::Feature(OSErrInitializer init)
  1075. {
  1076.     good    =    !init();
  1077. }
  1078.  
  1079. Feature::Feature(const Feature & precondition, voidInitializer init)
  1080. {
  1081.     if (precondition)    {
  1082.         good = true;
  1083.         init();
  1084.     } else
  1085.         good = false;
  1086. }
  1087.  
  1088. Feature::Feature(voidInitializer init)
  1089. {
  1090.     good = true;
  1091.     init();
  1092. }
  1093.  
  1094. Feature::Feature(const Feature & cond1, const Feature & cond2)
  1095. {
  1096.     good = cond1 && cond2;
  1097. }
  1098.  
  1099. OSErr AppleTalkIdentity(short & net, short & node)
  1100. {
  1101.     static short    mynet;
  1102.     static short    mynode;
  1103.     static OSErr    err = 1;
  1104.  
  1105.     if (err == 1)
  1106.         if (!(err = MPPOpen()))
  1107.             err = GetNodeAddress(&mynode, &mynet);
  1108.  
  1109.  
  1110.     net    =    mynet;
  1111.     node    =    mynode;
  1112.  
  1113.     return err;
  1114. }