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