chooser.c revision f9f7a7f2
1de3c0529Smrg/* 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 = calloc (1, 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 memcpy(hostname->data, host, hostname->length); 351 } 352 } 353 } 354 } 355 if (!XdmcpAllocARRAY8 (&new->hostaddr, hostAddr.length)) 356 { 357 free (new); 358 return 0; 359 } 360 memcpy(new->hostaddr.data, hostAddr.data, hostAddr.length); 361 new->connectionType = connectionType; 362 new->hostname = *hostname; 363 364 *names = new; 365 new->next = NULL; 366 NameTableSize++; 367 } 368 else 369 { 370 new = *names; 371 free (new->fullname); 372 XdmcpDisposeARRAY8 (&new->status); 373 XdmcpDisposeARRAY8 (hostname); 374 } 375 new->willing = willing; 376 new->status = *status; 377 378 hostname = &new->hostname; 379 fulllen = hostname->length; 380 if (fulllen < 30) 381 fulllen = 30; 382 fulllen += status->length + 10; 383 new->fullname = malloc (fulllen); 384 if (!new->fullname) 385 { 386 new->fullname = "Unknown"; 387 } 388 else 389 { 390 snprintf(new->fullname, fulllen, "%-30.*s %*.*s", 391 hostname->length, hostname->data, 392 status->length, status->length, status->data); 393 } 394 RebuildTable (NameTableSize); 395 return 1; 396} 397 398static void 399DisposeHostname (HostName *host) 400{ 401 XdmcpDisposeARRAY8 (&host->hostname); 402 XdmcpDisposeARRAY8 (&host->hostaddr); 403 XdmcpDisposeARRAY8 (&host->status); 404 free (host->fullname); 405 free (host); 406} 407 408static void 409EmptyHostnames (void) 410{ 411 HostName *hosts, *next; 412 413 for (hosts = hostNamedb; hosts; hosts = next) 414 { 415 next = hosts->next; 416 DisposeHostname (hosts); 417 } 418 NameTableSize = 0; 419 hostNamedb = NULL; 420 RebuildTable (NameTableSize); 421} 422 423/* ARGSUSED */ 424static void 425ReceivePacket (XtPointer closure, int *source, XtInputId *id) 426{ 427 XdmcpHeader header; 428 ARRAY8 authenticationName = {0, NULL}; 429 ARRAY8 hostname = {0, NULL}; 430 ARRAY8 status = {0, NULL}; 431 int saveHostname = 0; 432#if defined(IPv6) && defined(AF_INET6) 433 struct sockaddr_storage addr; 434#else 435 struct sockaddr addr; 436#endif 437 int addrlen; 438 int sfd = * (int *) closure; 439 440 addrlen = sizeof (addr); 441 if (!XdmcpFill (sfd, &buffer, (XdmcpNetaddr) &addr, &addrlen)) 442 return; 443 if (!XdmcpReadHeader (&buffer, &header)) 444 return; 445 if (header.version != XDM_PROTOCOL_VERSION) 446 return; 447 switch (header.opcode) { 448 case WILLING: 449 if (XdmcpReadARRAY8 (&buffer, &authenticationName) && 450 XdmcpReadARRAY8 (&buffer, &hostname) && 451 XdmcpReadARRAY8 (&buffer, &status)) 452 { 453 if (header.length == 6 + authenticationName.length + 454 hostname.length + status.length) 455 { 456 if (AddHostname (&hostname, &status, (struct sockaddr *) &addr, 457 header.opcode == (int) WILLING)) 458 saveHostname = 1; 459 } 460 } 461 XdmcpDisposeARRAY8 (&authenticationName); 462 break; 463 case UNWILLING: 464 if (XdmcpReadARRAY8 (&buffer, &hostname) && 465 XdmcpReadARRAY8 (&buffer, &status)) 466 { 467 if (header.length == 4 + hostname.length + status.length) 468 { 469 if (AddHostname (&hostname, &status, (struct sockaddr *) &addr, 470 header.opcode == (int) WILLING)) 471 saveHostname = 1; 472 473 } 474 } 475 break; 476 default: 477 break; 478 } 479 if (!saveHostname) 480 { 481 XdmcpDisposeARRAY8 (&hostname); 482 XdmcpDisposeARRAY8 (&status); 483 } 484} 485 486static void 487RegisterHostaddr (struct sockaddr *addr, int len, xdmOpCode type) 488{ 489 HostAddr *host, **prev; 490 491 host = malloc (sizeof (HostAddr)); 492 if (!host) 493 return; 494 host->addr = malloc (len); 495 if (!host->addr) 496 { 497 free (host); 498 return; 499 } 500 memcpy(host->addr, addr, len); 501 host->addrlen = len; 502 host->type = type; 503 for (prev = &hostAddrdb; *prev; prev = &(*prev)->next) 504 ; 505 *prev = host; 506 host->next = NULL; 507} 508 509/* 510 * Register the address for this host. 511 * Called with each of the names on the command line. 512 * The special name "BROADCAST" looks up all the broadcast 513 * addresses on the local host. 514 */ 515 516/* Handle variable length ifreq in BNR2 and later */ 517#ifdef VARIABLE_IFREQ 518# define ifr_size(p) (sizeof (struct ifreq) + \ 519 (p->ifr_addr.sa_len > sizeof (p->ifr_addr) ? \ 520 p->ifr_addr.sa_len - sizeof (p->ifr_addr) : 0)) 521#else 522# define ifr_size(p) (sizeof (struct ifreq)) 523#endif 524 525static void 526RegisterHostname (char *name) 527{ 528#if !defined(IPv6) || !defined(AF_INET6) 529 struct hostent *hostent; 530#endif 531 struct sockaddr_in in_addr; 532 struct ifconf ifc; 533 register struct ifreq *ifr; 534 struct sockaddr broad_addr; 535 char buf[2048], *cp, *cplim; 536 537 if (!strcmp (name, BROADCAST_HOSTNAME)) 538 { 539 ifc.ifc_len = sizeof (buf); 540 ifc.ifc_buf = buf; 541 if (ifioctl (socketFD, (int) SIOCGIFCONF, (char *) &ifc) < 0) 542 return; 543 544 cplim = (char *) ifc.ifc_req + ifc.ifc_len; 545 546 for (cp = (char *) ifc.ifc_req; cp < cplim; cp += ifr_size (ifr)) 547 { 548 ifr = (struct ifreq *) cp; 549 if (ifr->ifr_addr.sa_family != AF_INET) 550 continue; 551 552 broad_addr = ifr->ifr_addr; 553 ((struct sockaddr_in *) &broad_addr)->sin_addr.s_addr = 554 htonl (INADDR_BROADCAST); 555#ifdef SIOCGIFBRDADDR 556 { 557 struct ifreq broad_req; 558 559 broad_req = *ifr; 560 if (ifioctl (socketFD, SIOCGIFFLAGS, (char *) &broad_req) != -1 && 561 (broad_req.ifr_flags & IFF_BROADCAST) && 562 (broad_req.ifr_flags & IFF_UP) 563 ) 564 { 565 broad_req = *ifr; 566 if (ifioctl (socketFD, SIOCGIFBRDADDR, &broad_req) != -1) 567 broad_addr = broad_req.ifr_addr; 568 else 569 continue; 570 } 571 else 572 continue; 573 } 574#endif 575 in_addr = *((struct sockaddr_in *) &broad_addr); 576 in_addr.sin_port = htons (XDM_UDP_PORT); 577#ifdef BSD44SOCKETS 578 in_addr.sin_len = sizeof(in_addr); 579#endif 580 RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr), 581 BROADCAST_QUERY); 582 } 583 } 584 else 585 { 586 /* address as hex string, e.g., "12180022" (deprecated) */ 587 if (strlen(name) == 8 && 588 FromHex(name, (char *)&in_addr.sin_addr, strlen(name)) == 0) 589 { 590 in_addr.sin_family = AF_INET; 591 in_addr.sin_port = htons (XDM_UDP_PORT); 592#ifdef BSD44SOCKETS 593 in_addr.sin_len = sizeof(in_addr); 594#endif 595 RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr), 596 QUERY); 597 } 598#if defined(IPv6) && defined(AF_INET6) 599 else { 600 char sport[8]; 601 struct addrinfo *ai, *nai, hints; 602 bzero(&hints,sizeof(hints)); 603 hints.ai_socktype = SOCK_DGRAM; 604 snprintf(sport, sizeof(sport), "%d", XDM_UDP_PORT); 605 if (getaddrinfo(name, sport, &hints, &ai) == 0) { 606 for (nai = ai ; nai != NULL ; nai = nai->ai_next) { 607 if ((nai->ai_family == AF_INET) || 608 (nai->ai_family == AF_INET6)) { 609 if (((nai->ai_family == AF_INET) && 610 IN_MULTICAST(((struct sockaddr_in *) nai->ai_addr) 611 ->sin_addr.s_addr)) 612 || ((nai->ai_family == AF_INET6) && 613 IN6_IS_ADDR_MULTICAST( 614 &((struct sockaddr_in6 *) nai->ai_addr) 615 ->sin6_addr))) 616 { 617 RegisterHostaddr(nai->ai_addr, nai->ai_addrlen, 618 BROADCAST_QUERY); 619 } else { 620 RegisterHostaddr(nai->ai_addr, nai->ai_addrlen, 621 QUERY); 622 } 623 } 624 } 625 freeaddrinfo(ai); 626 } 627 } 628#else 629 /* Per RFC 1123, check first for IP address in dotted-decimal form */ 630 else if ((in_addr.sin_addr.s_addr = inet_addr(name)) != -1) 631 in_addr.sin_family = AF_INET; 632 else 633 { 634 hostent = gethostbyname (name); 635 if (!hostent) 636 return; 637 if (hostent->h_addrtype != AF_INET || hostent->h_length != 4) 638 return; 639 in_addr.sin_family = hostent->h_addrtype; 640 memcpy(&in_addr.sin_addr, hostent->h_addr, 4); 641 } 642 in_addr.sin_port = htons (XDM_UDP_PORT); 643# ifdef BSD44SOCKETS 644 in_addr.sin_len = sizeof(in_addr); 645# endif 646 RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr), 647 QUERY); 648#endif /* IPv6 */ 649 } 650} 651 652static ARRAYofARRAY8 AuthenticationNames; 653 654static int 655InitXDMCP (char **argv) 656{ 657 int soopts = 1; 658 XdmcpHeader header; 659 int i; 660 661 header.version = XDM_PROTOCOL_VERSION; 662 header.opcode = (CARD16) BROADCAST_QUERY; 663 header.length = 1; 664 for (i = 0; i < (int)AuthenticationNames.length; i++) 665 header.length += 2 + AuthenticationNames.data[i].length; 666 XdmcpWriteHeader (&broadcastBuffer, &header); 667 XdmcpWriteARRAYofARRAY8 (&broadcastBuffer, &AuthenticationNames); 668 669 header.version = XDM_PROTOCOL_VERSION; 670 header.opcode = (CARD16) QUERY; 671 header.length = 1; 672 for (i = 0; i < (int)AuthenticationNames.length; i++) 673 header.length += 2 + AuthenticationNames.data[i].length; 674 XdmcpWriteHeader (&directBuffer, &header); 675 XdmcpWriteARRAYofARRAY8 (&directBuffer, &AuthenticationNames); 676 if ((socketFD = socket (AF_INET, SOCK_DGRAM, 0)) < 0) 677 return 0; 678#if defined(IPv6) && defined(AF_INET6) 679 socket6FD = socket (AF_INET6, SOCK_DGRAM, 0); 680#endif 681#ifdef SO_BROADCAST 682 soopts = 1; 683 if (setsockopt (socketFD, SOL_SOCKET, SO_BROADCAST, (char *)&soopts, sizeof (soopts)) < 0) 684 perror ("setsockopt"); 685#endif 686 687 XtAddInput (socketFD, (XtPointer) XtInputReadMask, ReceivePacket, 688 (XtPointer) &socketFD); 689#if defined(IPv6) && defined(AF_INET6) 690 if (socket6FD != -1) 691 XtAddInput (socket6FD, (XtPointer) XtInputReadMask, ReceivePacket, 692 (XtPointer) &socket6FD); 693#endif 694 while (*argv) 695 { 696 RegisterHostname (*argv); 697 ++argv; 698 } 699 pingTry = 0; 700 PingHosts ((XtPointer)NULL, (XtIntervalId *)NULL); 701 return 1; 702} 703 704static void 705Choose (HostName *h) 706{ 707 if (app_resources.xdmAddress) 708 { 709 struct sockaddr_in in_addr; 710#if defined(IPv6) && defined(AF_INET6) 711 struct sockaddr_in6 in6_addr; 712#endif 713 struct sockaddr *addr = NULL; 714 int family; 715 int len = 0; 716 int fd; 717 char buf[1024]; 718 XdmcpBuffer buffer; 719 char *xdm; 720 721 xdm = (char *) app_resources.xdmAddress->data; 722 family = (xdm[0] << 8) + xdm[1]; 723 switch (family) { 724 case AF_INET: 725#ifdef BSD44SOCKETS 726 in_addr.sin_len = sizeof(in_addr); 727#endif 728 in_addr.sin_family = family; 729 memcpy(&in_addr.sin_port, xdm + 2, 2); 730 memcpy(&in_addr.sin_addr, xdm + 4, 4); 731 addr = (struct sockaddr *) &in_addr; 732 len = sizeof (in_addr); 733 break; 734#if defined(IPv6) && defined(AF_INET6) 735 case AF_INET6: 736 bzero(&in6_addr, sizeof(in6_addr)); 737# ifdef SIN6_LEN 738 in6_addr.sin6_len = sizeof(in6_addr); 739# endif 740 in6_addr.sin6_family = family; 741 memcpy(&in6_addr.sin6_port, xdm + 2, 2); 742 memcpy(&in6_addr.sin6_addr, xdm + 4, 16); 743 addr = (struct sockaddr *) &in6_addr; 744 len = sizeof (in6_addr); 745 break; 746#endif 747 } 748 if ((fd = socket (family, SOCK_STREAM, 0)) == -1) 749 { 750 fprintf (stderr, "Cannot create response socket\n"); 751 exit (REMANAGE_DISPLAY); 752 } 753 if (connect (fd, addr, len) == -1) 754 { 755 fprintf (stderr, "Cannot connect to xdm\n"); 756 exit (REMANAGE_DISPLAY); 757 } 758 buffer.data = (BYTE *) buf; 759 buffer.size = sizeof (buf); 760 buffer.pointer = 0; 761 buffer.count = 0; 762 XdmcpWriteARRAY8 (&buffer, app_resources.clientAddress); 763 XdmcpWriteCARD16 (&buffer, (CARD16) app_resources.connectionType); 764 XdmcpWriteARRAY8 (&buffer, &h->hostaddr); 765 write (fd, (char *)buffer.data, buffer.pointer); 766 close (fd); 767 } 768 else 769 { 770 int i; 771 772 printf ("%u\n", h->connectionType); 773 for (i = 0; i < (int)h->hostaddr.length; i++) 774 printf ("%u%s", h->hostaddr.data[i], 775 i == h->hostaddr.length - 1 ? "\n" : " "); 776 } 777} 778 779/* 780 next_line returns the next line in a list 781 across the list end. 782 (0, 1, 2, 3, 0, 1, 2, 3 ....) 783*/ 784 785static int 786next_line(unsigned int current, unsigned int size, int event) 787{ 788 switch(event) { 789 case Button5: 790 return (current + 1) % size; 791 case Button4: 792 return (current + size - 1) % size; 793 case XK_Down: 794 return (current + 1) % size; 795 case XK_Up: 796 return (current + size - 1) % size; 797 } 798 return -1; 799} 800 801/* 802 Hostselect selects a given chooser line. 803 Returns 1 when host is willing and 0 if not 804*/ 805 806static int 807Hostselect (int line) 808{ 809 XawListReturnStruct *r; 810 HostName *h; 811 812 /* Assume the next host is willing */ 813 XawListHighlight (list,line); 814 r = XawListShowCurrent (list); 815 /* copied from DoCheckWilling */ 816 for (h = hostNamedb; h; h = h->next) 817 { 818 if (!strcmp (r->string, h->fullname)) 819 { 820 if (!h->willing) 821 XawListUnhighlight (list); 822 else 823 { 824 /* Scroll viewport to make sure new selection is visible */ 825 Arg size[2]; 826 Dimension height, portheight; 827 Position y; 828 int lineheight, liney; 829 830 XtSetArg (size[0], XtNheight, &height); 831 XtSetArg (size[1], XtNy, &y); 832 XtGetValues (list, size, (Cardinal) 2); 833 834 XtSetArg (size[0], XtNheight, &portheight); 835 XtGetValues (viewport, size, (Cardinal) 1); 836 837 lineheight = height / NameTableSize; 838 liney = lineheight * line; 839 840 if ((y + liney) < 0) { 841 XawViewportSetCoordinates(viewport, 0, liney); 842 } else if ((y + liney + lineheight) > portheight) { 843 XawViewportSetCoordinates(viewport, 0, 844 (liney + lineheight) - portheight); 845 } 846 847 XtFree((char *) r); 848 return 1; 849 } 850 } 851 } 852 XtFree((char *) r); 853 return 0; 854} 855 856/* 857 Selectfirst selects the first willing host 858 in the chooser list (so you can select a host without 859 presence of mouse, but with pressing space or return, 860 or XK_Down / XK_Up 861*/ 862 863static void 864Selectfirst (void) 865{ 866 int line; 867 868 for (line = 0; line < NameTableSize; line++) 869 { 870 if (Hostselect(line)) 871 return; 872 } 873 return; 874} 875 876/* 877 Storeold stores the selected line into global int oldentry 878*/ 879 880static void 881Storeold (Widget w, XEvent *event, String *params, Cardinal *num_params) 882{ 883 XawListReturnStruct *r = XawListShowCurrent(list); 884 885 oldline = r->list_index; 886 XtFree((char *) r); 887} 888 889/* 890 Setold restores the global int oldentry 891 when you try to select a host with your mouse 892 who is unwilling as follows: 893 <Btn1Down>: Store() Set() CheckWilling() Setold() \n\ 894*/ 895 896static void 897Setold (Widget w, XEvent *event, String *params, Cardinal *num_params) 898{ 899 900 if ( (XawListShowCurrent(list))->list_index == XAW_LIST_NONE && oldline != XAW_LIST_NONE) 901 XawListHighlight (list, oldline); 902} 903 904/* 905 HostCycle tries to select the next willing host across 906 the list end and will stop at the first found willing host 907 or after trying all entries. 908*/ 909 910static void 911HostCycle(unsigned int line, unsigned int size, KeySym keysym) 912{ 913 unsigned int newline = line; 914 /* Do it only once around the chooser list, either direction */ 915 while ( (newline = next_line(newline,size,keysym)) != line && newline != -1) 916 { 917 if (Hostselect(newline)) 918 return; 919 } 920 /* No other willing host could be found, stay at the old one*/ 921 XawListHighlight (list, line); 922 return; 923} 924 925/* 926 Switch_Key handles XK_Up and XK_Down 927 and highlights an appropriate line in the chooser list. 928*/ 929 930static void 931Switch_Key (Widget w, XEvent *event, String *params, Cardinal *num_params) 932{ 933 char strbuf[128]; 934 KeySym keysym = 0; 935 static XComposeStatus compose_status = {NULL, 0}; 936 XawListReturnStruct *r; 937 938 XLookupString (&event->xkey, strbuf, sizeof (strbuf), 939 &keysym, &compose_status); 940 941 if (keysym != XK_Up && keysym != XK_Down) 942 return; 943 944 r = XawListShowCurrent (list); 945 946 if (r->list_index == XAW_LIST_NONE) 947 Selectfirst(); 948 else 949 HostCycle(r->list_index,NameTableSize,keysym); 950 951 XtFree((char *) r); 952 return; 953} 954 955 956 957/* 958 Switch_Btn handles ScrollWheel Forward (Button5) and Backward 959 (Button4) and highlights an appropriate line in the chooser list. 960*/ 961 962static void 963Switch_Btn (Widget w, XEvent *event, String *params, Cardinal *num_params) 964{ 965 XawListReturnStruct *r; 966 r = XawListShowCurrent (list); 967 968 if (r->list_index == XAW_LIST_NONE) 969 Selectfirst(); 970 else 971 HostCycle(r->list_index,NameTableSize,event->xbutton.button); 972 973 XtFree((char *) r); 974 return; 975} 976 977 978/* ARGSUSED */ 979static void 980DoAccept (Widget w, XEvent *event, String *params, Cardinal *num_params) 981{ 982 XawListReturnStruct *r; 983 HostName *h; 984 985 r = XawListShowCurrent (list); 986 if (r->list_index == XAW_LIST_NONE) 987#ifdef XKB 988 XkbStdBell(XtDisplay(toplevel),XtWindow(w),0,XkbBI_MinorError); 989#else 990 XBell (XtDisplay (toplevel), 0); 991#endif 992 else 993 { 994 for (h = hostNamedb; h; h = h->next) 995 if (!strcmp (r->string, h->fullname)) 996 { 997 Choose (h); 998 } 999 exit (OBEYSESS_DISPLAY); 1000 } 1001 XtFree((char *) r); 1002} 1003 1004/* ARGSUSED */ 1005static void 1006DoCheckWilling (Widget w, XEvent *event, String *params, Cardinal *num_params) 1007{ 1008 XawListReturnStruct *r; 1009 HostName *h; 1010 1011 r = XawListShowCurrent (list); 1012 if (r->list_index != XAW_LIST_NONE) { 1013 for (h = hostNamedb; h; h = h->next) 1014 if (!strcmp (r->string, h->fullname)) 1015 if (!h->willing) 1016 XawListUnhighlight (list); 1017 } 1018 XtFree((char *) r); 1019} 1020 1021/* ARGSUSED */ 1022_X_NORETURN 1023static void 1024DoCancel (Widget w, XEvent *event, String *params, Cardinal *num_params) 1025{ 1026 exit (OBEYSESS_DISPLAY); 1027} 1028 1029/* ARGSUSED */ 1030static void 1031DoPing (Widget w, XEvent *event, String *params, Cardinal *num_params) 1032{ 1033 EmptyHostnames (); 1034 pingTry = 0; 1035 PingHosts ((XtPointer)NULL, (XtIntervalId *)NULL); 1036} 1037 1038static XtActionsRec app_actions[] = { 1039 { "Accept", DoAccept }, 1040 { "Cancel", DoCancel }, 1041 { "CheckWilling", DoCheckWilling }, 1042 { "Ping", DoPing }, 1043 { "KeySwitch", Switch_Key }, 1044 { "BtnSwitch", Switch_Btn }, 1045 { "Store", Storeold }, 1046 { "Setold", Setold }, 1047}; 1048 1049int 1050main (int argc, char **argv) 1051{ 1052 Arg position[3]; 1053 Dimension width, height; 1054 Position x, y; 1055#ifdef USE_XINERAMA 1056 XineramaScreenInfo *screens; 1057 int s_num; 1058#endif 1059 1060 1061 toplevel = XtInitialize (argv[0], "Chooser", options, XtNumber(options), &argc, argv); 1062 1063 XtAddConverter(XtRString, XtRARRAY8, CvtStringToARRAY8, NULL, 0); 1064 1065 XtGetApplicationResources (toplevel, (XtPointer) &app_resources, resources, 1066 XtNumber (resources), NULL, (Cardinal) 0); 1067 1068 XtAddActions (app_actions, XtNumber (app_actions)); 1069 paned = XtCreateManagedWidget ("paned", panedWidgetClass, toplevel, NULL, 0); 1070 label = XtCreateManagedWidget ("label", labelWidgetClass, paned, NULL, 0); 1071 viewport = XtCreateManagedWidget ("viewport", viewportWidgetClass, paned, NULL, 0); 1072 list = XtCreateManagedWidget ("list", listWidgetClass, viewport, NULL, 0); 1073 box = XtCreateManagedWidget ("box", boxWidgetClass, paned, NULL, 0); 1074 cancel = XtCreateManagedWidget ("cancel", commandWidgetClass, box, NULL, 0); 1075 acceptit = XtCreateManagedWidget ("accept", commandWidgetClass, box, NULL, 0); 1076 ping = XtCreateManagedWidget ("ping", commandWidgetClass, box, NULL, 0); 1077 1078 /* 1079 * center ourselves on the screen 1080 */ 1081 XtSetMappedWhenManaged(toplevel, FALSE); 1082 XtRealizeWidget (toplevel); 1083 1084 XtSetArg (position[0], XtNwidth, &width); 1085 XtSetArg (position[1], XtNheight, &height); 1086 XtGetValues (toplevel, position, (Cardinal) 2); 1087#ifdef USE_XINERAMA 1088 if ( 1089 XineramaIsActive(XtDisplay(toplevel)) && 1090 (screens = XineramaQueryScreens(XtDisplay(toplevel), &s_num)) != NULL 1091 ) 1092 { 1093 x = (Position)(screens[0].x_org + (screens[0].width - width) / 2); 1094 y = (Position)(screens[0].y_org + (screens[0].height - height) / 3); 1095 1096 XFree(screens); 1097 } 1098 else 1099#endif 1100 { 1101 x = (Position)(WidthOfScreen (XtScreen (toplevel)) - width) / 2; 1102 y = (Position)(HeightOfScreen (XtScreen (toplevel)) - height) / 3; 1103 } 1104 XtSetArg (position[0], XtNx, x); 1105 XtSetArg (position[1], XtNy, y); 1106 XtSetValues (toplevel, position, (Cardinal) 2); 1107 1108 /* 1109 * Run 1110 */ 1111 XtMapWidget(toplevel); 1112 InitXDMCP (argv + 1); 1113 XtMainLoop (); 1114 exit(0); 1115 /*NOTREACHED*/ 1116} 1117 1118/* Converts the hex string s of length len into the byte array d. 1119 Returns 0 if s was a legal hex string, 1 otherwise. 1120 */ 1121static int 1122FromHex (char *s, char *d, int len) 1123{ 1124 int t; 1125 int ret = len&1; /* odd-length hex strings are illegal */ 1126 while (len >= 2) 1127 { 1128#define HexChar(c) ('0' <= (c) && (c) <= '9' ? (c) - '0' : (c) - 'a' + 10) 1129 1130 if (!ishexdigit(*s)) 1131 ret = 1; 1132 t = HexChar (*s) << 4; 1133 s++; 1134 if (!ishexdigit(*s)) 1135 ret = 1; 1136 t += HexChar (*s); 1137 s++; 1138 *d++ = t; 1139 len -= 2; 1140 } 1141 return ret; 1142} 1143 1144/*ARGSUSED*/ 1145static void 1146CvtStringToARRAY8 (XrmValuePtr args, Cardinal *num_args, XrmValuePtr fromVal, XrmValuePtr toVal) 1147{ 1148 static ARRAY8Ptr dest; 1149 char *s; 1150 int len; 1151 1152 dest = (ARRAY8Ptr) XtMalloc (sizeof (ARRAY8)); 1153 len = fromVal->size; 1154 s = (char *) fromVal->addr; 1155 if (!XdmcpAllocARRAY8 (dest, len >> 1)) 1156 XtStringConversionWarning ((char *) fromVal->addr, XtRARRAY8); 1157 else 1158 { 1159 FromHex (s, (char *) dest->data, len); 1160 } 1161 toVal->addr = (caddr_t) &dest; 1162 toVal->size = sizeof (ARRAY8Ptr); 1163} 1164