chooser.c revision b7d26471
1/* 2 * 3Copyright 1990, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in 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 126static int FromHex (char *s, char *d, int len); 127static int oldline; 128 129static Widget toplevel, label, viewport, paned, list, box, cancel, acceptit, ping; 130 131static void CvtStringToARRAY8( 132 XrmValuePtr args, 133 Cardinal *num_args, 134 XrmValuePtr fromVal, 135 XrmValuePtr toVal); 136 137static 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 147static 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 157static XrmOptionDescRec options[] = { 158 { "-xdmaddress", "*xdmAddress", XrmoptionSepArg, NULL }, 159 { "-clientaddress", "*clientAddress", XrmoptionSepArg, NULL }, 160 { "-connectionType","*connectionType", XrmoptionSepArg, NULL }, 161}; 162 163typedef struct _hostAddr { 164 struct _hostAddr *next; 165 struct sockaddr *addr; 166 int addrlen; 167 xdmOpCode type; 168} HostAddr; 169 170static HostAddr *hostAddrdb; 171 172typedef 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 181static HostName *hostNamedb; 182 183static int socketFD; 184#if defined(IPv6) && defined(AF_INET6) 185static int socket6FD; 186#endif 187 188static int pingTry; 189 190#define PING_INTERVAL 2000 191#define TRIES 3 192 193static XdmcpBuffer directBuffer, broadcastBuffer; 194static 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 200static int 201ifioctl (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 */ 230static void 231PingHosts (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 255char **NameTable; 256int NameTableSize; 257 258static int 259HostnameCompare (const void *a, const void *b) 260{ 261 return strcmp (*(char **)a, *(char **)b); 262} 263 264static void 265RebuildTable (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 286static int 287AddHostname (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 399static void 400DisposeHostname (HostName *host) 401{ 402 XdmcpDisposeARRAY8 (&host->hostname); 403 XdmcpDisposeARRAY8 (&host->hostaddr); 404 XdmcpDisposeARRAY8 (&host->status); 405 free (host->fullname); 406 free (host); 407} 408 409static void 410EmptyHostnames (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 */ 425static void 426ReceivePacket (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 487static void 488RegisterHostaddr (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 526static void 527RegisterHostname (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 653static ARRAYofARRAY8 AuthenticationNames; 654 655static int 656InitXDMCP (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 705static void 706Choose (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 786static int 787next_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 807static int 808Hostselect (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 864static void 865Selectfirst (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 881static void 882Storeold (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 897static void 898Setold (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 911static void 912HostCycle(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 931static void 932Switch_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 963static void 964Switch_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 */ 980static void 981DoAccept (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 */ 1006static void 1007DoCheckWilling (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 1024static void 1025DoCancel (Widget w, XEvent *event, String *params, Cardinal *num_params) 1026{ 1027 exit (OBEYSESS_DISPLAY); 1028} 1029 1030/* ARGSUSED */ 1031static void 1032DoPing (Widget w, XEvent *event, String *params, Cardinal *num_params) 1033{ 1034 EmptyHostnames (); 1035 pingTry = 0; 1036 PingHosts ((XtPointer)NULL, (XtIntervalId *)NULL); 1037} 1038 1039static 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 1050int 1051main (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 */ 1122static int 1123FromHex (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*/ 1146static void 1147CvtStringToARRAY8 (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