Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtlogin / chooser.c
1 /*                                                                      *
2  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
3  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
4  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
5  * (c) Copyright 1993, 1994 Novell, Inc.                                *
6  */
7 /*
8  * $TOG: chooser.c /main/8 1998/03/04 19:26:30 mgreess $
9  *
10 Copyright (c) 1990  X Consortium
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in
20 all copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
25 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
26 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29 Except as contained in this notice, the name of the X Consortium shall not be
30 used in advertising or otherwise to promote the sale, use or other dealings
31 in this Software without prior written authorization from the X Consortium.
32  *
33  * Author:  Keith Packard, MIT X Consortium
34  */
35
36 /*
37  * Chooser - display a menu of names and let the user select one
38  */
39
40 /*
41  * Layout:
42  *
43  *  +--------------------------------------------------+
44  *  |             +------------------+                 |
45  *  |             |      Label       |                 |
46  *  |             +------------------+                 |
47  *  |    +-+--------------+                            |
48  *  |    |^| name-1       |                            |
49  *  |    ||| name-2       |                            |
50  *  |    |v| name-3       |                            |
51  *  |    | | name-4       |                            |
52  *  |    | | name-5       |                            |
53  *  |    | | name-6       |                            |
54  *  |    +----------------+                            |
55  *  |    cancel  accept  ping                          |
56  *  +--------------------------------------------------+
57  */
58
59 #include    <X11/Intrinsic.h>
60 #include    <X11/StringDefs.h>
61 #include    <X11/Xatom.h>
62
63
64 #include    <Xm/Xm.h>
65 #include    <Xm/DragC.h>
66 #include    <Xm/List.h>
67
68 #define     CHOOSER
69
70 #include    "dm.h"
71
72 #include    "vg.h"
73 #include    "vgmsg.h"
74
75 #include    <X11/Xdmcp.h>
76
77 #include    <sys/types.h>
78 #include    <stdio.h>
79 #include    <ctype.h>
80 #include    <locale.h>
81 #include    <nl_types.h>
82 #ifndef NL_CAT_LOCALE
83 #define NL_CAT_LOCALE 0
84 #endif
85
86 #ifdef SVR4
87 #include    <sys/sockio.h>
88 #endif
89 #include    <sys/socket.h>
90 #include    <netinet/in.h>
91 #include    <sys/ioctl.h>
92
93 /*
94  * From Xm/XmStringI.h
95  */
96 extern XtPointer _XmStringUngenerate (
97                                 XmString string,
98                                 XmStringTag tag,
99                                 XmTextType tag_type,
100                                 XmTextType output_type);
101
102 #define BROADCAST_HOSTNAME  "BROADCAST"
103
104 #ifndef ishexdigit
105 #define ishexdigit(c)   (isdigit(c) || 'a' <= (c) && (c) <= 'f')
106 #endif
107
108 #ifdef hpux
109 # include <sys/utsname.h>
110 # ifdef HAS_IFREQ
111 #  include <net/if.h>
112 # endif
113 #else
114 #ifdef __convex__
115 # include <sync/queue.h>
116 # include <sync/sema.h>
117 #endif
118 # include <net/if.h>
119 #endif /* hpux */
120
121 #include    <netdb.h>
122
123 Widget      toplevel, label, viewport, paned, list, box, cancel, acceptit, ping;
124
125 extern Widget chooser_list;
126 extern int orig_argc;
127 extern char **orig_argv;
128 extern int amChooser;
129 extern void MakeOptionsProc();
130
131 static Arg  chooserArgs[25];     /** Hopefully enough args **/
132
133 static void     CvtStringToARRAY8();
134
135 static struct _app_resources {
136     ARRAY8Ptr   xdmAddress;
137     ARRAY8Ptr   clientAddress;
138     int         connectionType;
139 } app_resources;
140
141 #define offset(field) XtOffsetOf(struct _app_resources, field)
142
143 #define XtRARRAY8   "ARRAY8"
144
145 static XtResource  resources[] = {
146     {"xdmAddress",      "XdmAddress",  XtRARRAY8,       sizeof (ARRAY8Ptr),
147         offset (xdmAddress),        XtRString,  NULL },
148     {"clientAddress",   "ClientAddress",  XtRARRAY8,    sizeof (ARRAY8Ptr),
149         offset (clientAddress),     XtRString,  NULL },
150     {"connectionType",  "ConnectionType",   XtRInt,     sizeof (int),
151         offset (connectionType),    XtRImmediate,       (XtPointer) 0 }
152 };
153 #undef offset
154
155 static XrmOptionDescRec options[] = {
156     "-xdmaddress",      "*xdmAddress",      XrmoptionSepArg,    NULL,
157     "-clientaddress",   "*clientAddress",   XrmoptionSepArg,    NULL,
158     "-connectionType",  "*connectionType",  XrmoptionSepArg,    NULL,
159 };
160
161 typedef struct _hostAddr {
162     struct _hostAddr    *next;
163     struct sockaddr     *addr;
164     int                 addrlen;
165     xdmOpCode           type;
166 } HostAddr;
167
168 static HostAddr    *hostAddrdb;
169
170 typedef struct _hostName {
171     struct _hostName    *next;
172     char                *fullname;
173     int                 willing;
174     ARRAY8              hostname, status;
175     CARD16              connectionType;
176     ARRAY8              hostaddr;
177 } HostName;
178
179 static HostName    *hostNamedb;
180
181 static int  socketFD;
182
183 static int  pingTry;
184
185 #define PING_INTERVAL   2000
186 #define TRIES           3
187
188 static XdmcpBuffer      directBuffer, broadcastBuffer;
189 static XdmcpBuffer      buffer;
190
191
192 /* ARGSUSED */
193 static void
194 PingHosts (closure, id)
195     XtPointer closure;
196     XtIntervalId *id;
197 {
198     HostAddr    *hosts;
199
200     for (hosts = hostAddrdb; hosts; hosts = hosts->next)
201     {
202         if (hosts->type == QUERY)
203             XdmcpFlush (socketFD, &directBuffer, hosts->addr, hosts->addrlen);
204         else
205             XdmcpFlush (socketFD, &broadcastBuffer, hosts->addr, hosts->addrlen);
206     }
207     if (++pingTry < TRIES)
208         XtAddTimeOut (PING_INTERVAL, PingHosts, (XtPointer) 0);
209 }
210
211 char    **NameTable;
212 int     NameTableSize;
213
214 static int
215 HostnameCompare (a, b)
216 #if defined(__STDC__)
217     const void *a, *b;
218 #else
219     char *a, *b;
220 #endif
221 {
222     return strcmp (*(char **)a, *(char **)b);
223 }
224
225 static void
226 RebuildTable (size)
227 {
228     char        **newTable = 0;
229     HostName    *names;
230     int         i;
231     XmStringTable newStringTable;
232     Arg         listArgs[10];
233     int         numArgs;
234
235     if (size)
236     {
237         newTable = (char **) malloc (size * sizeof (char *));
238         if (!newTable)
239             return;
240         for (names = hostNamedb, i = 0; names; names = names->next, i++)
241             newTable[i] = names->fullname;
242         qsort (newTable, size, sizeof (char *), HostnameCompare);
243     }
244       else  {
245         XmListDeleteAllItems(chooser_list);
246         if (NameTable)
247             free((char *)NameTable);
248         NameTableSize = 0;
249         return;
250     }
251
252     /***********************************/
253     /** Reload the data in the XmList **/
254     /***********************************/
255     newStringTable = (XmStringTable)malloc(size * sizeof(XmString));
256     if (!newStringTable) {
257         free((char *)newTable);
258         return;
259     }
260     for (i = 0; i < size; i++) {
261         newStringTable[i] = XmStringCreateLocalized(newTable[i]);
262     }
263     numArgs = 0;
264     XtSetArg(listArgs[numArgs], XmNitemCount, size); numArgs++;
265     XtSetArg(listArgs[numArgs], XmNitems, newStringTable); numArgs++;
266     XtSetValues(chooser_list, listArgs, numArgs);
267
268     free((char *) newStringTable);
269
270     if (NameTable)
271         free ((char *) NameTable);
272     NameTable = newTable;
273     NameTableSize = size;
274 }
275
276 static void
277 RebuildTableAdd (size)
278         int size;
279 {
280     char        **newTable = 0;
281     HostName    *names;
282     int         i;
283     XmString    tempString;
284     int         position;
285
286     if (size)
287     {
288         newTable = (char **) malloc (size * sizeof (char *));
289         if (!newTable)
290             return;
291         for (names = hostNamedb, i = 0; names; names = names->next, i++)
292             newTable[i] = names->fullname;
293         qsort (newTable, size, sizeof (char *), HostnameCompare);
294     }
295
296     for (i = 0; i < size; i++) {
297         tempString = XmStringCreateLocalized(newTable[i]);
298         if ((position = XmListItemPos(chooser_list, tempString)) == 0) {
299             /****************************/
300             /** need to add a new host **/
301             /****************************/
302             XmListAddItemUnselected(chooser_list, tempString, (i+1));
303             XmStringFree(tempString);
304             break;
305         }
306         XmStringFree(tempString);
307     }
308
309     if (NameTable)
310         free ((char *) NameTable);
311     NameTable = newTable;
312     NameTableSize = size;
313 }
314
315
316 static int
317 AddHostname (hostname, status, addr, willing)
318     ARRAY8Ptr       hostname, status;
319     struct sockaddr *addr;
320     int             willing;
321 {
322     HostName    *new, **names, *name;
323     ARRAY8      hostAddr;
324     CARD16      connectionType;
325     int         fulllen;
326     int         update = 0;
327
328     switch (addr->sa_family)
329     {
330     case AF_INET:
331         hostAddr.data = (CARD8 *) &((struct sockaddr_in *) addr)->sin_addr;
332         hostAddr.length = 4;
333         connectionType = FamilyInternet;
334         break;
335     default:
336         hostAddr.data = (CARD8 *) "";
337         hostAddr.length = 0;
338         connectionType = FamilyLocal;
339         break;
340     }
341     for (names = &hostNamedb; *names; names = & (*names)->next)
342     {
343         name = *names;
344         if (connectionType == name->connectionType &&
345             XdmcpARRAY8Equal (&hostAddr, &name->hostaddr))
346         {
347             if (XdmcpARRAY8Equal (status, &name->status))
348             {
349                 return 0;
350             }
351             update = 1;
352             break;
353         }
354     }
355     if (!*names)
356     {
357         new = (HostName *) malloc (sizeof (HostName));
358         if (!new)
359             return 0;
360         if (hostname->length)
361         {
362             switch (addr->sa_family)
363             {
364             case AF_INET:
365                 {
366                     struct hostent  *hostent;
367                     char            *host;
368         
369                     hostent = gethostbyaddr ((char *)hostAddr.data, hostAddr.length, AF_INET);
370                     if (hostent)
371                     {
372                         XdmcpDisposeARRAY8 (hostname);
373                         host = hostent->h_name;
374                         XdmcpAllocARRAY8 (hostname, strlen (host));
375                         memmove( hostname->data, host, hostname->length);
376                     }
377                 }
378             }
379         }
380         if (!XdmcpAllocARRAY8 (&new->hostaddr, hostAddr.length))
381         {
382             free ((char *) new->fullname);
383             free ((char *) new);
384             return 0;
385         }
386         memmove( new->hostaddr.data, hostAddr.data, hostAddr.length);
387         new->connectionType = connectionType;
388         new->hostname = *hostname;
389
390         *names = new;
391         new->next = 0;
392         NameTableSize++;
393     }
394     else
395     {
396         new = *names;
397         free (new->fullname);
398         XdmcpDisposeARRAY8 (&new->status);
399         XdmcpDisposeARRAY8 (hostname);
400     }
401     new->willing = willing;
402     new->status = *status;
403
404     hostname = &new->hostname;
405     fulllen = hostname->length;
406     if (fulllen < 30)
407         fulllen = 30;
408     new->fullname = malloc (fulllen + status->length + 10);
409     if (!new->fullname)
410     {
411         new->fullname = "Unknown";
412     }
413     else
414     {
415         sprintf (new->fullname, "%-30.*s %*.*s",
416                  hostname->length, hostname->data,
417                  status->length, status->length, status->data);
418     }
419     if (update)
420         RebuildTable (NameTableSize);
421     else
422         RebuildTableAdd (NameTableSize);
423     return 1;
424 }
425
426 static
427 DisposeHostname (host)
428     HostName    *host;
429 {
430     XdmcpDisposeARRAY8 (&host->hostname);
431     XdmcpDisposeARRAY8 (&host->hostaddr);
432     XdmcpDisposeARRAY8 (&host->status);
433     free ((char *) host->fullname);
434     free ((char *) host);
435 }
436
437 static
438 RemoveHostname (host)
439     HostName    *host;
440 {
441     HostName    **prev, *hosts;
442
443     prev = &hostNamedb;;
444     for (hosts = hostNamedb; hosts; hosts = hosts->next)
445     {
446         if (hosts == host)
447             break;
448         prev = &hosts->next;
449     }
450     if (!hosts)
451         return;
452     *prev = host->next;
453     DisposeHostname (host);
454     NameTableSize--;
455     RebuildTable (NameTableSize);
456 }
457
458 static
459 EmptyHostnames ()
460 {
461     HostName    *hosts, *next;
462
463     for (hosts = hostNamedb; hosts; hosts = next)
464     {
465         next = hosts->next;
466         DisposeHostname (hosts);
467     }
468     NameTableSize = 0;
469     hostNamedb = 0;
470     RebuildTable (NameTableSize);
471 }
472
473 /* ARGSUSED */
474 static void
475 ReceivePacket (closure, source, id)
476     XtPointer   closure;
477     int         *source;
478     XtInputId   *id;
479 {
480     XdmcpHeader     header;
481     ARRAY8          authenticationName;
482     ARRAY8          hostname;
483     ARRAY8          status;
484     int             saveHostname = 0;
485     struct sockaddr addr;
486     int             addrlen;
487
488     addrlen = sizeof (addr);
489     if (!XdmcpFill (socketFD, &buffer, &addr, &addrlen))
490         return;
491     if (!XdmcpReadHeader (&buffer, &header))
492         return;
493     if (header.version != XDM_PROTOCOL_VERSION)
494         return;
495     hostname.data = 0;
496     status.data = 0;
497     authenticationName.data = 0;
498     switch (header.opcode) {
499     case WILLING:
500         if (XdmcpReadARRAY8 (&buffer, &authenticationName) &&
501             XdmcpReadARRAY8 (&buffer, &hostname) &&
502             XdmcpReadARRAY8 (&buffer, &status))
503         {
504             if (header.length == 6 + authenticationName.length +
505                 hostname.length + status.length)
506             {
507                 if (AddHostname (&hostname, &status, &addr, header.opcode == (int) WILLING))
508                     saveHostname = 1;
509             }
510         }
511         XdmcpDisposeARRAY8 (&authenticationName);
512         break;
513     case UNWILLING:
514         if (XdmcpReadARRAY8 (&buffer, &hostname) &&
515             XdmcpReadARRAY8 (&buffer, &status))
516         {
517             if (header.length == 4 + hostname.length + status.length)
518             {
519                 if (AddHostname (&hostname, &status, &addr, header.opcode == (int) WILLING))
520                     saveHostname = 1;
521
522             }
523         }
524         break;
525     default:
526         break;
527     }
528     if (!saveHostname)
529     {
530         XdmcpDisposeARRAY8 (&hostname);
531         XdmcpDisposeARRAY8 (&status);
532     }
533 }
534
535 RegisterHostaddr (addr, len, type)
536     struct sockaddr *addr;
537     int             len;
538     xdmOpCode       type;
539 {
540     HostAddr            *host, **prev;
541
542     host = (HostAddr *) malloc (sizeof (HostAddr));
543     if (!host)
544         return;
545     host->addr = (struct sockaddr *) malloc (len);
546     if (!host->addr)
547     {
548         free ((char *) host);
549         return;
550     }
551     memmove( (char *) host->addr, (char *) addr, len);
552     host->addrlen = len;
553     host->type = type;
554     for (prev = &hostAddrdb; *prev; prev = &(*prev)->next)
555         ;
556     *prev = host;
557     host->next = NULL;
558 }
559
560 /*
561  * Register the address for this host.
562  * Called with each of the names on the command line.
563  * The special name "BROADCAST" looks up all the broadcast
564  *  addresses on the local host.
565  */
566
567 RegisterHostname (name)
568     char    *name;
569 {
570     struct hostent      *hostent;
571     struct sockaddr_in  in_addr;
572     struct ifconf       ifc;
573     register struct ifreq *ifr;
574     struct sockaddr     broad_addr;
575     char                buf[2048];
576     int                 n;
577
578     if (!strcmp (name, BROADCAST_HOSTNAME))
579     {
580         ifc.ifc_len = sizeof (buf);
581         ifc.ifc_buf = buf;
582         if (ioctl (socketFD, (int) SIOCGIFCONF, (char *) &ifc) < 0)
583             return;
584         for (ifr = ifc.ifc_req
585 #if defined (__bsdi__) || defined(__NetBSD__)
586              ; (char *)ifr < ifc.ifc_buf + ifc.ifc_len;
587              ifr = (struct ifreq *)((char *)ifr + sizeof (struct ifreq) +
588                 (ifr->ifr_addr.sa_len > sizeof (ifr->ifr_addr) ?
589                  ifr->ifr_addr.sa_len - sizeof (ifr->ifr_addr) : 0))
590 #else
591              , n = ifc.ifc_len / sizeof (struct ifreq); --n >= 0; ifr++
592 #endif
593              )
594         {
595             if (ifr->ifr_addr.sa_family != AF_INET)
596                 continue;
597
598             broad_addr = ifr->ifr_addr;
599             ((struct sockaddr_in *) &broad_addr)->sin_addr.s_addr =
600                 htonl (INADDR_BROADCAST);
601 #ifdef SIOCGIFBRDADDR
602             {
603                 struct ifreq    broad_req;
604     
605                 broad_req = *ifr;
606                 if (ioctl (socketFD, SIOCGIFFLAGS, (char *) &broad_req) != -1 &&
607                     (broad_req.ifr_flags & IFF_BROADCAST) &&
608                     (broad_req.ifr_flags & IFF_UP)
609                     )
610                 {
611                     broad_req = *ifr;
612                     if (ioctl (socketFD, SIOCGIFBRDADDR, &broad_req) != -1)
613                         broad_addr = broad_req.ifr_addr;
614                     else
615                         continue;
616                 }
617                 else
618                     continue;
619             }
620 #endif
621             in_addr = *((struct sockaddr_in *) &broad_addr);
622             in_addr.sin_port = htons (XDM_UDP_PORT);
623 #ifdef BSD44SOCKETS
624             in_addr.sin_len = sizeof(in_addr);
625 #endif
626             RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr),
627                               BROADCAST_QUERY);
628         }
629     }
630     else
631     {
632
633         /* address as hex string, e.g., "12180022" (depreciated) */
634         if (strlen(name) == 8 &&
635             FromHex(name, (char *)&in_addr.sin_addr, strlen(name)) == 0)
636         {
637             in_addr.sin_family = AF_INET;
638         }
639         /* Per RFC 1123, check first for IP address in dotted-decimal form */
640         else if ((in_addr.sin_addr.s_addr = inet_addr(name)) != -1)
641             in_addr.sin_family = AF_INET;
642         else
643         {
644             hostent = gethostbyname (name);
645             if (!hostent)
646                 return;
647             if (hostent->h_addrtype != AF_INET || hostent->h_length != 4)
648                 return;
649             in_addr.sin_family = hostent->h_addrtype;
650             memmove( &in_addr.sin_addr, hostent->h_addr, 4);
651         }
652         in_addr.sin_port = htons (XDM_UDP_PORT);
653 #ifdef BSD44SOCKETS
654         in_addr.sin_len = sizeof(in_addr);
655 #endif
656         RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr),
657                           QUERY);
658     }
659 }
660
661 static ARRAYofARRAY8    AuthenticationNames;
662
663 RegisterAuthenticationName (name, namelen)
664     char    *name;
665     int     namelen;
666 {
667     ARRAY8Ptr   authName;
668     if (!XdmcpReallocARRAYofARRAY8 (&AuthenticationNames,
669                                     AuthenticationNames.length + 1))
670         return;
671     authName = &AuthenticationNames.data[AuthenticationNames.length-1];
672     if (!XdmcpAllocARRAY8 (authName, namelen))
673         return;
674     memmove( authName->data, name, namelen);
675 }
676
677 InitXDMCP (argv)
678     char    **argv;
679 {
680     int soopts = 1;
681     XdmcpHeader header;
682     int i;
683     int optlen;
684
685     header.version = XDM_PROTOCOL_VERSION;
686     header.opcode = (CARD16) BROADCAST_QUERY;
687     header.length = 1;
688     for (i = 0; i < (int)AuthenticationNames.length; i++)
689         header.length += 2 + AuthenticationNames.data[i].length;
690     XdmcpWriteHeader (&broadcastBuffer, &header);
691     XdmcpWriteARRAYofARRAY8 (&broadcastBuffer, &AuthenticationNames);
692
693     header.version = XDM_PROTOCOL_VERSION;
694     header.opcode = (CARD16) QUERY;
695     header.length = 1;
696     for (i = 0; i < (int)AuthenticationNames.length; i++)
697         header.length += 2 + AuthenticationNames.data[i].length;
698     XdmcpWriteHeader (&directBuffer, &header);
699     XdmcpWriteARRAYofARRAY8 (&directBuffer, &AuthenticationNames);
700     if ((socketFD = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
701         return 0;
702 #ifdef SO_BROADCAST
703     soopts = 1;
704     if (setsockopt (socketFD, SOL_SOCKET, SO_BROADCAST, (char *)&soopts, sizeof (soopts)) < 0)
705         perror ("setsockopt");
706 #endif
707     
708     XtAddInput (socketFD, (XtPointer) XtInputReadMask, ReceivePacket,
709                 (XtPointer) 0);
710     while (*argv)
711     {
712         RegisterHostname (*argv);
713         ++argv;
714     }
715     pingTry = 0;
716     PingHosts ((XtPointer)NULL, (XtIntervalId *)NULL);
717     return 1;
718 }
719
720 void
721 Choose (h)
722     HostName    *h;
723 {
724     if (app_resources.xdmAddress)
725     {
726         struct sockaddr_in  in_addr;
727         struct sockaddr *addr;
728         int             family;
729         int             len;
730         int             fd;
731         char            buf[1024];
732         XdmcpBuffer     buffer;
733         char            *xdm;
734
735         xdm = (char *) app_resources.xdmAddress->data;
736         family = (xdm[0] << 8) + xdm[1];
737         switch (family) {
738         case AF_INET:
739 #ifdef BSD44SOCKETS
740             in_addr.sin_len = sizeof(in_addr);
741 #endif
742             in_addr.sin_family = family;
743             memmove( &in_addr.sin_port, xdm + 2, 2);
744             memmove( &in_addr.sin_addr, xdm + 4, 4);
745             addr = (struct sockaddr *) &in_addr;
746             len = sizeof (in_addr);
747             break;
748         }
749         if ((fd = socket (family, SOCK_STREAM, 0)) == -1)
750         {
751             fprintf (stderr, "Cannot create response socket\n");
752             exit (REMANAGE_DISPLAY);
753         }
754         if (connect (fd, addr, len) == -1)
755         {
756             fprintf (stderr, "Cannot connect to xdm\n");
757             exit (REMANAGE_DISPLAY);
758         }
759         buffer.data = (BYTE *) buf;
760         buffer.size = sizeof (buf);
761         buffer.pointer = 0;
762         buffer.count = 0;
763         XdmcpWriteARRAY8 (&buffer, app_resources.clientAddress);
764         XdmcpWriteCARD16 (&buffer, (CARD16) app_resources.connectionType);
765         XdmcpWriteARRAY8 (&buffer, &h->hostaddr);
766         write (fd, (char *)buffer.data, buffer.pointer);
767         close (fd);
768     }
769     else
770     {
771         int i;
772
773         printf ("%u\n", h->connectionType);
774         for (i = 0; i < (int)h->hostaddr.length; i++)
775             printf ("%u%s", h->hostaddr.data[i],
776                     i == h->hostaddr.length - 1 ? "\n" : " ");
777     }
778 }
779
780 /* ARGSUSED */
781 void
782 DoAccept (w, event, params, num_params)
783     Widget w;
784     XEvent *event;
785     String *params;
786     Cardinal *num_params;
787 {
788     HostName            *h;
789     XmStringTable       selectedItem;
790     int                 selectedCount;
791     int                 i;
792     char                *text;
793
794     /*********************************/
795     /** see if anything is selected **/
796     /*********************************/
797     i = 0;
798     XtSetArg(chooserArgs[i], XmNselectedItemCount, &selectedCount); i++;
799     XtGetValues(chooser_list, chooserArgs, i);
800     if (selectedCount != 1) {
801         XBell (XtDisplay (toplevel), 0);
802         return;
803     }
804
805     /**********************************************/
806     /** retrieve the selected item from the list **/
807     /**********************************************/
808     i = 0;
809     XtSetArg(chooserArgs[i], XmNselectedItems, &selectedItem); i++;
810     XtGetValues(chooser_list, chooserArgs, i);
811     text = (char*) _XmStringUngenerate(
812                         selectedItem[0], NULL,
813                         XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
814     if (NULL == text) return;
815     
816     for (h = hostNamedb; h; h = h->next)
817         if (!strcmp (text, h->fullname))
818         {
819             Choose (h);
820         }
821     if (NULL != text) XtFree(text);
822     exit (OBEYSESS_DISPLAY);
823 }
824
825 /* ARGSUSED */
826 static void
827 DoCheckWilling (w, event, params, num_params)
828     Widget w;
829     XEvent *event;
830     String *params;
831     Cardinal *num_params;
832 {
833     HostName            *h;
834     XmStringTable       selectedItem;
835     int                 selectedCount;
836     int                 i;
837     char                *text;
838
839     /*********************************/
840     /** see if anything is selected **/
841     /*********************************/
842     i = 0;
843     XtSetArg(chooserArgs[i], XmNselectedItemCount, &selectedCount); i++;
844     XtGetValues(chooser_list, chooserArgs, i);
845     if (selectedCount != 1) {
846         return;
847     }
848
849     /**********************************************/
850     /** retrieve the selected item from the list **/
851     /**********************************************/
852     i = 0;
853     XtSetArg(chooserArgs[i], XmNselectedItems, &selectedItem); i++;
854     XtGetValues(chooser_list, chooserArgs, i);
855     text = (char*) _XmStringUngenerate(
856                         selectedItem[0], NULL,
857                         XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
858     if (NULL == text) return;
859     
860     for (h = hostNamedb; h; h = h->next)
861         if (!strcmp (text, h->fullname))
862             if (!h->willing)
863                 XmListDeselectAllItems (chooser_list);
864
865     if (NULL != text) XtFree(text);
866 }
867
868 /* ARGSUSED */
869 void
870 DoCancel (w, event, params, num_params)
871     Widget w;
872     XEvent *event;
873     String *params;
874     Cardinal *num_params;
875 {
876     exit (OBEYSESS_DISPLAY);
877 }
878
879 /* ARGSUSED */
880 void
881 DoPing (w, event, params, num_params)
882     Widget w;
883     XEvent *event;
884     String *params;
885     Cardinal *num_params;
886 {
887     EmptyHostnames ();
888     pingTry = 0;
889     PingHosts ((XtPointer)NULL, (XtIntervalId *)NULL);
890 }
891
892 static XtActionsRec app_actions[] = {
893     "Accept",       DoAccept,
894     "Cancel",       DoCancel,
895     "CheckWilling", DoCheckWilling,
896     "Ping",         DoPing,
897 };
898
899 main (argc, argv)
900     char    **argv;
901 {
902     Arg         position[3];
903     Dimension   width, height;
904     Position    x, y;
905     int         i;
906     char        *xsetup;
907
908     /******************************/
909     /** set the locale, and      **/
910     /** open the message catalog **/
911     /******************************/
912
913     setlocale(LC_ALL, "");
914     XtSetLanguageProc( NULL, NULL, NULL );
915     langenv = getenv("LANG");
916
917     /******************************************/
918     /** set the font paths                   **/
919     /******************************************/
920     if ( (xsetup = getenv("XSETUP")) != NULL)
921       if(system(xsetup) == -1)
922             fprintf (stderr, "dtchooser: Cannot source %s\n",xsetup);
923
924     /******************************************/
925     /** save argc and argv for RespondLangCB **/
926     /******************************************/
927     amChooser = 1;  /** tell RespondLangCB we are a chooser **/
928     orig_argc = argc;
929     orig_argv = (char **)malloc(sizeof(char *) * (orig_argc+1));
930     for (i = 0; i < orig_argc; i++) {
931         orig_argv[i] = argv[i];
932     }
933     orig_argv[orig_argc] = NULL;
934
935     toplevel = XtInitialize (argv[0], "Dtlogin", options, XtNumber(options),
936                              &argc, argv);
937
938     XtVaSetValues(XmGetXmDisplay(XtDisplay(toplevel)),
939                 XmNdragInitiatorProtocolStyle, XmDRAG_NONE,
940                 NULL);
941
942     XtAddConverter(XtRString, XtRARRAY8, CvtStringToARRAY8, NULL, 0);
943
944     XtGetApplicationResources (toplevel, (XtPointer) &app_resources, resources,
945                                XtNumber (resources), NULL, (Cardinal) 0);
946
947     dpyinfo.dpy         = XtDisplay(toplevel);
948 /*    dpyinfo.name      = "";*/
949     dpyinfo.screen      = DefaultScreen(dpyinfo.dpy);
950     dpyinfo.root        = RootWindow   (dpyinfo.dpy, dpyinfo.screen);
951     dpyinfo.depth       = DefaultDepth (dpyinfo.dpy, dpyinfo.screen);
952     dpyinfo.width       = DisplayWidth (dpyinfo.dpy, dpyinfo.screen);
953     dpyinfo.height      = DisplayHeight(dpyinfo.dpy, dpyinfo.screen);
954     dpyinfo.black_pixel = BlackPixel   (dpyinfo.dpy, dpyinfo.screen);
955     dpyinfo.visual      = DefaultVisual(dpyinfo.dpy, dpyinfo.screen);
956
957     /*
958      *  build widgets...
959      */
960
961     MakeBackground();           /* login_shell, table, matte              */
962     MakeLogo();                 /* logo, logo_pixmap, logo_shadow         */
963     MakeButtons();              /* Push Buttons                           */
964     MakeChooser();              /* Chooser List ...                       */
965
966     if (appInfo.optionsDelay == 0 )
967         MakeOptionsMenu();      /* make option_button pop-up menu         */
968     else
969         XtAddTimeOut((unsigned long) appInfo.optionsDelay * 1000, MakeOptionsProc, NULL);
970
971 #if 0
972     /*
973      * center ourselves on the screen
974      */
975     XtSetMappedWhenManaged(toplevel, FALSE);
976     XtRealizeWidget (toplevel);
977 #endif
978     XtRealizeWidget (login_shell);
979 XtPopup(login_shell, XtGrabNone);
980 #if 0
981     XtSetArg (position[0], XtNwidth, &width);
982     XtSetArg (position[1], XtNheight, &height);
983     XtGetValues (login_shell, position, (Cardinal) 2);
984     x = (Position)(WidthOfScreen (XtScreen (toplevel)) - width) / 2;
985     y = (Position)(HeightOfScreen (XtScreen (toplevel)) - height) / 3;
986     XtSetArg (position[0], XtNx, x);
987     XtSetArg (position[1], XtNy, y);
988     XtSetValues (login_shell, position, (Cardinal) 2);
989 #endif
990
991     /*
992      * Run
993      */
994 #if 0
995     XtMapWidget(toplevel);
996 #endif
997     InitXDMCP (argv + 1);
998     XtMainLoop ();
999     exit(0);
1000     /*NOTREACHED*/
1001 }
1002
1003 /* Converts the hex string s of length len into the byte array d.
1004    Returns 0 if s was a legal hex string, 1 otherwise.
1005    */
1006 int
1007 FromHex (s, d, len)
1008     char    *s, *d;
1009     int     len;
1010 {
1011     int t;
1012     int ret = len&1;            /* odd-length hex strings are illegal */
1013     while (len >= 2)
1014     {
1015 #define HexChar(c)  ('0' <= (c) && (c) <= '9' ? (c) - '0' : (c) - 'a' + 10)
1016
1017         if (!ishexdigit(*s))
1018             ret = 1;
1019         t = HexChar (*s) << 4;
1020         s++;
1021         if (!ishexdigit(*s))
1022             ret = 1;
1023         t += HexChar (*s);
1024         s++;
1025         *d++ = t;
1026         len -= 2;
1027     }
1028     return ret;
1029 }
1030
1031 /*ARGSUSED*/
1032 static void
1033 CvtStringToARRAY8 (args, num_args, fromVal, toVal)
1034     XrmValuePtr args;
1035     Cardinal    *num_args;
1036     XrmValuePtr fromVal;
1037     XrmValuePtr toVal;
1038 {
1039     static ARRAY8Ptr    dest;
1040     char        *s;
1041     int         len;
1042
1043     dest = (ARRAY8Ptr) XtMalloc (sizeof (ARRAY8));
1044     len = fromVal->size;
1045     s = (char *) fromVal->addr;
1046     if (!XdmcpAllocARRAY8 (dest, len >> 1))
1047         XtStringConversionWarning ((char *) fromVal->addr, XtRARRAY8);
1048     else
1049     {
1050         FromHex (s, (char *) dest->data, len);
1051     }
1052     toVal->addr = (caddr_t) &dest;
1053     toVal->size = sizeof (ARRAY8Ptr);
1054 }