dtlogin: start to resolve static analysis warnings
[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 librararies 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, hosts->addr, hosts->addrlen);
226         else
227             XdmcpFlush (socketFD, &broadcastBuffer, 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->fullname);
401             free ((char *) new);
402             return 0;
403         }
404         memmove( new->hostaddr.data, hostAddr.data, hostAddr.length);
405         new->connectionType = connectionType;
406         new->hostname = *hostname;
407
408         *names = new;
409         new->next = 0;
410         NameTableSize++;
411     }
412     else
413     {
414         new = *names;
415         free (new->fullname);
416         XdmcpDisposeARRAY8 (&new->status);
417         XdmcpDisposeARRAY8 (hostname);
418     }
419     new->willing = willing;
420     new->status = *status;
421
422     hostname = &new->hostname;
423     fulllen = hostname->length;
424     if (fulllen < 30)
425         fulllen = 30;
426     new->fullname = malloc (fulllen + status->length + 10);
427     if (!new->fullname)
428     {
429         new->fullname = "Unknown";
430     }
431     else
432     {
433         sprintf (new->fullname, "%-30.*s %*.*s",
434                  hostname->length, hostname->data,
435                  status->length, status->length, status->data);
436     }
437     if (update)
438         RebuildTable (NameTableSize);
439     else
440         RebuildTableAdd (NameTableSize);
441     return 1;
442 }
443
444 static void
445 DisposeHostname (HostName *host)
446 {
447     XdmcpDisposeARRAY8 (&host->hostname);
448     XdmcpDisposeARRAY8 (&host->hostaddr);
449     XdmcpDisposeARRAY8 (&host->status);
450     free ((char *) host->fullname);
451     free ((char *) host);
452 }
453
454 static int
455 RemoveHostname (HostName *host)
456 {
457     HostName    **prev, *hosts;
458
459     prev = &hostNamedb;;
460     for (hosts = hostNamedb; hosts; hosts = hosts->next)
461     {
462         if (hosts == host)
463             break;
464         prev = &hosts->next;
465     }
466     if (!hosts)
467         return 0;
468     *prev = host->next;
469     DisposeHostname (host);
470     NameTableSize--;
471     RebuildTable (NameTableSize);
472
473     return 1;
474 }
475
476 static void
477 EmptyHostnames (void)
478 {
479     HostName    *hosts, *next;
480
481     for (hosts = hostNamedb; hosts; hosts = next)
482     {
483         next = hosts->next;
484         DisposeHostname (hosts);
485     }
486     NameTableSize = 0;
487     hostNamedb = 0;
488     RebuildTable (NameTableSize);
489 }
490
491 /* ARGSUSED */
492 static void
493 ReceivePacket (XtPointer closure, int *source, XtInputId *id)
494 {
495     XdmcpHeader     header;
496     ARRAY8          authenticationName;
497     ARRAY8          hostname;
498     ARRAY8          status;
499     int             saveHostname = 0;
500     struct sockaddr addr;
501     int             addrlen;
502
503     addrlen = sizeof (addr);
504     if (!XdmcpFill (socketFD, &buffer, &addr, &addrlen))
505         return;
506     if (!XdmcpReadHeader (&buffer, &header))
507         return;
508     if (header.version != XDM_PROTOCOL_VERSION)
509         return;
510     hostname.data = 0;
511     status.data = 0;
512     authenticationName.data = 0;
513     switch (header.opcode) {
514     case WILLING:
515         if (XdmcpReadARRAY8 (&buffer, &authenticationName) &&
516             XdmcpReadARRAY8 (&buffer, &hostname) &&
517             XdmcpReadARRAY8 (&buffer, &status))
518         {
519             if (header.length == 6 + authenticationName.length +
520                 hostname.length + status.length)
521             {
522                 if (AddHostname (&hostname, &status, &addr, header.opcode == (int) WILLING))
523                     saveHostname = 1;
524             }
525         }
526         XdmcpDisposeARRAY8 (&authenticationName);
527         break;
528     case UNWILLING:
529         if (XdmcpReadARRAY8 (&buffer, &hostname) &&
530             XdmcpReadARRAY8 (&buffer, &status))
531         {
532             if (header.length == 4 + hostname.length + status.length)
533             {
534                 if (AddHostname (&hostname, &status, &addr, header.opcode == (int) WILLING))
535                     saveHostname = 1;
536
537             }
538         }
539         break;
540     default:
541         break;
542     }
543     if (!saveHostname)
544     {
545         XdmcpDisposeARRAY8 (&hostname);
546         XdmcpDisposeARRAY8 (&status);
547     }
548 }
549
550 int
551 RegisterHostaddr (struct sockaddr *addr, int len, xdmOpCode type)
552 {
553     HostAddr            *host, **prev;
554
555     host = (HostAddr *) malloc (sizeof (HostAddr));
556     if (!host)
557         return 0;
558     host->addr = (struct sockaddr *) malloc (len);
559     if (!host->addr)
560     {
561         free ((char *) host);
562         return 0;
563     }
564     memmove( (char *) host->addr, (char *) addr, len);
565     host->addrlen = len;
566     host->type = type;
567     for (prev = &hostAddrdb; *prev; prev = &(*prev)->next)
568         ;
569     *prev = host;
570     host->next = NULL;
571     return 1;
572 }
573
574 /*
575  * Register the address for this host.
576  * Called with each of the names on the command line.
577  * The special name "BROADCAST" looks up all the broadcast
578  *  addresses on the local host.
579  */
580 int
581 RegisterHostname (char *name)
582 {
583     struct hostent      *hostent;
584     struct sockaddr_in  in_addr;
585     struct ifconf       ifc;
586     register struct ifreq *ifr;
587     struct sockaddr     broad_addr;
588     char                buf[2048];
589     int                 n;
590
591     if (!strcmp (name, BROADCAST_HOSTNAME))
592     {
593         ifc.ifc_len = sizeof (buf);
594         ifc.ifc_buf = buf;
595         if (ioctl (socketFD, (int) SIOCGIFCONF, (char *) &ifc) < 0)
596             return 0;
597         for (ifr = ifc.ifc_req
598 #if defined (__bsdi__) || defined(__NetBSD__)
599              ; (char *)ifr < ifc.ifc_buf + ifc.ifc_len;
600              ifr = (struct ifreq *)((char *)ifr + sizeof (struct ifreq) +
601                 (ifr->ifr_addr.sa_len > sizeof (ifr->ifr_addr) ?
602                  ifr->ifr_addr.sa_len - sizeof (ifr->ifr_addr) : 0))
603 #else
604              , n = ifc.ifc_len / sizeof (struct ifreq); --n >= 0; ifr++
605 #endif
606              )
607         {
608             if (ifr->ifr_addr.sa_family != AF_INET)
609                 continue;
610
611             broad_addr = ifr->ifr_addr;
612             ((struct sockaddr_in *) &broad_addr)->sin_addr.s_addr =
613                 htonl (INADDR_BROADCAST);
614 #ifdef SIOCGIFBRDADDR
615             {
616                 struct ifreq    broad_req;
617     
618                 broad_req = *ifr;
619                 if (ioctl (socketFD, SIOCGIFFLAGS, (char *) &broad_req) != -1 &&
620                     (broad_req.ifr_flags & IFF_BROADCAST) &&
621                     (broad_req.ifr_flags & IFF_UP)
622                     )
623                 {
624                     broad_req = *ifr;
625                     if (ioctl (socketFD, SIOCGIFBRDADDR, &broad_req) != -1)
626                         broad_addr = broad_req.ifr_addr;
627                     else
628                         continue;
629                 }
630                 else
631                     continue;
632             }
633 #endif
634             in_addr = *((struct sockaddr_in *) &broad_addr);
635             in_addr.sin_port = htons (XDM_UDP_PORT);
636 #ifdef BSD44SOCKETS
637             in_addr.sin_len = sizeof(in_addr);
638 #endif
639             RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr),
640                               BROADCAST_QUERY);
641         }
642     }
643     else
644     {
645
646         /* address as hex string, e.g., "12180022" (depreciated) */
647         if (strlen(name) == 8 &&
648             FromHex(name, (char *)&in_addr.sin_addr, strlen(name)) == 0)
649         {
650             in_addr.sin_family = AF_INET;
651         }
652         /* Per RFC 1123, check first for IP address in dotted-decimal form */
653         else if ((in_addr.sin_addr.s_addr = inet_addr(name)) != -1)
654             in_addr.sin_family = AF_INET;
655         else
656         {
657             hostent = gethostbyname (name);
658             if (!hostent)
659                 return 0;
660             if (hostent->h_addrtype != AF_INET || hostent->h_length != 4)
661                 return 0;
662             in_addr.sin_family = hostent->h_addrtype;
663             memmove( &in_addr.sin_addr, hostent->h_addr, 4);
664         }
665         in_addr.sin_port = htons (XDM_UDP_PORT);
666 #ifdef BSD44SOCKETS
667         in_addr.sin_len = sizeof(in_addr);
668 #endif
669         RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr),
670                           QUERY);
671     }
672     return 1;
673 }
674
675 static ARRAYofARRAY8    AuthenticationNames;
676
677 static int
678 RegisterAuthenticationName (char *name, int namelen)
679 {
680     ARRAY8Ptr   authName;
681     if (!XdmcpReallocARRAYofARRAY8 (&AuthenticationNames,
682                                     AuthenticationNames.length + 1))
683         return 0;
684     authName = &AuthenticationNames.data[AuthenticationNames.length-1];
685     if (!XdmcpAllocARRAY8 (authName, namelen))
686         return 0;
687     memmove( authName->data, name, namelen);
688
689     return 1;
690 }
691
692 int
693 InitXDMCP (char **argv)
694 {
695     int soopts = 1;
696     XdmcpHeader header;
697     int i;
698     int optlen;
699
700     header.version = XDM_PROTOCOL_VERSION;
701     header.opcode = (CARD16) BROADCAST_QUERY;
702     header.length = 1;
703     for (i = 0; i < (int)AuthenticationNames.length; i++)
704         header.length += 2 + AuthenticationNames.data[i].length;
705     XdmcpWriteHeader (&broadcastBuffer, &header);
706     XdmcpWriteARRAYofARRAY8 (&broadcastBuffer, &AuthenticationNames);
707
708     header.version = XDM_PROTOCOL_VERSION;
709     header.opcode = (CARD16) QUERY;
710     header.length = 1;
711     for (i = 0; i < (int)AuthenticationNames.length; i++)
712         header.length += 2 + AuthenticationNames.data[i].length;
713     XdmcpWriteHeader (&directBuffer, &header);
714     XdmcpWriteARRAYofARRAY8 (&directBuffer, &AuthenticationNames);
715     if ((socketFD = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
716         return 0;
717 #ifdef SO_BROADCAST
718     soopts = 1;
719     if (setsockopt (socketFD, SOL_SOCKET, SO_BROADCAST, (char *)&soopts, sizeof (soopts)) < 0)
720         perror ("setsockopt");
721 #endif
722     
723     XtAddInput (socketFD, (XtPointer) XtInputReadMask, ReceivePacket,
724                 (XtPointer) 0);
725     while (*argv)
726     {
727         RegisterHostname (*argv);
728         ++argv;
729     }
730     pingTry = 0;
731     PingHosts ((XtPointer)NULL, (XtIntervalId *)NULL);
732     return 1;
733 }
734
735 void
736 Choose (HostName *h)
737 {
738     if (app_resources.xdmAddress)
739     {
740         struct sockaddr_in  in_addr;
741         struct sockaddr *addr;
742         int             family;
743         int             len;
744         int             fd;
745         char            buf[1024];
746         XdmcpBuffer     buffer;
747         char            *xdm;
748
749         xdm = (char *) app_resources.xdmAddress->data;
750         family = (xdm[0] << 8) + xdm[1];
751         switch (family) {
752         case AF_INET:
753 #ifdef BSD44SOCKETS
754             in_addr.sin_len = sizeof(in_addr);
755 #endif
756             in_addr.sin_family = family;
757             memmove( &in_addr.sin_port, xdm + 2, 2);
758             memmove( &in_addr.sin_addr, xdm + 4, 4);
759             addr = (struct sockaddr *) &in_addr;
760             len = sizeof (in_addr);
761             break;
762         }
763         if ((fd = socket (family, SOCK_STREAM, 0)) == -1)
764         {
765             fprintf (stderr, "Cannot create response socket\n");
766             exit (REMANAGE_DISPLAY);
767         }
768         if (connect (fd, addr, len) == -1)
769         {
770             fprintf (stderr, "Cannot connect to xdm\n");
771             exit (REMANAGE_DISPLAY);
772         }
773         buffer.data = (BYTE *) buf;
774         buffer.size = sizeof (buf);
775         buffer.pointer = 0;
776         buffer.count = 0;
777         XdmcpWriteARRAY8 (&buffer, app_resources.clientAddress);
778         XdmcpWriteCARD16 (&buffer, (CARD16) app_resources.connectionType);
779         XdmcpWriteARRAY8 (&buffer, &h->hostaddr);
780         write (fd, (char *)buffer.data, buffer.pointer);
781         close (fd);
782     }
783     else
784     {
785         int i;
786
787         printf ("%u\n", h->connectionType);
788         for (i = 0; i < (int)h->hostaddr.length; i++)
789             printf ("%u%s", h->hostaddr.data[i],
790                     i == h->hostaddr.length - 1 ? "\n" : " ");
791     }
792 }
793
794 /* ARGSUSED */
795 void
796 DoAccept (Widget w, XEvent *event, String *params, Cardinal *num_params)
797 {
798     HostName            *h;
799     XmStringTable       selectedItem;
800     int                 selectedCount;
801     int                 i;
802     char                *text;
803
804     /*********************************/
805     /** see if anything is selected **/
806     /*********************************/
807     i = 0;
808     XtSetArg(chooserArgs[i], XmNselectedItemCount, &selectedCount); i++;
809     XtGetValues(chooser_list, chooserArgs, i);
810     if (selectedCount != 1) {
811         XBell (XtDisplay (toplevel), 0);
812         return;
813     }
814
815     /**********************************************/
816     /** retrieve the selected item from the list **/
817     /**********************************************/
818     i = 0;
819     XtSetArg(chooserArgs[i], XmNselectedItems, &selectedItem); i++;
820     XtGetValues(chooser_list, chooserArgs, i);
821     text = (char*) _XmStringUngenerate(
822                         selectedItem[0], NULL,
823                         XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
824     if (NULL == text) return;
825     
826     for (h = hostNamedb; h; h = h->next)
827         if (!strcmp (text, h->fullname))
828         {
829             Choose (h);
830         }
831     if (NULL != text) XtFree(text);
832     exit (OBEYSESS_DISPLAY);
833 }
834
835 /* ARGSUSED */
836 static void
837 DoCheckWilling (Widget w, XEvent *event, String *params, Cardinal *num_params)
838 {
839     HostName            *h;
840     XmStringTable       selectedItem;
841     int                 selectedCount;
842     int                 i;
843     char                *text;
844
845     /*********************************/
846     /** see if anything is selected **/
847     /*********************************/
848     i = 0;
849     XtSetArg(chooserArgs[i], XmNselectedItemCount, &selectedCount); i++;
850     XtGetValues(chooser_list, chooserArgs, i);
851     if (selectedCount != 1) {
852         return;
853     }
854
855     /**********************************************/
856     /** retrieve the selected item from the list **/
857     /**********************************************/
858     i = 0;
859     XtSetArg(chooserArgs[i], XmNselectedItems, &selectedItem); i++;
860     XtGetValues(chooser_list, chooserArgs, i);
861     text = (char*) _XmStringUngenerate(
862                         selectedItem[0], NULL,
863                         XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
864     if (NULL == text) return;
865     
866     for (h = hostNamedb; h; h = h->next)
867         if (!strcmp (text, h->fullname))
868             if (!h->willing)
869                 XmListDeselectAllItems (chooser_list);
870
871     if (NULL != text) XtFree(text);
872 }
873
874 /* ARGSUSED */
875 void
876 DoCancel (Widget w, XEvent *event, String *params, Cardinal *num_params)
877 {
878     exit (OBEYSESS_DISPLAY);
879 }
880
881 /* ARGSUSED */
882 void
883 DoPing (Widget w, XEvent *event, String *params, Cardinal *num_params)
884 {
885     EmptyHostnames ();
886     pingTry = 0;
887     PingHosts ((XtPointer)NULL, (XtIntervalId *)NULL);
888 }
889
890 static XtActionsRec app_actions[] = {
891     "Accept",       DoAccept,
892     "Cancel",       DoCancel,
893     "CheckWilling", DoCheckWilling,
894     "Ping",         DoPing,
895 };
896
897 int
898 main (int argc, char **argv)
899 {
900     Arg         position[3];
901     Dimension   width, height;
902     Position    x, y;
903     int         i;
904     char        *xsetup;
905
906     /******************************/
907     /** set the locale, and      **/
908     /** open the message catalog **/
909     /******************************/
910
911     setlocale(LC_ALL, "");
912     XtSetLanguageProc( NULL, NULL, NULL );
913     langenv = getenv("LANG");
914
915     /******************************************/
916     /** set the font paths                   **/
917     /******************************************/
918     if ( (xsetup = getenv("XSETUP")) != NULL)
919       if(system(xsetup) == -1)
920             fprintf (stderr, "dtchooser: Cannot source %s\n",xsetup);
921
922     /******************************************/
923     /** save argc and argv for RespondLangCB **/
924     /******************************************/
925     amChooser = 1;  /** tell RespondLangCB we are a chooser **/
926     orig_argc = argc;
927     orig_argv = (char **)malloc(sizeof(char *) * (orig_argc+1));
928     for (i = 0; i < orig_argc; i++) {
929         orig_argv[i] = argv[i];
930     }
931     orig_argv[orig_argc] = NULL;
932
933     toplevel = XtInitialize (argv[0], "Dtlogin", options, XtNumber(options),
934                              &argc, argv);
935
936     XtVaSetValues(XmGetXmDisplay(XtDisplay(toplevel)),
937                 XmNdragInitiatorProtocolStyle, XmDRAG_NONE,
938                 NULL);
939
940     XtAddConverter(XtRString, XtRARRAY8, CvtStringToARRAY8, NULL, 0);
941
942     XtGetApplicationResources (toplevel, (XtPointer) &app_resources, resources,
943                                XtNumber (resources), NULL, (Cardinal) 0);
944
945     dpyinfo.dpy         = XtDisplay(toplevel);
946 /*    dpyinfo.name      = "";*/
947     dpyinfo.screen      = DefaultScreen(dpyinfo.dpy);
948     dpyinfo.root        = RootWindow   (dpyinfo.dpy, dpyinfo.screen);
949     dpyinfo.depth       = DefaultDepth (dpyinfo.dpy, dpyinfo.screen);
950     dpyinfo.width       = DisplayWidth (dpyinfo.dpy, dpyinfo.screen);
951     dpyinfo.height      = DisplayHeight(dpyinfo.dpy, dpyinfo.screen);
952     dpyinfo.black_pixel = BlackPixel   (dpyinfo.dpy, dpyinfo.screen);
953     dpyinfo.visual      = DefaultVisual(dpyinfo.dpy, dpyinfo.screen);
954
955     /*
956      *  build widgets...
957      */
958
959     MakeBackground();           /* login_shell, table, matte              */
960     MakeLogo();                 /* logo, logo_pixmap, logo_shadow         */
961     MakeButtons();              /* Push Buttons                           */
962     MakeChooser();              /* Chooser List ...                       */
963
964     if (appInfo.optionsDelay == 0 )
965         MakeOptionsMenu();      /* make option_button pop-up menu         */
966     else
967         XtAddTimeOut((unsigned long) appInfo.optionsDelay * 1000, MakeOptionsProc, NULL);
968
969 #if 0
970     /*
971      * center ourselves on the screen
972      */
973     XtSetMappedWhenManaged(toplevel, FALSE);
974     XtRealizeWidget (toplevel);
975 #endif
976     XtRealizeWidget (login_shell);
977 XtPopup(login_shell, XtGrabNone);
978 #if 0
979     XtSetArg (position[0], XtNwidth, &width);
980     XtSetArg (position[1], XtNheight, &height);
981     XtGetValues (login_shell, position, (Cardinal) 2);
982     x = (Position)(WidthOfScreen (XtScreen (toplevel)) - width) / 2;
983     y = (Position)(HeightOfScreen (XtScreen (toplevel)) - height) / 3;
984     XtSetArg (position[0], XtNx, x);
985     XtSetArg (position[1], XtNy, y);
986     XtSetValues (login_shell, position, (Cardinal) 2);
987 #endif
988
989     /*
990      * Run
991      */
992 #if 0
993     XtMapWidget(toplevel);
994 #endif
995     InitXDMCP (argv + 1);
996     XtMainLoop ();
997
998     return 0;
999 }
1000
1001 /* Converts the hex string s of length len into the byte array d.
1002    Returns 0 if s was a legal hex string, 1 otherwise.
1003    */
1004 static int
1005 FromHex (char *s, char *d, int len)
1006 {
1007     int t;
1008     int ret = len&1;            /* odd-length hex strings are illegal */
1009     while (len >= 2)
1010     {
1011 #define HexChar(c)  ('0' <= (c) && (c) <= '9' ? (c) - '0' : (c) - 'a' + 10)
1012
1013         if (!ishexdigit(*s))
1014             ret = 1;
1015         t = HexChar (*s) << 4;
1016         s++;
1017         if (!ishexdigit(*s))
1018             ret = 1;
1019         t += HexChar (*s);
1020         s++;
1021         *d++ = t;
1022         len -= 2;
1023     }
1024     return ret;
1025 }
1026
1027 /*ARGSUSED*/
1028 static void
1029 CvtStringToARRAY8 (XrmValuePtr args, Cardinal *num_args, XrmValuePtr fromVal, XrmValuePtr toVal)
1030 {
1031     static ARRAY8Ptr    dest;
1032     char        *s;
1033     int         len;
1034
1035     dest = (ARRAY8Ptr) XtMalloc (sizeof (ARRAY8));
1036     len = fromVal->size;
1037     s = (char *) fromVal->addr;
1038     if (!XdmcpAllocARRAY8 (dest, len >> 1))
1039         XtStringConversionWarning ((char *) fromVal->addr, XtRARRAY8);
1040     else
1041     {
1042         FromHex (s, (char *) dest->data, len);
1043     }
1044     toVal->addr = (caddr_t) &dest;
1045     toVal->size = sizeof (ARRAY8Ptr);
1046 }