1 /*
2 *
3 Copyright 1990, 1998 The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24 *
25 * Author: Keith Packard, MIT X Consortium
26 */
27
28
29 /*
30 * Chooser - display a menu of names and let the user select one
31 */
32
33 /*
34 * Layout:
35 *
36 * +--------------------------------------------------+
37 * | +------------------+ |
38 * | | Label | |
39 * | +------------------+ |
40 * | +-+--------------+ |
41 * | |^| name-1 | |
42 * | ||| name-2 | |
43 * | |v| name-3 | |
44 * | | | name-4 | |
45 * | | | name-5 | |
46 * | | | name-6 | |
47 * | +----------------+ |
48 * | cancel accept ping |
49 * +--------------------------------------------------+
50 */
51
52 #include <X11/Intrinsic.h>
53 #include <X11/StringDefs.h>
54 #include <X11/Xatom.h>
55
56 #include <X11/Xaw/Paned.h>
57 #include <X11/Xaw/Label.h>
58 #include <X11/Xaw/Viewport.h>
59 #include <X11/Xaw/List.h>
60 #include <X11/Xaw/Box.h>
61 #include <X11/Xaw/Command.h>
62
63 #include "dm.h"
64
65 #include <X11/Xdmcp.h>
66
67 #include <sys/types.h>
68 #include <stdio.h>
69 #include <ctype.h>
70
71 #ifdef USE_XINERAMA
72 # include <X11/extensions/Xinerama.h>
73 #endif
74
75 #if defined(SVR4)
76 # include <sys/sockio.h>
77 #endif
78 #if defined(SVR4) && defined(PowerMAX_OS)
79 # include <sys/stropts.h>
80 #endif
81 #if defined(SYSV) && defined(i386)
82 # include <sys/stream.h>
83 #endif
84
85 #include "dm_socket.h"
86
87 #include <arpa/inet.h>
88
89 #include <sys/ioctl.h>
90
91 #ifdef HAVE_SYS_PARAM_H
92 # include <sys/param.h>
93 # ifdef BSD
94 # if (BSD >= 199103)
95 # define VARIABLE_IFREQ
96 # endif
97 # endif
98 #endif
99
100 #ifdef XKB
101 # include <X11/extensions/XKBbells.h>
102 #endif
103
104 #define BROADCAST_HOSTNAME "BROADCAST"
105
106 #ifndef ishexdigit
107 # define ishexdigit(c) (isdigit(c) || ('a' <= (c) && (c) <= 'f'))
108 #endif
109
110 #ifdef hpux
111 # include <sys/utsname.h>
112 # ifdef HAS_IFREQ
113 # include <net/if.h>
114 # endif
115 #else
116 # ifdef __convex__
117 # include <sync/queue.h>
118 # include <sync/sema.h>
119 # endif
120 # include <net/if.h>
121 #endif /* hpux */
122
123 #include <netdb.h>
124 #include <X11/keysym.h>
125
126 static int FromHex (char *s, char *d, int len);
127 static int oldline;
128
129 static Widget toplevel, label, viewport, paned, list, box, cancel, acceptit, ping;
130
131 static void CvtStringToARRAY8(
132 XrmValuePtr args,
133 Cardinal *num_args,
134 XrmValuePtr fromVal,
135 XrmValuePtr toVal);
136
137 static struct _app_resources {
138 ARRAY8Ptr xdmAddress;
139 ARRAY8Ptr clientAddress;
140 int connectionType;
141 } app_resources;
142
143 #define offset(field) XtOffsetOf(struct _app_resources, field)
144
145 #define XtRARRAY8 "ARRAY8"
146
147 static XtResource resources[] = {
148 {"xdmAddress", "XdmAddress", XtRARRAY8, sizeof (ARRAY8Ptr),
149 offset (xdmAddress), XtRString, NULL },
150 {"clientAddress", "ClientAddress", XtRARRAY8, sizeof (ARRAY8Ptr),
151 offset (clientAddress), XtRString, NULL },
152 {"connectionType", "ConnectionType", XtRInt, sizeof (int),
153 offset (connectionType), XtRImmediate, (XtPointer) 0 }
154 };
155 #undef offset
156
157 static XrmOptionDescRec options[] = {
158 { "-xdmaddress", "*xdmAddress", XrmoptionSepArg, NULL },
159 { "-clientaddress", "*clientAddress", XrmoptionSepArg, NULL },
160 { "-connectionType","*connectionType", XrmoptionSepArg, NULL },
161 };
162
163 typedef struct _hostAddr {
164 struct _hostAddr *next;
165 struct sockaddr *addr;
166 int addrlen;
167 xdmOpCode type;
168 } HostAddr;
169
170 static HostAddr *hostAddrdb;
171
172 typedef struct _hostName {
173 struct _hostName *next;
174 char *fullname;
175 int willing;
176 ARRAY8 hostname, status;
177 CARD16 connectionType;
178 ARRAY8 hostaddr;
179 } HostName;
180
181 static HostName *hostNamedb;
182
183 static int socketFD;
184 #if defined(IPv6) && defined(AF_INET6)
185 static int socket6FD;
186 #endif
187
188 static int pingTry;
189
190 #define PING_INTERVAL 2000
191 #define TRIES 3
192
193 static XdmcpBuffer directBuffer, broadcastBuffer;
194 static XdmcpBuffer buffer;
195
196 #if (defined(SVR4) && !defined(sun) && !defined(__sgi) && !defined(NCR)) && defined(SIOCGIFCONF)
197
198 /* Deal with different SIOCGIFCONF ioctl semantics on these OSs */
199
200 static int
ifioctl(int fd,int cmd,char * arg)201 ifioctl (int fd, int cmd, char *arg)
202 {
203 struct strioctl ioc;
204 int ret;
205
206 bzero((char *) &ioc, sizeof(ioc));
207 ioc.ic_cmd = cmd;
208 ioc.ic_timout = 0;
209 if (cmd == SIOCGIFCONF)
210 {
211 ioc.ic_len = ((struct ifconf *) arg)->ifc_len;
212 ioc.ic_dp = ((struct ifconf *) arg)->ifc_buf;
213 }
214 else
215 {
216 ioc.ic_len = sizeof(struct ifreq);
217 ioc.ic_dp = arg;
218 }
219 ret = ioctl(fd, I_STR, (char *) &ioc);
220 if (ret >= 0 && cmd == SIOCGIFCONF)
221 ((struct ifconf *) arg)->ifc_len = ioc.ic_len;
222 return(ret);
223 }
224 #else /* (SVR4 && !sun && !NCR) && SIOCGIFCONF */
225 # define ifioctl ioctl
226 #endif /* (SVR4 && !sun && !NCR) && SIOCGIFCONF */
227
228
229 /* ARGSUSED */
230 static void
PingHosts(XtPointer closure,XtIntervalId * id)231 PingHosts (XtPointer closure, XtIntervalId *id)
232 {
233 HostAddr *hosts;
234 int sfd = socketFD;
235
236 for (hosts = hostAddrdb; hosts; hosts = hosts->next)
237 {
238 #if defined(IPv6) && defined(AF_INET6)
239 if ( ((struct sockaddr *) hosts->addr)->sa_family == AF_INET6 )
240 sfd = socket6FD;
241 else
242 sfd = socketFD;
243 #endif
244 if (hosts->type == QUERY)
245 XdmcpFlush (sfd, &directBuffer,
246 (XdmcpNetaddr) hosts->addr, hosts->addrlen);
247 else
248 XdmcpFlush (sfd, &broadcastBuffer,
249 (XdmcpNetaddr) hosts->addr, hosts->addrlen);
250 }
251 if (++pingTry < TRIES)
252 XtAddTimeOut (PING_INTERVAL, PingHosts, (XtPointer) 0);
253 }
254
255 char **NameTable;
256 int NameTableSize;
257
258 static int
HostnameCompare(const void * a,const void * b)259 HostnameCompare (const void *a, const void *b)
260 {
261 return strcmp (*(char **)a, *(char **)b);
262 }
263
264 static void
RebuildTable(int size)265 RebuildTable (int size)
266 {
267 char **newTable = NULL;
268 HostName *names;
269 int i;
270
271 if (size)
272 {
273 newTable = malloc (size * sizeof (char *));
274 if (!newTable)
275 return;
276 for (names = hostNamedb, i = 0; names; names = names->next, i++)
277 newTable[i] = names->fullname;
278 qsort (newTable, size, sizeof (char *), HostnameCompare);
279 }
280 XawListChange (list, newTable, size, 0, TRUE);
281 free (NameTable);
282 NameTable = newTable;
283 NameTableSize = size;
284 }
285
286 static int
AddHostname(ARRAY8Ptr hostname,ARRAY8Ptr status,struct sockaddr * addr,int willing)287 AddHostname (ARRAY8Ptr hostname, ARRAY8Ptr status, struct sockaddr *addr, int willing)
288 {
289 HostName *new, **names, *name;
290 ARRAY8 hostAddr = {0, NULL};
291 CARD16 connectionType;
292 int fulllen;
293
294 switch (addr->sa_family)
295 {
296 case AF_INET:
297 hostAddr.data = (CARD8 *) &((struct sockaddr_in *) addr)->sin_addr;
298 hostAddr.length = 4;
299 connectionType = FamilyInternet;
300 break;
301 #if defined(IPv6) && defined(AF_INET6)
302 case AF_INET6:
303 hostAddr.data = (CARD8 *) &((struct sockaddr_in6 *) addr)->sin6_addr;
304 hostAddr.length = 16;
305 connectionType = FamilyInternet6;
306 break;
307 #endif
308 default:
309 hostAddr.data = (CARD8 *) "";
310 hostAddr.length = 0;
311 connectionType = FamilyLocal;
312 break;
313 }
314 for (names = &hostNamedb; *names; names = & (*names)->next)
315 {
316 name = *names;
317 if (connectionType == name->connectionType &&
318 XdmcpARRAY8Equal (&hostAddr, &name->hostaddr))
319 {
320 if (XdmcpARRAY8Equal (status, &name->status))
321 {
322 return 0;
323 }
324 break;
325 }
326 }
327 if (!*names)
328 {
329 new = malloc (sizeof (HostName));
330 if (!new)
331 return 0;
332 if (hostname->length)
333 {
334 switch (addr->sa_family)
335 {
336 case AF_INET:
337 #if defined(IPv6) && defined(AF_INET6)
338 case AF_INET6:
339 #endif
340 {
341 struct hostent *hostent;
342 char *host;
343
344 hostent = gethostbyaddr ((char *)hostAddr.data, hostAddr.length, addr->sa_family);
345 if (hostent)
346 {
347 XdmcpDisposeARRAY8 (hostname);
348 host = (char *)hostent->h_name;
349 XdmcpAllocARRAY8 (hostname, strlen (host));
350 memmove( hostname->data, host, hostname->length);
351 }
352 }
353 }
354 }
355 if (!XdmcpAllocARRAY8 (&new->hostaddr, hostAddr.length))
356 {
357 free (new->fullname);
358 free (new);
359 return 0;
360 }
361 memmove( new->hostaddr.data, hostAddr.data, hostAddr.length);
362 new->connectionType = connectionType;
363 new->hostname = *hostname;
364
365 *names = new;
366 new->next = NULL;
367 NameTableSize++;
368 }
369 else
370 {
371 new = *names;
372 free (new->fullname);
373 XdmcpDisposeARRAY8 (&new->status);
374 XdmcpDisposeARRAY8 (hostname);
375 }
376 new->willing = willing;
377 new->status = *status;
378
379 hostname = &new->hostname;
380 fulllen = hostname->length;
381 if (fulllen < 30)
382 fulllen = 30;
383 fulllen += status->length + 10;
384 new->fullname = malloc (fulllen);
385 if (!new->fullname)
386 {
387 new->fullname = "Unknown";
388 }
389 else
390 {
391 snprintf(new->fullname, fulllen, "%-30.*s %*.*s",
392 hostname->length, hostname->data,
393 status->length, status->length, status->data);
394 }
395 RebuildTable (NameTableSize);
396 return 1;
397 }
398
399 static void
DisposeHostname(HostName * host)400 DisposeHostname (HostName *host)
401 {
402 XdmcpDisposeARRAY8 (&host->hostname);
403 XdmcpDisposeARRAY8 (&host->hostaddr);
404 XdmcpDisposeARRAY8 (&host->status);
405 free (host->fullname);
406 free (host);
407 }
408
409 static void
EmptyHostnames(void)410 EmptyHostnames (void)
411 {
412 HostName *hosts, *next;
413
414 for (hosts = hostNamedb; hosts; hosts = next)
415 {
416 next = hosts->next;
417 DisposeHostname (hosts);
418 }
419 NameTableSize = 0;
420 hostNamedb = NULL;
421 RebuildTable (NameTableSize);
422 }
423
424 /* ARGSUSED */
425 static void
ReceivePacket(XtPointer closure,int * source,XtInputId * id)426 ReceivePacket (XtPointer closure, int *source, XtInputId *id)
427 {
428 XdmcpHeader header;
429 ARRAY8 authenticationName = {0, NULL};
430 ARRAY8 hostname = {0, NULL};
431 ARRAY8 status = {0, NULL};
432 int saveHostname = 0;
433 #if defined(IPv6) && defined(AF_INET6)
434 struct sockaddr_storage addr;
435 #else
436 struct sockaddr addr;
437 #endif
438 int addrlen;
439 int sfd = * (int *) closure;
440
441 addrlen = sizeof (addr);
442 if (!XdmcpFill (sfd, &buffer, (XdmcpNetaddr) &addr, &addrlen))
443 return;
444 if (!XdmcpReadHeader (&buffer, &header))
445 return;
446 if (header.version != XDM_PROTOCOL_VERSION)
447 return;
448 switch (header.opcode) {
449 case WILLING:
450 if (XdmcpReadARRAY8 (&buffer, &authenticationName) &&
451 XdmcpReadARRAY8 (&buffer, &hostname) &&
452 XdmcpReadARRAY8 (&buffer, &status))
453 {
454 if (header.length == 6 + authenticationName.length +
455 hostname.length + status.length)
456 {
457 if (AddHostname (&hostname, &status, (struct sockaddr *) &addr,
458 header.opcode == (int) WILLING))
459 saveHostname = 1;
460 }
461 }
462 XdmcpDisposeARRAY8 (&authenticationName);
463 break;
464 case UNWILLING:
465 if (XdmcpReadARRAY8 (&buffer, &hostname) &&
466 XdmcpReadARRAY8 (&buffer, &status))
467 {
468 if (header.length == 4 + hostname.length + status.length)
469 {
470 if (AddHostname (&hostname, &status, (struct sockaddr *) &addr,
471 header.opcode == (int) WILLING))
472 saveHostname = 1;
473
474 }
475 }
476 break;
477 default:
478 break;
479 }
480 if (!saveHostname)
481 {
482 XdmcpDisposeARRAY8 (&hostname);
483 XdmcpDisposeARRAY8 (&status);
484 }
485 }
486
487 static void
RegisterHostaddr(struct sockaddr * addr,int len,xdmOpCode type)488 RegisterHostaddr (struct sockaddr *addr, int len, xdmOpCode type)
489 {
490 HostAddr *host, **prev;
491
492 host = malloc (sizeof (HostAddr));
493 if (!host)
494 return;
495 host->addr = malloc (len);
496 if (!host->addr)
497 {
498 free (host);
499 return;
500 }
501 memmove( (char *) host->addr, (char *) addr, len);
502 host->addrlen = len;
503 host->type = type;
504 for (prev = &hostAddrdb; *prev; prev = &(*prev)->next)
505 ;
506 *prev = host;
507 host->next = NULL;
508 }
509
510 /*
511 * Register the address for this host.
512 * Called with each of the names on the command line.
513 * The special name "BROADCAST" looks up all the broadcast
514 * addresses on the local host.
515 */
516
517 /* Handle variable length ifreq in BNR2 and later */
518 #ifdef VARIABLE_IFREQ
519 # define ifr_size(p) (sizeof (struct ifreq) + \
520 (p->ifr_addr.sa_len > sizeof (p->ifr_addr) ? \
521 p->ifr_addr.sa_len - sizeof (p->ifr_addr) : 0))
522 #else
523 # define ifr_size(p) (sizeof (struct ifreq))
524 #endif
525
526 static void
RegisterHostname(char * name)527 RegisterHostname (char *name)
528 {
529 #if !defined(IPv6) || !defined(AF_INET6)
530 struct hostent *hostent;
531 #endif
532 struct sockaddr_in in_addr;
533 struct ifconf ifc;
534 register struct ifreq *ifr;
535 struct sockaddr broad_addr;
536 char buf[2048], *cp, *cplim;
537
538 if (!strcmp (name, BROADCAST_HOSTNAME))
539 {
540 ifc.ifc_len = sizeof (buf);
541 ifc.ifc_buf = buf;
542 if (ifioctl (socketFD, (int) SIOCGIFCONF, (char *) &ifc) < 0)
543 return;
544
545 cplim = (char *) ifc.ifc_req + ifc.ifc_len;
546
547 for (cp = (char *) ifc.ifc_req; cp < cplim; cp += ifr_size (ifr))
548 {
549 ifr = (struct ifreq *) cp;
550 if (ifr->ifr_addr.sa_family != AF_INET)
551 continue;
552
553 broad_addr = ifr->ifr_addr;
554 ((struct sockaddr_in *) &broad_addr)->sin_addr.s_addr =
555 htonl (INADDR_BROADCAST);
556 #ifdef SIOCGIFBRDADDR
557 {
558 struct ifreq broad_req;
559
560 broad_req = *ifr;
561 if (ifioctl (socketFD, SIOCGIFFLAGS, (char *) &broad_req) != -1 &&
562 (broad_req.ifr_flags & IFF_BROADCAST) &&
563 (broad_req.ifr_flags & IFF_UP)
564 )
565 {
566 broad_req = *ifr;
567 if (ifioctl (socketFD, SIOCGIFBRDADDR, &broad_req) != -1)
568 broad_addr = broad_req.ifr_addr;
569 else
570 continue;
571 }
572 else
573 continue;
574 }
575 #endif
576 in_addr = *((struct sockaddr_in *) &broad_addr);
577 in_addr.sin_port = htons (XDM_UDP_PORT);
578 #ifdef BSD44SOCKETS
579 in_addr.sin_len = sizeof(in_addr);
580 #endif
581 RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr),
582 BROADCAST_QUERY);
583 }
584 }
585 else
586 {
587 /* address as hex string, e.g., "12180022" (deprecated) */
588 if (strlen(name) == 8 &&
589 FromHex(name, (char *)&in_addr.sin_addr, strlen(name)) == 0)
590 {
591 in_addr.sin_family = AF_INET;
592 in_addr.sin_port = htons (XDM_UDP_PORT);
593 #ifdef BSD44SOCKETS
594 in_addr.sin_len = sizeof(in_addr);
595 #endif
596 RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr),
597 QUERY);
598 }
599 #if defined(IPv6) && defined(AF_INET6)
600 else {
601 char sport[8];
602 struct addrinfo *ai, *nai, hints;
603 bzero(&hints,sizeof(hints));
604 hints.ai_socktype = SOCK_DGRAM;
605 snprintf(sport, sizeof(sport), "%d", XDM_UDP_PORT);
606 if (getaddrinfo(name, sport, &hints, &ai) == 0) {
607 for (nai = ai ; nai != NULL ; nai = nai->ai_next) {
608 if ((nai->ai_family == AF_INET) ||
609 (nai->ai_family == AF_INET6)) {
610 if (((nai->ai_family == AF_INET) &&
611 IN_MULTICAST(((struct sockaddr_in *) nai->ai_addr)
612 ->sin_addr.s_addr))
613 || ((nai->ai_family == AF_INET6) &&
614 IN6_IS_ADDR_MULTICAST(
615 &((struct sockaddr_in6 *) nai->ai_addr)
616 ->sin6_addr)))
617 {
618 RegisterHostaddr(nai->ai_addr, nai->ai_addrlen,
619 BROADCAST_QUERY);
620 } else {
621 RegisterHostaddr(nai->ai_addr, nai->ai_addrlen,
622 QUERY);
623 }
624 }
625 }
626 freeaddrinfo(ai);
627 }
628 }
629 #else
630 /* Per RFC 1123, check first for IP address in dotted-decimal form */
631 else if ((in_addr.sin_addr.s_addr = inet_addr(name)) != -1)
632 in_addr.sin_family = AF_INET;
633 else
634 {
635 hostent = gethostbyname (name);
636 if (!hostent)
637 return;
638 if (hostent->h_addrtype != AF_INET || hostent->h_length != 4)
639 return;
640 in_addr.sin_family = hostent->h_addrtype;
641 memmove( &in_addr.sin_addr, hostent->h_addr, 4);
642 }
643 in_addr.sin_port = htons (XDM_UDP_PORT);
644 # ifdef BSD44SOCKETS
645 in_addr.sin_len = sizeof(in_addr);
646 # endif
647 RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr),
648 QUERY);
649 #endif /* IPv6 */
650 }
651 }
652
653 static ARRAYofARRAY8 AuthenticationNames;
654
655 static int
InitXDMCP(char ** argv)656 InitXDMCP (char **argv)
657 {
658 int soopts = 1;
659 XdmcpHeader header;
660 int i;
661
662 header.version = XDM_PROTOCOL_VERSION;
663 header.opcode = (CARD16) BROADCAST_QUERY;
664 header.length = 1;
665 for (i = 0; i < (int)AuthenticationNames.length; i++)
666 header.length += 2 + AuthenticationNames.data[i].length;
667 XdmcpWriteHeader (&broadcastBuffer, &header);
668 XdmcpWriteARRAYofARRAY8 (&broadcastBuffer, &AuthenticationNames);
669
670 header.version = XDM_PROTOCOL_VERSION;
671 header.opcode = (CARD16) QUERY;
672 header.length = 1;
673 for (i = 0; i < (int)AuthenticationNames.length; i++)
674 header.length += 2 + AuthenticationNames.data[i].length;
675 XdmcpWriteHeader (&directBuffer, &header);
676 XdmcpWriteARRAYofARRAY8 (&directBuffer, &AuthenticationNames);
677 if ((socketFD = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
678 return 0;
679 #if defined(IPv6) && defined(AF_INET6)
680 socket6FD = socket (AF_INET6, SOCK_DGRAM, 0);
681 #endif
682 #ifdef SO_BROADCAST
683 soopts = 1;
684 if (setsockopt (socketFD, SOL_SOCKET, SO_BROADCAST, (char *)&soopts, sizeof (soopts)) < 0)
685 perror ("setsockopt");
686 #endif
687
688 XtAddInput (socketFD, (XtPointer) XtInputReadMask, ReceivePacket,
689 (XtPointer) &socketFD);
690 #if defined(IPv6) && defined(AF_INET6)
691 if (socket6FD != -1)
692 XtAddInput (socket6FD, (XtPointer) XtInputReadMask, ReceivePacket,
693 (XtPointer) &socket6FD);
694 #endif
695 while (*argv)
696 {
697 RegisterHostname (*argv);
698 ++argv;
699 }
700 pingTry = 0;
701 PingHosts ((XtPointer)NULL, (XtIntervalId *)NULL);
702 return 1;
703 }
704
705 static void
Choose(HostName * h)706 Choose (HostName *h)
707 {
708 if (app_resources.xdmAddress)
709 {
710 struct sockaddr_in in_addr;
711 #if defined(IPv6) && defined(AF_INET6)
712 struct sockaddr_in6 in6_addr;
713 #endif
714 struct sockaddr *addr = NULL;
715 int family;
716 int len = 0;
717 int fd;
718 char buf[1024];
719 XdmcpBuffer buffer;
720 char *xdm;
721
722 xdm = (char *) app_resources.xdmAddress->data;
723 family = (xdm[0] << 8) + xdm[1];
724 switch (family) {
725 case AF_INET:
726 #ifdef BSD44SOCKETS
727 in_addr.sin_len = sizeof(in_addr);
728 #endif
729 in_addr.sin_family = family;
730 memmove( &in_addr.sin_port, xdm + 2, 2);
731 memmove( &in_addr.sin_addr, xdm + 4, 4);
732 addr = (struct sockaddr *) &in_addr;
733 len = sizeof (in_addr);
734 break;
735 #if defined(IPv6) && defined(AF_INET6)
736 case AF_INET6:
737 bzero(&in6_addr, sizeof(in6_addr));
738 # ifdef SIN6_LEN
739 in6_addr.sin6_len = sizeof(in6_addr);
740 # endif
741 in6_addr.sin6_family = family;
742 memmove( &in6_addr.sin6_port, xdm + 2, 2);
743 memmove( &in6_addr.sin6_addr, xdm + 4, 16);
744 addr = (struct sockaddr *) &in6_addr;
745 len = sizeof (in6_addr);
746 break;
747 #endif
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 /*
781 next_line returns the next line in a list
782 across the list end.
783 (0, 1, 2, 3, 0, 1, 2, 3 ....)
784 */
785
786 static int
next_line(unsigned int current,unsigned int size,int event)787 next_line(unsigned int current, unsigned int size, int event)
788 {
789 switch(event) {
790 case Button5:
791 return (current + 1) % size;
792 case Button4:
793 return (current + size - 1) % size;
794 case XK_Down:
795 return (current + 1) % size;
796 case XK_Up:
797 return (current + size - 1) % size;
798 }
799 return -1;
800 }
801
802 /*
803 Hostselect selects a given chooser line.
804 Returns 1 when host is willing and 0 if not
805 */
806
807 static int
Hostselect(int line)808 Hostselect (int line)
809 {
810 XawListReturnStruct *r;
811 HostName *h;
812
813 /* Assume the next host is willing */
814 XawListHighlight (list,line);
815 r = XawListShowCurrent (list);
816 /* copied from DoCheckWilling */
817 for (h = hostNamedb; h; h = h->next)
818 {
819 if (!strcmp (r->string, h->fullname))
820 {
821 if (!h->willing)
822 XawListUnhighlight (list);
823 else
824 {
825 /* Scroll viewport to make sure new selection is visible */
826 Arg size[2];
827 Dimension height, portheight;
828 Position y;
829 int lineheight, liney;
830
831 XtSetArg (size[0], XtNheight, &height);
832 XtSetArg (size[1], XtNy, &y);
833 XtGetValues (list, size, (Cardinal) 2);
834
835 XtSetArg (size[0], XtNheight, &portheight);
836 XtGetValues (viewport, size, (Cardinal) 1);
837
838 lineheight = height / NameTableSize;
839 liney = lineheight * line;
840
841 if ((y + liney) < 0) {
842 XawViewportSetCoordinates(viewport, 0, liney);
843 } else if ((y + liney + lineheight) > portheight) {
844 XawViewportSetCoordinates(viewport, 0,
845 (liney + lineheight) - portheight);
846 }
847
848 XtFree((char *) r);
849 return 1;
850 }
851 }
852 }
853 XtFree((char *) r);
854 return 0;
855 }
856
857 /*
858 Selectfirst selects the first willing host
859 in the chooser list (so you can select a host without
860 presence of mouse, but with pressing space or return,
861 or XK_Down / XK_Up
862 */
863
864 static void
Selectfirst(void)865 Selectfirst (void)
866 {
867 int line;
868
869 for (line = 0; line < NameTableSize; line++)
870 {
871 if (Hostselect(line))
872 return;
873 }
874 return;
875 }
876
877 /*
878 Storeold stores the selected line into global int oldentry
879 */
880
881 static void
Storeold(Widget w,XEvent * event,String * params,Cardinal * num_params)882 Storeold (Widget w, XEvent *event, String *params, Cardinal *num_params)
883 {
884 XawListReturnStruct *r = XawListShowCurrent(list);
885
886 oldline = r->list_index;
887 XtFree((char *) r);
888 }
889
890 /*
891 Setold restores the global int oldentry
892 when you try to select a host with your mouse
893 who is unwilling as follows:
894 <Btn1Down>: Store() Set() CheckWilling() Setold() \n\
895 */
896
897 static void
Setold(Widget w,XEvent * event,String * params,Cardinal * num_params)898 Setold (Widget w, XEvent *event, String *params, Cardinal *num_params)
899 {
900
901 if ( (XawListShowCurrent(list))->list_index == XAW_LIST_NONE && oldline != XAW_LIST_NONE)
902 XawListHighlight (list, oldline);
903 }
904
905 /*
906 HostCycle tries to select the next willing host across
907 the list end and will stop at the first found willing host
908 or after trying all entries.
909 */
910
911 static void
HostCycle(unsigned int line,unsigned int size,KeySym keysym)912 HostCycle(unsigned int line, unsigned int size, KeySym keysym)
913 {
914 unsigned int newline = line;
915 /* Do it only once around the chooser list, either direction */
916 while ( (newline = next_line(newline,size,keysym)) != line && newline != -1)
917 {
918 if (Hostselect(newline))
919 return;
920 }
921 /* No other willing host could be found, stay at the old one*/
922 XawListHighlight (list, line);
923 return;
924 }
925
926 /*
927 Switch_Key handles XK_Up and XK_Down
928 and highlights an appropriate line in the chooser list.
929 */
930
931 static void
Switch_Key(Widget w,XEvent * event,String * params,Cardinal * num_params)932 Switch_Key (Widget w, XEvent *event, String *params, Cardinal *num_params)
933 {
934 char strbuf[128];
935 KeySym keysym = 0;
936 static XComposeStatus compose_status = {NULL, 0};
937 XawListReturnStruct *r;
938
939 XLookupString (&event->xkey, strbuf, sizeof (strbuf),
940 &keysym, &compose_status);
941
942 if (keysym != XK_Up && keysym != XK_Down)
943 return;
944
945 r = XawListShowCurrent (list);
946
947 if (r->list_index == XAW_LIST_NONE)
948 Selectfirst();
949 else
950 HostCycle(r->list_index,NameTableSize,keysym);
951
952 XtFree((char *) r);
953 return;
954 }
955
956
957
958 /*
959 Switch_Btn handles ScrollWheel Forward (Button5) and Backward
960 (Button4) and highlights an appropriate line in the chooser list.
961 */
962
963 static void
Switch_Btn(Widget w,XEvent * event,String * params,Cardinal * num_params)964 Switch_Btn (Widget w, XEvent *event, String *params, Cardinal *num_params)
965 {
966 XawListReturnStruct *r;
967 r = XawListShowCurrent (list);
968
969 if (r->list_index == XAW_LIST_NONE)
970 Selectfirst();
971 else
972 HostCycle(r->list_index,NameTableSize,event->xbutton.button);
973
974 XtFree((char *) r);
975 return;
976 }
977
978
979 /* ARGSUSED */
980 static void
DoAccept(Widget w,XEvent * event,String * params,Cardinal * num_params)981 DoAccept (Widget w, XEvent *event, String *params, Cardinal *num_params)
982 {
983 XawListReturnStruct *r;
984 HostName *h;
985
986 r = XawListShowCurrent (list);
987 if (r->list_index == XAW_LIST_NONE)
988 #ifdef XKB
989 XkbStdBell(XtDisplay(toplevel),XtWindow(w),0,XkbBI_MinorError);
990 #else
991 XBell (XtDisplay (toplevel), 0);
992 #endif
993 else
994 {
995 for (h = hostNamedb; h; h = h->next)
996 if (!strcmp (r->string, h->fullname))
997 {
998 Choose (h);
999 }
1000 exit (OBEYSESS_DISPLAY);
1001 }
1002 XtFree((char *) r);
1003 }
1004
1005 /* ARGSUSED */
1006 static void
DoCheckWilling(Widget w,XEvent * event,String * params,Cardinal * num_params)1007 DoCheckWilling (Widget w, XEvent *event, String *params, Cardinal *num_params)
1008 {
1009 XawListReturnStruct *r;
1010 HostName *h;
1011
1012 r = XawListShowCurrent (list);
1013 if (r->list_index != XAW_LIST_NONE) {
1014 for (h = hostNamedb; h; h = h->next)
1015 if (!strcmp (r->string, h->fullname))
1016 if (!h->willing)
1017 XawListUnhighlight (list);
1018 }
1019 XtFree((char *) r);
1020 }
1021
1022 /* ARGSUSED */
1023 _X_NORETURN
1024 static void
DoCancel(Widget w,XEvent * event,String * params,Cardinal * num_params)1025 DoCancel (Widget w, XEvent *event, String *params, Cardinal *num_params)
1026 {
1027 exit (OBEYSESS_DISPLAY);
1028 }
1029
1030 /* ARGSUSED */
1031 static void
DoPing(Widget w,XEvent * event,String * params,Cardinal * num_params)1032 DoPing (Widget w, XEvent *event, String *params, Cardinal *num_params)
1033 {
1034 EmptyHostnames ();
1035 pingTry = 0;
1036 PingHosts ((XtPointer)NULL, (XtIntervalId *)NULL);
1037 }
1038
1039 static XtActionsRec app_actions[] = {
1040 { "Accept", DoAccept },
1041 { "Cancel", DoCancel },
1042 { "CheckWilling", DoCheckWilling },
1043 { "Ping", DoPing },
1044 { "KeySwitch", Switch_Key },
1045 { "BtnSwitch", Switch_Btn },
1046 { "Store", Storeold },
1047 { "Setold", Setold },
1048 };
1049
1050 int
main(int argc,char ** argv)1051 main (int argc, char **argv)
1052 {
1053 Arg position[3];
1054 Dimension width, height;
1055 Position x, y;
1056 #ifdef USE_XINERAMA
1057 XineramaScreenInfo *screens;
1058 int s_num;
1059 #endif
1060
1061
1062 toplevel = XtInitialize (argv[0], "Chooser", options, XtNumber(options), &argc, argv);
1063
1064 XtAddConverter(XtRString, XtRARRAY8, CvtStringToARRAY8, NULL, 0);
1065
1066 XtGetApplicationResources (toplevel, (XtPointer) &app_resources, resources,
1067 XtNumber (resources), NULL, (Cardinal) 0);
1068
1069 XtAddActions (app_actions, XtNumber (app_actions));
1070 paned = XtCreateManagedWidget ("paned", panedWidgetClass, toplevel, NULL, 0);
1071 label = XtCreateManagedWidget ("label", labelWidgetClass, paned, NULL, 0);
1072 viewport = XtCreateManagedWidget ("viewport", viewportWidgetClass, paned, NULL, 0);
1073 list = XtCreateManagedWidget ("list", listWidgetClass, viewport, NULL, 0);
1074 box = XtCreateManagedWidget ("box", boxWidgetClass, paned, NULL, 0);
1075 cancel = XtCreateManagedWidget ("cancel", commandWidgetClass, box, NULL, 0);
1076 acceptit = XtCreateManagedWidget ("accept", commandWidgetClass, box, NULL, 0);
1077 ping = XtCreateManagedWidget ("ping", commandWidgetClass, box, NULL, 0);
1078
1079 /*
1080 * center ourselves on the screen
1081 */
1082 XtSetMappedWhenManaged(toplevel, FALSE);
1083 XtRealizeWidget (toplevel);
1084
1085 XtSetArg (position[0], XtNwidth, &width);
1086 XtSetArg (position[1], XtNheight, &height);
1087 XtGetValues (toplevel, position, (Cardinal) 2);
1088 #ifdef USE_XINERAMA
1089 if (
1090 XineramaIsActive(XtDisplay(toplevel)) &&
1091 (screens = XineramaQueryScreens(XtDisplay(toplevel), &s_num)) != NULL
1092 )
1093 {
1094 x = (Position)(screens[0].x_org + (screens[0].width - width) / 2);
1095 y = (Position)(screens[0].y_org + (screens[0].height - height) / 3);
1096
1097 XFree(screens);
1098 }
1099 else
1100 #endif
1101 {
1102 x = (Position)(WidthOfScreen (XtScreen (toplevel)) - width) / 2;
1103 y = (Position)(HeightOfScreen (XtScreen (toplevel)) - height) / 3;
1104 }
1105 XtSetArg (position[0], XtNx, x);
1106 XtSetArg (position[1], XtNy, y);
1107 XtSetValues (toplevel, position, (Cardinal) 2);
1108
1109 /*
1110 * Run
1111 */
1112 XtMapWidget(toplevel);
1113 InitXDMCP (argv + 1);
1114 XtMainLoop ();
1115 exit(0);
1116 /*NOTREACHED*/
1117 }
1118
1119 /* Converts the hex string s of length len into the byte array d.
1120 Returns 0 if s was a legal hex string, 1 otherwise.
1121 */
1122 static int
FromHex(char * s,char * d,int len)1123 FromHex (char *s, char *d, int len)
1124 {
1125 int t;
1126 int ret = len&1; /* odd-length hex strings are illegal */
1127 while (len >= 2)
1128 {
1129 #define HexChar(c) ('0' <= (c) && (c) <= '9' ? (c) - '0' : (c) - 'a' + 10)
1130
1131 if (!ishexdigit(*s))
1132 ret = 1;
1133 t = HexChar (*s) << 4;
1134 s++;
1135 if (!ishexdigit(*s))
1136 ret = 1;
1137 t += HexChar (*s);
1138 s++;
1139 *d++ = t;
1140 len -= 2;
1141 }
1142 return ret;
1143 }
1144
1145 /*ARGSUSED*/
1146 static void
CvtStringToARRAY8(XrmValuePtr args,Cardinal * num_args,XrmValuePtr fromVal,XrmValuePtr toVal)1147 CvtStringToARRAY8 (XrmValuePtr args, Cardinal *num_args, XrmValuePtr fromVal, XrmValuePtr toVal)
1148 {
1149 static ARRAY8Ptr dest;
1150 char *s;
1151 int len;
1152
1153 dest = (ARRAY8Ptr) XtMalloc (sizeof (ARRAY8));
1154 len = fromVal->size;
1155 s = (char *) fromVal->addr;
1156 if (!XdmcpAllocARRAY8 (dest, len >> 1))
1157 XtStringConversionWarning ((char *) fromVal->addr, XtRARRAY8);
1158 else
1159 {
1160 FromHex (s, (char *) dest->data, len);
1161 }
1162 toVal->addr = (caddr_t) &dest;
1163 toVal->size = sizeof (ARRAY8Ptr);
1164 }
1165