home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / clients / xdm / chooser.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-26  |  19.9 KB  |  820 lines

  1. /*
  2.  * $XConsortium: chooser.c,v 1.10 91/08/25 10:49:47 keith Exp $
  3.  *
  4.  * Copyright 1990 Massachusetts Institute of Technology
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and its
  7.  * documentation for any purpose is hereby granted without fee, provided that
  8.  * the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of M.I.T. not be used in advertising or
  11.  * publicity pertaining to distribution of the software without specific,
  12.  * written prior permission.  M.I.T. makes no representations about the
  13.  * suitability of this software for any purpose.  It is provided "as is"
  14.  * without express or implied warranty.
  15.  *
  16.  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  17.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
  18.  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  20.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
  21.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22.  *
  23.  * Author:  Keith Packard, MIT X Consortium
  24.  */
  25.  
  26. /*
  27.  * Chooser - display a menu of names and let the user select one
  28.  */
  29.  
  30. /*
  31.  * Layout:
  32.  *
  33.  *  +--------------------------------------------------+
  34.  *  |             +------------------+                 |
  35.  *  |             |      Label       |                 |
  36.  *  |             +------------------+                 |
  37.  *  |    +-+--------------+                            |
  38.  *  |    |^| name-1       |                            |
  39.  *  |    ||| name-2       |                            |
  40.  *  |    |v| name-3       |                            |
  41.  *  |    | | name-4       |                            |
  42.  *  |    | | name-5       |                            |
  43.  *  |    | | name-6       |                            |
  44.  *  |    +----------------+                            |
  45.  *  |    cancel  accept  ping                          |
  46.  *  +--------------------------------------------------+
  47.  */
  48.  
  49. #include    <X11/Intrinsic.h>
  50. #include    <X11/StringDefs.h>
  51. #include    <X11/Xatom.h>
  52.  
  53. #include    <X11/Xaw/Paned.h>
  54. #include    <X11/Xaw/Label.h>
  55. #include    <X11/Xaw/Viewport.h>
  56. #include    <X11/Xaw/List.h>
  57. #include    <X11/Xaw/Box.h>
  58. #include    <X11/Xaw/Command.h>
  59.  
  60. #include    "dm.h"
  61.  
  62. #include    <X11/Xdmcp.h>
  63.  
  64. #include    <sys/types.h>
  65. #include    <stdio.h>
  66. #include    <ctype.h>
  67.  
  68. #ifdef SVR4
  69. #include    <sys/sockio.h>
  70. #endif
  71. #include    <sys/socket.h>
  72. #include    <netinet/in.h>
  73. #include    <sys/ioctl.h>
  74.  
  75. #define BROADCAST_HOSTNAME  "BROADCAST"
  76.  
  77. #ifdef hpux
  78. # include <sys/utsname.h>
  79. # ifdef HAS_IFREQ
  80. #  include <net/if.h>
  81. # endif
  82. #else
  83. #ifdef __convex__
  84. # include <sync/queue.h>
  85. # include <sync/sema.h>
  86. #endif
  87. # include <net/if.h>
  88. #endif /* hpux */
  89.  
  90. #include    <netdb.h>
  91.  
  92. Widget        toplevel, label, viewport, paned, list, box, cancel, acceptit, ping;
  93.  
  94. static void    CvtStringToARRAY8();
  95.  
  96. static struct _app_resources {
  97.     ARRAY8Ptr   xdmAddress;
  98.     ARRAY8Ptr    clientAddress;
  99.     int        connectionType;
  100. } app_resources;
  101.  
  102. #define offset(field) XtOffsetOf(struct _app_resources, field)
  103.  
  104. #define XtRARRAY8   "ARRAY8"
  105.  
  106. static XtResource  resources[] = {
  107.     {"xdmAddress",    "XdmAddress",  XtRARRAY8,    sizeof (ARRAY8Ptr),
  108.     offset (xdmAddress),        XtRString,    NULL },
  109.     {"clientAddress",    "ClientAddress",  XtRARRAY8,    sizeof (ARRAY8Ptr),
  110.     offset (clientAddress),        XtRString,    NULL },
  111.     {"connectionType",    "ConnectionType",   XtRInt,    sizeof (int),
  112.     offset (connectionType),    XtRImmediate,    (XtPointer) 0 }
  113. };
  114. #undef offset
  115.  
  116. static XrmOptionDescRec options[] = {
  117.     "-xdmaddress",    "*xdmAddress",        XrmoptionSepArg,    NULL,
  118.     "-clientaddress",    "*clientAddress",   XrmoptionSepArg,    NULL,
  119.     "-connectionType",    "*connectionType",  XrmoptionSepArg,    NULL,
  120. };
  121.  
  122. typedef struct _hostAddr {
  123.     struct _hostAddr    *next;
  124.     struct sockaddr    *addr;
  125.     int            addrlen;
  126.     xdmOpCode        type;
  127. } HostAddr;
  128.  
  129. static HostAddr    *hostAddrdb;
  130.  
  131. typedef struct _hostName {
  132.     struct _hostName    *next;
  133.     char        *fullname;
  134.     int            willing;
  135.     ARRAY8        hostname, status;
  136.     CARD16        connectionType;
  137.     ARRAY8        hostaddr;
  138. } HostName;
  139.  
  140. static HostName    *hostNamedb;
  141.  
  142. static int  socketFD;
  143.  
  144. static int  pingTry;
  145.  
  146. #define PING_INTERVAL    2000
  147. #define TRIES        3
  148.  
  149. static XdmcpBuffer    directBuffer, broadcastBuffer;
  150. static XdmcpBuffer    buffer;
  151.  
  152. /* ARGSUSED */
  153. static void
  154. PingHosts (closure, id)
  155.     XtPointer closure;
  156.     XtIntervalId *id;
  157. {
  158.     HostAddr    *hosts;
  159.  
  160.     for (hosts = hostAddrdb; hosts; hosts = hosts->next)
  161.     {
  162.     if (hosts->type == QUERY)
  163.         XdmcpFlush (socketFD, &directBuffer, hosts->addr, hosts->addrlen);
  164.     else
  165.         XdmcpFlush (socketFD, &broadcastBuffer, hosts->addr, hosts->addrlen);
  166.     }
  167.     if (++pingTry < TRIES)
  168.     XtAddTimeOut (PING_INTERVAL, PingHosts, (XtPointer) 0);
  169. }
  170.  
  171. char    **NameTable;
  172. int    NameTableSize;
  173.  
  174. static int
  175. HostnameCompare (a, b)
  176. #if __STDC__
  177.     const void *a, *b;
  178. #else
  179.     char *a, *b;
  180. #endif
  181. {
  182.     return strcmp (*(char **)a, *(char **)b);
  183. }
  184.  
  185. static void
  186. RebuildTable (size)
  187. {
  188.     char    **newTable = 0;
  189.     HostName    *names;
  190.     int        i;
  191.  
  192.     if (size)
  193.     {
  194.     newTable = (char **) malloc (size * sizeof (char *));
  195.     if (!newTable)
  196.         return;
  197.     for (names = hostNamedb, i = 0; names; names = names->next, i++)
  198.         newTable[i] = names->fullname;
  199.     qsort (newTable, size, sizeof (char *), HostnameCompare);
  200.     }
  201.     XawListChange (list, newTable, size, 0, TRUE);
  202.     if (NameTable)
  203.     free ((char *) NameTable);
  204.     NameTable = newTable;
  205.     NameTableSize = size;
  206. }
  207.  
  208. static int
  209. AddHostname (hostname, status, addr, willing)
  210.     ARRAY8Ptr        hostname, status;
  211.     struct sockaddr *addr;
  212.     int            willing;
  213. {
  214.     HostName    *new, **names, *name;
  215.     ARRAY8    hostAddr;
  216.     CARD16    connectionType;
  217.     int        fulllen;
  218.  
  219.     switch (addr->sa_family)
  220.     {
  221.     case AF_INET:
  222.     hostAddr.data = (CARD8 *) &((struct sockaddr_in *) addr)->sin_addr;
  223.     hostAddr.length = 4;
  224.     connectionType = FamilyInternet;
  225.     break;
  226.     default:
  227.     hostAddr.data = (CARD8 *) "";
  228.     hostAddr.length = 0;
  229.     connectionType = FamilyLocal;
  230.     break;
  231.     }
  232.     for (names = &hostNamedb; *names; names = & (*names)->next)
  233.     {
  234.     name = *names;
  235.     if (connectionType == name->connectionType &&
  236.         XdmcpARRAY8Equal (&hostAddr, &name->hostaddr))
  237.     {
  238.         if (XdmcpARRAY8Equal (status, &name->status))
  239.         {
  240.         return 0;
  241.         }
  242.         break;
  243.     }
  244.     }
  245.     if (!*names)
  246.     {
  247.     new = (HostName *) malloc (sizeof (HostName));
  248.         if (!new)
  249.         return 0;
  250.     if (hostname->length)
  251.     {
  252.         switch (addr->sa_family)
  253.         {
  254.         case AF_INET:
  255.             {
  256.                 struct hostent  *hostent;
  257.             char        *host;
  258.         
  259.                 hostent = gethostbyaddr (hostAddr.data, hostAddr.length, AF_INET);
  260.                 if (hostent)
  261.                 {
  262.             XdmcpDisposeARRAY8 (hostname);
  263.                 host = hostent->h_name;
  264.             XdmcpAllocARRAY8 (hostname, strlen (host));
  265.             bcopy (host, hostname->data, hostname->length);
  266.                 }
  267.             }
  268.         }
  269.     }
  270.         if (!XdmcpAllocARRAY8 (&new->hostaddr, hostAddr.length))
  271.         {
  272.         free ((char *) new->fullname);
  273.         free ((char *) new);
  274.         return 0;
  275.         }
  276.         bcopy (hostAddr.data, new->hostaddr.data, hostAddr.length);
  277.     new->connectionType = connectionType;
  278.     new->hostname = *hostname;
  279.  
  280.         *names = new;
  281.         new->next = 0;
  282.     NameTableSize++;
  283.     }
  284.     else
  285.     {
  286.     new = *names;
  287.     free (new->fullname);
  288.     XdmcpDisposeARRAY8 (&new->status);
  289.     XdmcpDisposeARRAY8 (hostname);
  290.     }
  291.     new->willing = willing;
  292.     new->status = *status;
  293.  
  294.     hostname = &new->hostname;
  295.     fulllen = hostname->length;
  296.     if (fulllen < 30)
  297.     fulllen = 30;
  298.     new->fullname = malloc (fulllen + status->length + 10);
  299.     if (!new->fullname)
  300.     {
  301.     new->fullname = "Unknown";
  302.     }
  303.     else
  304.     {
  305.     sprintf (new->fullname, "%-30.*s %*.*s",
  306.          hostname->length, hostname->data,
  307.          status->length, status->length, status->data);
  308.     }
  309.     RebuildTable (NameTableSize);
  310.     return 1;
  311. }
  312.  
  313. static
  314. DisposeHostname (host)
  315.     HostName    *host;
  316. {
  317.     XdmcpDisposeARRAY8 (&host->hostname);
  318.     XdmcpDisposeARRAY8 (&host->hostaddr);
  319.     XdmcpDisposeARRAY8 (&host->status);
  320.     free ((char *) host->fullname);
  321.     free ((char *) host);
  322. }
  323.  
  324. static
  325. RemoveHostname (host)
  326.     HostName    *host;
  327. {
  328.     HostName    **prev, *hosts;
  329.  
  330.     prev = &hostNamedb;;
  331.     for (hosts = hostNamedb; hosts; hosts = hosts->next)
  332.     {
  333.     if (hosts == host)
  334.         break;
  335.     prev = &hosts->next;
  336.     }
  337.     if (!hosts)
  338.     return;
  339.     *prev = host->next;
  340.     DisposeHostname (host);
  341.     NameTableSize--;
  342.     RebuildTable (NameTableSize);
  343. }
  344.  
  345. static
  346. EmptyHostnames ()
  347. {
  348.     HostName    *hosts, *next;
  349.  
  350.     for (hosts = hostNamedb; hosts; hosts = next)
  351.     {
  352.     next = hosts->next;
  353.     DisposeHostname (hosts);
  354.     }
  355.     NameTableSize = 0;
  356.     hostNamedb = 0;
  357.     RebuildTable (NameTableSize);
  358. }
  359.  
  360. /* ARGSUSED */
  361. static void
  362. ReceivePacket (closure, source, id)
  363.     XtPointer    closure;
  364.     int        *source;
  365.     XtInputId    *id;
  366. {
  367.     XdmcpHeader        header;
  368.     ARRAY8        authenticationName;
  369.     ARRAY8        hostname;
  370.     ARRAY8        status;
  371.     int            saveHostname = 0;
  372.     struct sockaddr addr;
  373.     int            addrlen;
  374.  
  375.     addrlen = sizeof (addr);
  376.     if (!XdmcpFill (socketFD, &buffer, &addr, &addrlen))
  377.     return;
  378.     if (!XdmcpReadHeader (&buffer, &header))
  379.     return;
  380.     if (header.version != XDM_PROTOCOL_VERSION)
  381.     return;
  382.     hostname.data = 0;
  383.     status.data = 0;
  384.     authenticationName.data = 0;
  385.     switch (header.opcode) {
  386.     case WILLING:
  387.         if (XdmcpReadARRAY8 (&buffer, &authenticationName) &&
  388.         XdmcpReadARRAY8 (&buffer, &hostname) &&
  389.         XdmcpReadARRAY8 (&buffer, &status))
  390.         {
  391.         if (header.length == 6 + authenticationName.length +
  392.             hostname.length + status.length)
  393.         {
  394.         if (AddHostname (&hostname, &status, &addr, header.opcode == (int) WILLING))
  395.             saveHostname = 1;
  396.         }
  397.         }
  398.     XdmcpDisposeARRAY8 (&authenticationName);
  399.     break;
  400.     case UNWILLING:
  401.         if (XdmcpReadARRAY8 (&buffer, &hostname) &&
  402.         XdmcpReadARRAY8 (&buffer, &status))
  403.         {
  404.         if (header.length == 4 + hostname.length + status.length)
  405.         {
  406.         if (AddHostname (&hostname, &status, &addr, header.opcode == (int) WILLING))
  407.             saveHostname = 1;
  408.  
  409.         }
  410.         }
  411.     break;
  412.     default:
  413.     break;
  414.     }
  415.     if (!saveHostname)
  416.     {
  417.         XdmcpDisposeARRAY8 (&hostname);
  418.         XdmcpDisposeARRAY8 (&status);
  419.     }
  420. }
  421.  
  422. RegisterHostaddr (addr, len, type)
  423.     struct sockaddr *addr;
  424.     int            len;
  425.     xdmOpCode        type;
  426. {
  427.     HostAddr        *host, **prev;
  428.  
  429.     host = (HostAddr *) malloc (sizeof (HostAddr));
  430.     if (!host)
  431.     return;
  432.     host->addr = (struct sockaddr *) malloc (len);
  433.     if (!host->addr)
  434.     {
  435.     free ((char *) host);
  436.     return;
  437.     }
  438.     bcopy ((char *) addr, (char *) host->addr, len);
  439.     host->addrlen = len;
  440.     host->type = type;
  441.     for (prev = &hostAddrdb; *prev; prev = &(*prev)->next)
  442.     ;
  443.     *prev = host;
  444.     host->next = NULL;
  445. }
  446.  
  447. /*
  448.  * Register the address for this host.
  449.  * Called with each of the names on the command line.
  450.  * The special name "BROADCAST" looks up all the broadcast
  451.  *  addresses on the local host.
  452.  */
  453.  
  454. RegisterHostname (name)
  455.     char    *name;
  456. {
  457.     struct hostent    *hostent;
  458.     struct sockaddr_in    in_addr;
  459.     struct ifconf    ifc;
  460.     register struct ifreq *ifr;
  461.     struct sockaddr    broad_addr;
  462.     char        buf[2048];
  463.     int            n;
  464.  
  465.     if (!strcmp (name, BROADCAST_HOSTNAME))
  466.     {
  467.     ifc.ifc_len = sizeof (buf);
  468.     ifc.ifc_buf = buf;
  469.     if (ioctl (socketFD, (int) SIOCGIFCONF, (char *) &ifc) < 0)
  470.         return;
  471.     for (ifr = ifc.ifc_req, n = ifc.ifc_len / sizeof (struct ifreq); --n >= 0;
  472.         ifr++)
  473.     {
  474.         if (ifr->ifr_addr.sa_family != AF_INET)
  475.         continue;
  476.  
  477.         broad_addr = ifr->ifr_addr;
  478.         ((struct sockaddr_in *) &broad_addr)->sin_addr.s_addr =
  479.         htonl (INADDR_BROADCAST);
  480. #ifdef SIOCGIFBRDADDR
  481.         {
  482.         struct ifreq    broad_req;
  483.     
  484.         broad_req = *ifr;
  485.         if (ioctl (socketFD, SIOCGIFFLAGS, (char *) &broad_req) != -1 &&
  486.             (broad_req.ifr_flags & IFF_BROADCAST) &&
  487.             (broad_req.ifr_flags & IFF_UP)
  488.             )
  489.         {
  490.             broad_req = *ifr;
  491.             if (ioctl (socketFD, SIOCGIFBRDADDR, &broad_req) != -1)
  492.             broad_addr = broad_req.ifr_addr;
  493.             else
  494.             continue;
  495.         }
  496.         else
  497.             continue;
  498.         }
  499. #endif
  500.         in_addr = *((struct sockaddr_in *) &broad_addr);
  501.         in_addr.sin_port = htons (XDM_UDP_PORT);
  502.         RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr),
  503.                   BROADCAST_QUERY);
  504.     }
  505.     }
  506.     else
  507.     {
  508. #ifndef ishexdigit
  509. #define ishexdigit(c)    (isdigit(c) || 'a' <= (c) && (c) <= 'f')
  510. #endif
  511.  
  512.     if (isascii (name[0]) && ishexdigit (name[0]))
  513.     {
  514.         if (!index (name, '.'))
  515.         FromHex (name, &in_addr.sin_addr.s_addr, strlen (name));
  516.         else
  517.         in_addr.sin_addr.s_addr = inet_addr (name);
  518.         if (in_addr.sin_addr.s_addr == -1)
  519.         return;
  520.         in_addr.sin_family = AF_INET;
  521.     }
  522.     else
  523.     {
  524.         hostent = gethostbyname (name);
  525.         if (!hostent)
  526.         return;
  527.         if (hostent->h_addrtype != AF_INET || hostent->h_length != 4)
  528.             return;
  529.         in_addr.sin_family = hostent->h_addrtype;
  530.         bcopy (hostent->h_addr, &in_addr.sin_addr, 4);
  531.     }
  532.     in_addr.sin_port = htons (XDM_UDP_PORT);
  533.     RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr),
  534.               QUERY);
  535.     }
  536. }
  537.  
  538. static ARRAYofARRAY8    AuthenticationNames;
  539.  
  540. RegisterAuthenticationName (name, namelen)
  541.     char    *name;
  542.     int        namelen;
  543. {
  544.     ARRAY8Ptr    authName;
  545.     if (!XdmcpReallocARRAYofARRAY8 (&AuthenticationNames,
  546.                     AuthenticationNames.length + 1))
  547.     return;
  548.     authName = &AuthenticationNames.data[AuthenticationNames.length-1];
  549.     if (!XdmcpAllocARRAY8 (authName, namelen))
  550.     return;
  551.     bcopy (name, authName->data, namelen);
  552. }
  553.  
  554. InitXDMCP (argv)
  555.     char    **argv;
  556. {
  557.     int    soopts = 1;
  558.     XdmcpHeader    header;
  559.     int    i;
  560.     int optlen;
  561.  
  562.     header.version = XDM_PROTOCOL_VERSION;
  563.     header.opcode = (CARD16) BROADCAST_QUERY;
  564.     header.length = 1;
  565.     for (i = 0; i < (int)AuthenticationNames.length; i++)
  566.     header.length += 2 + AuthenticationNames.data[i].length;
  567.     XdmcpWriteHeader (&broadcastBuffer, &header);
  568.     XdmcpWriteARRAYofARRAY8 (&broadcastBuffer, &AuthenticationNames);
  569.  
  570.     header.version = XDM_PROTOCOL_VERSION;
  571.     header.opcode = (CARD16) QUERY;
  572.     header.length = 1;
  573.     for (i = 0; i < (int)AuthenticationNames.length; i++)
  574.     header.length += 2 + AuthenticationNames.data[i].length;
  575.     XdmcpWriteHeader (&directBuffer, &header);
  576.     XdmcpWriteARRAYofARRAY8 (&directBuffer, &AuthenticationNames);
  577.     if ((socketFD = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
  578.     return 0;
  579. #ifdef SO_BROADCAST
  580.     soopts = 1;
  581.     if (setsockopt (socketFD, SOL_SOCKET, SO_BROADCAST, &soopts, sizeof (soopts)) < 0)
  582.     perror ("setsockopt");
  583. #endif
  584.     
  585.     XtAddInput (socketFD, (XtPointer) XtInputReadMask, ReceivePacket,
  586.         (XtPointer) 0);
  587.     while (*argv)
  588.     {
  589.     RegisterHostname (*argv);
  590.     ++argv;
  591.     }
  592.     pingTry = 0;
  593.     PingHosts ((XtPointer)NULL, (XtIntervalId *)NULL);
  594.     return 1;
  595. }
  596.  
  597. Boolean
  598. Choose (h)
  599.     HostName    *h;
  600. {
  601.     if (app_resources.xdmAddress)
  602.     {
  603.     struct sockaddr_in  in_addr;
  604.     struct sockaddr    *addr;
  605.     int        family;
  606.     int        len;
  607.     int        fd;
  608.     char        buf[1024];
  609.     XdmcpBuffer    buffer;
  610.     char        *xdm;
  611.  
  612.     xdm = (char *) app_resources.xdmAddress->data;
  613.     family = (xdm[0] << 8) + xdm[1];
  614.     switch (family) {
  615.     case AF_INET:
  616.         in_addr.sin_family = family;
  617.         bcopy (xdm + 2, &in_addr.sin_port, 2);
  618.         bcopy (xdm + 4, &in_addr.sin_addr.s_addr, 4);
  619.         addr = (struct sockaddr *) &in_addr;
  620.         len = sizeof (in_addr);
  621.         break;
  622.     }
  623.     if ((fd = socket (family, SOCK_STREAM, 0)) == -1)
  624.     {
  625.         fprintf (stderr, "Cannot create response socket\n");
  626.         exit (REMANAGE_DISPLAY);
  627.     }
  628.     if (connect (fd, addr, len) == -1)
  629.     {
  630.         fprintf (stderr, "Cannot connect to xdm\n");
  631.         exit (REMANAGE_DISPLAY);
  632.     }
  633.     buffer.data = (BYTE *) buf;
  634.     buffer.size = sizeof (buf);
  635.     buffer.pointer = 0;
  636.     buffer.count = 0;
  637.     XdmcpWriteARRAY8 (&buffer, app_resources.clientAddress);
  638.     XdmcpWriteCARD16 (&buffer, (CARD16) app_resources.connectionType);
  639.     XdmcpWriteARRAY8 (&buffer, &h->hostaddr);
  640.     write (fd, buffer.data, buffer.pointer);
  641.     close (fd);
  642.     }
  643.     else
  644.     {
  645.     int i;
  646.  
  647.         printf ("%u\n", h->connectionType);
  648.         for (i = 0; i < (int)h->hostaddr.length; i++)
  649.         printf ("%u%s", h->hostaddr.data[i],
  650.             i == h->hostaddr.length - 1 ? "\n" : " ");
  651.     }
  652. }
  653.  
  654. /* ARGSUSED */
  655. static void
  656. DoAccept (w, event, params, num_params)
  657.     Widget w;
  658.     XEvent *event;
  659.     String *params;
  660.     Cardinal *num_params;
  661. {
  662.     XawListReturnStruct    *r;
  663.     HostName        *h;
  664.  
  665.     r = XawListShowCurrent (list);
  666.     if (r->list_index == XAW_LIST_NONE)
  667.     XBell (XtDisplay (toplevel), 0);
  668.     else
  669.     {
  670.     for (h = hostNamedb; h; h = h->next)
  671.         if (!strcmp (r->string, h->fullname))
  672.         {
  673.         Choose (h);
  674.         }
  675.     exit (OBEYSESS_DISPLAY);
  676.     }
  677. }
  678.  
  679. /* ARGSUSED */
  680. static void
  681. DoCheckWilling (w, event, params, num_params)
  682.     Widget w;
  683.     XEvent *event;
  684.     String *params;
  685.     Cardinal *num_params;
  686. {
  687.     XawListReturnStruct    *r;
  688.     HostName        *h;
  689.     
  690.     r = XawListShowCurrent (list);
  691.     if (r->list_index == XAW_LIST_NONE)
  692.     return;
  693.     for (h = hostNamedb; h; h = h->next)
  694.     if (!strcmp (r->string, h->fullname))
  695.         if (!h->willing)
  696.         XawListUnhighlight (list);
  697. }
  698.  
  699. /* ARGSUSED */
  700. static void
  701. DoCancel (w, event, params, num_params)
  702.     Widget w;
  703.     XEvent *event;
  704.     String *params;
  705.     Cardinal *num_params;
  706. {
  707.     exit (OBEYSESS_DISPLAY);
  708. }
  709.  
  710. /* ARGSUSED */
  711. static void
  712. DoPing (w, event, params, num_params)
  713.     Widget w;
  714.     XEvent *event;
  715.     String *params;
  716.     Cardinal *num_params;
  717. {
  718.     EmptyHostnames ();
  719.     pingTry = 0;
  720.     PingHosts ((XtPointer)NULL, (XtIntervalId *)NULL);
  721. }
  722.  
  723. static XtActionsRec app_actions[] = {
  724.     "Accept",        DoAccept,
  725.     "Cancel",        DoCancel,
  726.     "CheckWilling", DoCheckWilling,
  727.     "Ping",        DoPing,
  728. };
  729.  
  730. main (argc, argv)
  731.     char    **argv;
  732. {
  733.     Arg        position[3];
  734.     Dimension   width, height;
  735.     Position    x, y;
  736.  
  737.     toplevel = XtInitialize (argv[0], "Chooser", options, XtNumber(options), &argc, argv);
  738.  
  739.     XtAddConverter(XtRString, XtRARRAY8, CvtStringToARRAY8, NULL, 0);
  740.  
  741.     XtGetApplicationResources (toplevel, (XtPointer) &app_resources, resources,
  742.                    XtNumber (resources), NULL, (Cardinal) 0);
  743.  
  744.     XtAddActions (app_actions, XtNumber (app_actions));
  745.     paned = XtCreateManagedWidget ("paned", panedWidgetClass, toplevel, NULL, 0);
  746.     label = XtCreateManagedWidget ("label", labelWidgetClass, paned, NULL, 0);
  747.     viewport = XtCreateManagedWidget ("viewport", viewportWidgetClass, paned, NULL, 0);
  748.     list = XtCreateManagedWidget ("list", listWidgetClass, viewport, NULL, 0);
  749.     box = XtCreateManagedWidget ("box", boxWidgetClass, paned, NULL, 0);
  750.     cancel = XtCreateManagedWidget ("cancel", commandWidgetClass, box, NULL, 0);
  751.     acceptit = XtCreateManagedWidget ("accept", commandWidgetClass, box, NULL, 0);
  752.     ping = XtCreateManagedWidget ("ping", commandWidgetClass, box, NULL, 0);
  753.  
  754.     /*
  755.      * center ourselves on the screen
  756.      */
  757.     XtSetMappedWhenManaged(toplevel, FALSE);
  758.     XtRealizeWidget (toplevel);
  759.  
  760.     XtSetArg (position[0], XtNwidth, &width);
  761.     XtSetArg (position[1], XtNheight, &height);
  762.     XtGetValues (toplevel, position, (Cardinal) 2);
  763.     x = (Position)(WidthOfScreen (XtScreen (toplevel)) - width) / 2;
  764.     y = (Position)(HeightOfScreen (XtScreen (toplevel)) - height) / 3;
  765.     XtSetArg (position[0], XtNx, x);
  766.     XtSetArg (position[1], XtNy, y);
  767.     XtSetValues (toplevel, position, (Cardinal) 2);
  768.  
  769.     /*
  770.      * Run
  771.      */
  772.     XtMapWidget(toplevel);
  773.     InitXDMCP (argv + 1);
  774.     XtMainLoop ();
  775.     exit(0);
  776.     /*NOTREACHED*/
  777. }
  778.  
  779. FromHex (s, d, len)
  780.     char    *s, *d;
  781.     int        len;
  782. {
  783.     int    t;
  784.     while (len >= 2)
  785.     {
  786. #define HexChar(c)  ('0' <= (c) && (c) <= '9' ? (c) - '0' : (c) - 'a' + 10)
  787.     t = HexChar (*s) << 4;
  788.     s++;
  789.     t += HexChar (*s);
  790.     s++;
  791.     *d++ = t;
  792.     len -= 2;
  793.     }
  794. }
  795.  
  796. /*ARGSUSED*/
  797. static void
  798. CvtStringToARRAY8 (args, num_args, fromVal, toVal)
  799.     XrmValuePtr    args;
  800.     Cardinal    *num_args;
  801.     XrmValuePtr    fromVal;
  802.     XrmValuePtr    toVal;
  803. {
  804.     static ARRAY8Ptr    dest;
  805.     char    *s;
  806.     int        len;
  807.  
  808.     dest = (ARRAY8Ptr) XtMalloc (sizeof (ARRAY8));
  809.     len = fromVal->size;
  810.     s = (char *) fromVal->addr;
  811.     if (!XdmcpAllocARRAY8 (dest, len >> 1))
  812.     XtStringConversionWarning ((char *) fromVal->addr, XtRARRAY8);
  813.     else
  814.     {
  815.     FromHex (s, (char *) dest->data, len);
  816.     }
  817.     toVal->addr = (caddr_t) &dest;
  818.     toVal->size = sizeof (ARRAY8Ptr);
  819. }
  820.