chooser.c revision 629baa8c
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# ifdef ISC 84# include <sys/sioctl.h> 85# include <sys/stropts.h> 86# endif 87#endif 88 89#include "dm_socket.h" 90 91#include <arpa/inet.h> 92 93#include <sys/ioctl.h> 94#ifdef STREAMSCONN 95# ifdef WINTCP /* NCR with Wollongong TCP */ 96# include <netinet/ip.h> 97# endif 98# include <stropts.h> 99# include <tiuser.h> 100# include <netconfig.h> 101# include <netdir.h> 102#endif 103 104#ifdef HAVE_SYS_PARAM_H 105#include <sys/param.h> 106# ifdef BSD 107# if (BSD >= 199103) 108# define VARIABLE_IFREQ 109# endif 110# endif 111#endif 112 113#ifdef XKB 114# include <X11/extensions/XKBbells.h> 115#endif 116 117#define BROADCAST_HOSTNAME "BROADCAST" 118 119#ifndef ishexdigit 120# define ishexdigit(c) (isdigit(c) || ('a' <= (c) && (c) <= 'f')) 121#endif 122 123#ifdef hpux 124# include <sys/utsname.h> 125# ifdef HAS_IFREQ 126# include <net/if.h> 127# endif 128#else 129# ifdef __convex__ 130# include <sync/queue.h> 131# include <sync/sema.h> 132# endif 133# include <net/if.h> 134#endif /* hpux */ 135 136#include <netdb.h> 137#include <X11/keysym.h> 138 139static int FromHex (char *s, char *d, int len); 140static int oldline; 141 142static Widget toplevel, label, viewport, paned, list, box, cancel, acceptit, ping; 143 144static void CvtStringToARRAY8( 145 XrmValuePtr args, 146 Cardinal *num_args, 147 XrmValuePtr fromVal, 148 XrmValuePtr toVal); 149 150static struct _app_resources { 151 ARRAY8Ptr xdmAddress; 152 ARRAY8Ptr clientAddress; 153 int connectionType; 154} app_resources; 155 156#define offset(field) XtOffsetOf(struct _app_resources, field) 157 158#define XtRARRAY8 "ARRAY8" 159 160static XtResource resources[] = { 161 {"xdmAddress", "XdmAddress", XtRARRAY8, sizeof (ARRAY8Ptr), 162 offset (xdmAddress), XtRString, NULL }, 163 {"clientAddress", "ClientAddress", XtRARRAY8, sizeof (ARRAY8Ptr), 164 offset (clientAddress), XtRString, NULL }, 165 {"connectionType", "ConnectionType", XtRInt, sizeof (int), 166 offset (connectionType), XtRImmediate, (XtPointer) 0 } 167}; 168#undef offset 169 170static XrmOptionDescRec options[] = { 171 { "-xdmaddress", "*xdmAddress", XrmoptionSepArg, NULL }, 172 { "-clientaddress", "*clientAddress", XrmoptionSepArg, NULL }, 173 { "-connectionType","*connectionType", XrmoptionSepArg, NULL }, 174}; 175 176typedef struct _hostAddr { 177 struct _hostAddr *next; 178 struct sockaddr *addr; 179 int addrlen; 180 xdmOpCode type; 181} HostAddr; 182 183static HostAddr *hostAddrdb; 184 185typedef struct _hostName { 186 struct _hostName *next; 187 char *fullname; 188 int willing; 189 ARRAY8 hostname, status; 190 CARD16 connectionType; 191 ARRAY8 hostaddr; 192} HostName; 193 194static HostName *hostNamedb; 195 196static int socketFD; 197#if defined(IPv6) && defined(AF_INET6) 198static int socket6FD; 199#endif 200 201static int pingTry; 202 203#define PING_INTERVAL 2000 204#define TRIES 3 205 206static XdmcpBuffer directBuffer, broadcastBuffer; 207static XdmcpBuffer buffer; 208 209#if ((defined(SVR4) && !defined(sun) && !defined(__sgi) && !defined(NCR)) || defined(ISC)) && defined(SIOCGIFCONF) 210 211/* Deal with different SIOCGIFCONF ioctl semantics on these OSs */ 212 213static int 214ifioctl (int fd, int cmd, char *arg) 215{ 216 struct strioctl ioc; 217 int ret; 218 219 bzero((char *) &ioc, sizeof(ioc)); 220 ioc.ic_cmd = cmd; 221 ioc.ic_timout = 0; 222 if (cmd == SIOCGIFCONF) 223 { 224 ioc.ic_len = ((struct ifconf *) arg)->ifc_len; 225 ioc.ic_dp = ((struct ifconf *) arg)->ifc_buf; 226# ifdef ISC 227 /* SIOCGIFCONF is somewhat brain damaged on ISC. The argument 228 * buffer must contain the ifconf structure as header. Ifc_req 229 * is also not a pointer but a one element array of ifreq 230 * structures. On return this array is extended by enough 231 * ifreq fields to hold all interfaces. The return buffer length 232 * is placed in the buffer header. 233 */ 234 ((struct ifconf *) ioc.ic_dp)->ifc_len = 235 ioc.ic_len - sizeof(struct ifconf); 236# endif 237 } 238 else 239 { 240 ioc.ic_len = sizeof(struct ifreq); 241 ioc.ic_dp = arg; 242 } 243 ret = ioctl(fd, I_STR, (char *) &ioc); 244 if (ret >= 0 && cmd == SIOCGIFCONF) 245# ifdef SVR4 246 ((struct ifconf *) arg)->ifc_len = ioc.ic_len; 247# endif 248# ifdef ISC 249 { 250 ((struct ifconf *) arg)->ifc_len = 251 ((struct ifconf *)ioc.ic_dp)->ifc_len; 252 ((struct ifconf *) arg)->ifc_buf = 253 (caddr_t)((struct ifconf *)ioc.ic_dp)->ifc_req; 254 } 255# endif 256 return(ret); 257} 258#else /* ((SVR4 && !sun && !NCR) || ISC) && SIOCGIFCONF */ 259# define ifioctl ioctl 260#endif /* ((SVR4 && !sun) || ISC) && SIOCGIFCONF */ 261 262 263/* ARGSUSED */ 264static void 265PingHosts (XtPointer closure, XtIntervalId *id) 266{ 267 HostAddr *hosts; 268 int sfd = socketFD; 269 270 for (hosts = hostAddrdb; hosts; hosts = hosts->next) 271 { 272#if defined(IPv6) && defined(AF_INET6) 273 if ( ((struct sockaddr *) hosts->addr)->sa_family == AF_INET6 ) 274 sfd = socket6FD; 275 else 276 sfd = socketFD; 277#endif 278 if (hosts->type == QUERY) 279 XdmcpFlush (sfd, &directBuffer, 280 (XdmcpNetaddr) hosts->addr, hosts->addrlen); 281 else 282 XdmcpFlush (sfd, &broadcastBuffer, 283 (XdmcpNetaddr) hosts->addr, hosts->addrlen); 284 } 285 if (++pingTry < TRIES) 286 XtAddTimeOut (PING_INTERVAL, PingHosts, (XtPointer) 0); 287} 288 289char **NameTable; 290int NameTableSize; 291 292static int 293HostnameCompare (const void *a, const void *b) 294{ 295 return strcmp (*(char **)a, *(char **)b); 296} 297 298static void 299RebuildTable (int size) 300{ 301 char **newTable = NULL; 302 HostName *names; 303 int i; 304 305 if (size) 306 { 307 newTable = malloc (size * sizeof (char *)); 308 if (!newTable) 309 return; 310 for (names = hostNamedb, i = 0; names; names = names->next, i++) 311 newTable[i] = names->fullname; 312 qsort (newTable, size, sizeof (char *), HostnameCompare); 313 } 314 XawListChange (list, newTable, size, 0, TRUE); 315 free (NameTable); 316 NameTable = newTable; 317 NameTableSize = size; 318} 319 320static int 321AddHostname (ARRAY8Ptr hostname, ARRAY8Ptr status, struct sockaddr *addr, int willing) 322{ 323 HostName *new, **names, *name; 324 ARRAY8 hostAddr = {0, NULL}; 325 CARD16 connectionType; 326 int fulllen; 327 328 switch (addr->sa_family) 329 { 330 case AF_INET: 331 hostAddr.data = (CARD8 *) &((struct sockaddr_in *) addr)->sin_addr; 332 hostAddr.length = 4; 333 connectionType = FamilyInternet; 334 break; 335#if defined(IPv6) && defined(AF_INET6) 336 case AF_INET6: 337 hostAddr.data = (CARD8 *) &((struct sockaddr_in6 *) addr)->sin6_addr; 338 hostAddr.length = 16; 339 connectionType = FamilyInternet6; 340 break; 341#endif 342 default: 343 hostAddr.data = (CARD8 *) ""; 344 hostAddr.length = 0; 345 connectionType = FamilyLocal; 346 break; 347 } 348 for (names = &hostNamedb; *names; names = & (*names)->next) 349 { 350 name = *names; 351 if (connectionType == name->connectionType && 352 XdmcpARRAY8Equal (&hostAddr, &name->hostaddr)) 353 { 354 if (XdmcpARRAY8Equal (status, &name->status)) 355 { 356 return 0; 357 } 358 break; 359 } 360 } 361 if (!*names) 362 { 363 new = malloc (sizeof (HostName)); 364 if (!new) 365 return 0; 366 if (hostname->length) 367 { 368 switch (addr->sa_family) 369 { 370 case AF_INET: 371#if defined(IPv6) && defined(AF_INET6) 372 case AF_INET6: 373#endif 374 { 375 struct hostent *hostent; 376 char *host; 377 378 hostent = gethostbyaddr ((char *)hostAddr.data, hostAddr.length, addr->sa_family); 379 if (hostent) 380 { 381 XdmcpDisposeARRAY8 (hostname); 382 host = (char *)hostent->h_name; 383 XdmcpAllocARRAY8 (hostname, strlen (host)); 384 memmove( hostname->data, host, hostname->length); 385 } 386 } 387 } 388 } 389 if (!XdmcpAllocARRAY8 (&new->hostaddr, hostAddr.length)) 390 { 391 free (new->fullname); 392 free (new); 393 return 0; 394 } 395 memmove( new->hostaddr.data, hostAddr.data, hostAddr.length); 396 new->connectionType = connectionType; 397 new->hostname = *hostname; 398 399 *names = new; 400 new->next = NULL; 401 NameTableSize++; 402 } 403 else 404 { 405 new = *names; 406 free (new->fullname); 407 XdmcpDisposeARRAY8 (&new->status); 408 XdmcpDisposeARRAY8 (hostname); 409 } 410 new->willing = willing; 411 new->status = *status; 412 413 hostname = &new->hostname; 414 fulllen = hostname->length; 415 if (fulllen < 30) 416 fulllen = 30; 417 fulllen += status->length + 10; 418 new->fullname = malloc (fulllen); 419 if (!new->fullname) 420 { 421 new->fullname = "Unknown"; 422 } 423 else 424 { 425 snprintf(new->fullname, fulllen, "%-30.*s %*.*s", 426 hostname->length, hostname->data, 427 status->length, status->length, status->data); 428 } 429 RebuildTable (NameTableSize); 430 return 1; 431} 432 433static void 434DisposeHostname (HostName *host) 435{ 436 XdmcpDisposeARRAY8 (&host->hostname); 437 XdmcpDisposeARRAY8 (&host->hostaddr); 438 XdmcpDisposeARRAY8 (&host->status); 439 free (host->fullname); 440 free (host); 441} 442 443#if 0 444static void 445RemoveHostname (HostName *host) 446{ 447 HostName **prev, *hosts; 448 449 prev = &hostNamedb;; 450 for (hosts = hostNamedb; hosts; hosts = hosts->next) 451 { 452 if (hosts == host) 453 break; 454 prev = &hosts->next; 455 } 456 if (!hosts) 457 return; 458 *prev = host->next; 459 DisposeHostname (host); 460 NameTableSize--; 461 RebuildTable (NameTableSize); 462} 463#endif 464 465static void 466EmptyHostnames (void) 467{ 468 HostName *hosts, *next; 469 470 for (hosts = hostNamedb; hosts; hosts = next) 471 { 472 next = hosts->next; 473 DisposeHostname (hosts); 474 } 475 NameTableSize = 0; 476 hostNamedb = NULL; 477 RebuildTable (NameTableSize); 478} 479 480/* ARGSUSED */ 481static void 482ReceivePacket (XtPointer closure, int *source, XtInputId *id) 483{ 484 XdmcpHeader header; 485 ARRAY8 authenticationName = {0, NULL}; 486 ARRAY8 hostname = {0, NULL}; 487 ARRAY8 status = {0, NULL}; 488 int saveHostname = 0; 489#if defined(IPv6) && defined(AF_INET6) 490 struct sockaddr_storage addr; 491#else 492 struct sockaddr addr; 493#endif 494 int addrlen; 495 int sfd = * (int *) closure; 496 497 addrlen = sizeof (addr); 498 if (!XdmcpFill (sfd, &buffer, (XdmcpNetaddr) &addr, &addrlen)) 499 return; 500 if (!XdmcpReadHeader (&buffer, &header)) 501 return; 502 if (header.version != XDM_PROTOCOL_VERSION) 503 return; 504 switch (header.opcode) { 505 case WILLING: 506 if (XdmcpReadARRAY8 (&buffer, &authenticationName) && 507 XdmcpReadARRAY8 (&buffer, &hostname) && 508 XdmcpReadARRAY8 (&buffer, &status)) 509 { 510 if (header.length == 6 + authenticationName.length + 511 hostname.length + status.length) 512 { 513 if (AddHostname (&hostname, &status, (struct sockaddr *) &addr, 514 header.opcode == (int) WILLING)) 515 saveHostname = 1; 516 } 517 } 518 XdmcpDisposeARRAY8 (&authenticationName); 519 break; 520 case UNWILLING: 521 if (XdmcpReadARRAY8 (&buffer, &hostname) && 522 XdmcpReadARRAY8 (&buffer, &status)) 523 { 524 if (header.length == 4 + hostname.length + status.length) 525 { 526 if (AddHostname (&hostname, &status, (struct sockaddr *) &addr, 527 header.opcode == (int) WILLING)) 528 saveHostname = 1; 529 530 } 531 } 532 break; 533 default: 534 break; 535 } 536 if (!saveHostname) 537 { 538 XdmcpDisposeARRAY8 (&hostname); 539 XdmcpDisposeARRAY8 (&status); 540 } 541} 542 543static void 544RegisterHostaddr (struct sockaddr *addr, int len, xdmOpCode type) 545{ 546 HostAddr *host, **prev; 547 548 host = malloc (sizeof (HostAddr)); 549 if (!host) 550 return; 551 host->addr = malloc (len); 552 if (!host->addr) 553 { 554 free (host); 555 return; 556 } 557 memmove( (char *) host->addr, (char *) addr, len); 558 host->addrlen = len; 559 host->type = type; 560 for (prev = &hostAddrdb; *prev; prev = &(*prev)->next) 561 ; 562 *prev = host; 563 host->next = NULL; 564} 565 566/* 567 * Register the address for this host. 568 * Called with each of the names on the command line. 569 * The special name "BROADCAST" looks up all the broadcast 570 * addresses on the local host. 571 */ 572 573/* Handle variable length ifreq in BNR2 and later */ 574#ifdef VARIABLE_IFREQ 575# define ifr_size(p) (sizeof (struct ifreq) + \ 576 (p->ifr_addr.sa_len > sizeof (p->ifr_addr) ? \ 577 p->ifr_addr.sa_len - sizeof (p->ifr_addr) : 0)) 578#else 579# define ifr_size(p) (sizeof (struct ifreq)) 580#endif 581 582static void 583RegisterHostname (char *name) 584{ 585#if !defined(IPv6) || !defined(AF_INET6) 586 struct hostent *hostent; 587#endif 588 struct sockaddr_in in_addr; 589 struct ifconf ifc; 590 register struct ifreq *ifr; 591 struct sockaddr broad_addr; 592 char buf[2048], *cp, *cplim; 593 594 if (!strcmp (name, BROADCAST_HOSTNAME)) 595 { 596#ifdef WINTCP /* NCR with Wollongong TCP */ 597 int ipfd; 598 struct ifconf *ifcp; 599 struct strioctl ioc; 600 int n; 601 602 ifcp = (struct ifconf *)buf; 603 ifcp->ifc_buf = buf+4; 604 ifcp->ifc_len = sizeof (buf) - 4; 605 606 if ((ipfd=open( "/dev/ip", O_RDONLY )) < 0 ) 607 { 608 t_error( "RegisterHostname() t_open(/dev/ip) failed" ); 609 return; 610 } 611 612 ioc.ic_cmd = IPIOC_GETIFCONF; 613 ioc.ic_timout = 60; 614 ioc.ic_len = sizeof( buf ); 615 ioc.ic_dp = (char *)ifcp; 616 617 if (ioctl (ipfd, (int) I_STR, (char *) &ioc) < 0) 618 { 619 perror( "RegisterHostname() ioctl(I_STR(IPIOC_GETIFCONF)) failed" ); 620 close( ipfd ); 621 return; 622 } 623 624 for (ifr = ifcp->ifc_req, n = ifcp->ifc_len / sizeof (struct ifreq); 625 --n >= 0; 626 ifr++) 627#else /* WINTCP */ 628 ifc.ifc_len = sizeof (buf); 629 ifc.ifc_buf = buf; 630 if (ifioctl (socketFD, (int) SIOCGIFCONF, (char *) &ifc) < 0) 631 return; 632 633# ifdef ISC 634# define IFC_IFC_REQ (struct ifreq *) ifc.ifc_buf 635# else 636# define IFC_IFC_REQ ifc.ifc_req 637# endif 638 639 cplim = (char *) IFC_IFC_REQ + ifc.ifc_len; 640 641 for (cp = (char *) IFC_IFC_REQ; cp < cplim; cp += ifr_size (ifr)) 642#endif /* WINTCP */ 643 { 644#ifndef WINTCP 645 ifr = (struct ifreq *) cp; 646#endif 647 if (ifr->ifr_addr.sa_family != AF_INET) 648 continue; 649 650 broad_addr = ifr->ifr_addr; 651 ((struct sockaddr_in *) &broad_addr)->sin_addr.s_addr = 652 htonl (INADDR_BROADCAST); 653#ifdef SIOCGIFBRDADDR 654 { 655 struct ifreq broad_req; 656 657 broad_req = *ifr; 658# ifdef WINTCP /* NCR with Wollongong TCP */ 659 ioc.ic_cmd = IPIOC_GETIFFLAGS; 660 ioc.ic_timout = 0; 661 ioc.ic_len = sizeof( broad_req ); 662 ioc.ic_dp = (char *)&broad_req; 663 664 if (ioctl (ipfd, I_STR, (char *) &ioc) != -1 && 665# else /* WINTCP */ 666 if (ifioctl (socketFD, SIOCGIFFLAGS, (char *) &broad_req) != -1 && 667# endif /* WINTCP */ 668 (broad_req.ifr_flags & IFF_BROADCAST) && 669 (broad_req.ifr_flags & IFF_UP) 670 ) 671 { 672 broad_req = *ifr; 673# ifdef WINTCP /* NCR with Wollongong TCP */ 674 ioc.ic_cmd = IPIOC_GETIFBRDADDR; 675 ioc.ic_timout = 0; 676 ioc.ic_len = sizeof( broad_req ); 677 ioc.ic_dp = (char *)&broad_req; 678 679 if (ioctl (ipfd, I_STR, (char *) &ioc) != -1) 680# else /* WINTCP */ 681 if (ifioctl (socketFD, SIOCGIFBRDADDR, &broad_req) != -1) 682# endif /* WINTCP */ 683 broad_addr = broad_req.ifr_addr; 684 else 685 continue; 686 } 687 else 688 continue; 689 } 690#endif 691 in_addr = *((struct sockaddr_in *) &broad_addr); 692 in_addr.sin_port = htons (XDM_UDP_PORT); 693#ifdef BSD44SOCKETS 694 in_addr.sin_len = sizeof(in_addr); 695#endif 696 RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr), 697 BROADCAST_QUERY); 698 } 699 } 700 else 701 { 702 /* address as hex string, e.g., "12180022" (deprecated) */ 703 if (strlen(name) == 8 && 704 FromHex(name, (char *)&in_addr.sin_addr, strlen(name)) == 0) 705 { 706 in_addr.sin_family = AF_INET; 707 in_addr.sin_port = htons (XDM_UDP_PORT); 708#ifdef BSD44SOCKETS 709 in_addr.sin_len = sizeof(in_addr); 710#endif 711 RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr), 712 QUERY); 713 } 714#if defined(IPv6) && defined(AF_INET6) 715 else { 716 char sport[8]; 717 struct addrinfo *ai, *nai, hints; 718 bzero(&hints,sizeof(hints)); 719 hints.ai_socktype = SOCK_DGRAM; 720 snprintf(sport, sizeof(sport), "%d", XDM_UDP_PORT); 721 if (getaddrinfo(name, sport, &hints, &ai) == 0) { 722 for (nai = ai ; nai != NULL ; nai = nai->ai_next) { 723 if ((nai->ai_family == AF_INET) || 724 (nai->ai_family == AF_INET6)) { 725 if (((nai->ai_family == AF_INET) && 726 IN_MULTICAST(((struct sockaddr_in *) nai->ai_addr) 727 ->sin_addr.s_addr)) 728 || ((nai->ai_family == AF_INET6) && 729 IN6_IS_ADDR_MULTICAST( 730 &((struct sockaddr_in6 *) nai->ai_addr) 731 ->sin6_addr))) 732 { 733 RegisterHostaddr(nai->ai_addr, nai->ai_addrlen, 734 BROADCAST_QUERY); 735 } else { 736 RegisterHostaddr(nai->ai_addr, nai->ai_addrlen, 737 QUERY); 738 } 739 } 740 } 741 freeaddrinfo(ai); 742 } 743 } 744#else 745 /* Per RFC 1123, check first for IP address in dotted-decimal form */ 746 else if ((in_addr.sin_addr.s_addr = inet_addr(name)) != -1) 747 in_addr.sin_family = AF_INET; 748 else 749 { 750 hostent = gethostbyname (name); 751 if (!hostent) 752 return; 753 if (hostent->h_addrtype != AF_INET || hostent->h_length != 4) 754 return; 755 in_addr.sin_family = hostent->h_addrtype; 756 memmove( &in_addr.sin_addr, hostent->h_addr, 4); 757 } 758 in_addr.sin_port = htons (XDM_UDP_PORT); 759# ifdef BSD44SOCKETS 760 in_addr.sin_len = sizeof(in_addr); 761# endif 762 RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr), 763 QUERY); 764#endif /* IPv6 */ 765 } 766} 767 768static ARRAYofARRAY8 AuthenticationNames; 769 770#if 0 771static void 772RegisterAuthenticationName (char *name, int namelen) 773{ 774 ARRAY8Ptr authName; 775 if (!XdmcpReallocARRAYofARRAY8 (&AuthenticationNames, 776 AuthenticationNames.length + 1)) 777 return; 778 authName = &AuthenticationNames.data[AuthenticationNames.length-1]; 779 if (!XdmcpAllocARRAY8 (authName, namelen)) 780 return; 781 memmove( authName->data, name, namelen); 782} 783#endif 784 785static int 786InitXDMCP (char **argv) 787{ 788 int soopts = 1; 789 XdmcpHeader header; 790 int i; 791 792 header.version = XDM_PROTOCOL_VERSION; 793 header.opcode = (CARD16) BROADCAST_QUERY; 794 header.length = 1; 795 for (i = 0; i < (int)AuthenticationNames.length; i++) 796 header.length += 2 + AuthenticationNames.data[i].length; 797 XdmcpWriteHeader (&broadcastBuffer, &header); 798 XdmcpWriteARRAYofARRAY8 (&broadcastBuffer, &AuthenticationNames); 799 800 header.version = XDM_PROTOCOL_VERSION; 801 header.opcode = (CARD16) QUERY; 802 header.length = 1; 803 for (i = 0; i < (int)AuthenticationNames.length; i++) 804 header.length += 2 + AuthenticationNames.data[i].length; 805 XdmcpWriteHeader (&directBuffer, &header); 806 XdmcpWriteARRAYofARRAY8 (&directBuffer, &AuthenticationNames); 807#if defined(STREAMSCONN) 808 if ((socketFD = t_open ("/dev/udp", O_RDWR, 0)) < 0) 809 return 0; 810 811 if (t_bind( socketFD, NULL, NULL ) < 0) 812 { 813 t_close(socketFD); 814 return 0; 815 } 816 817 /* 818 * This part of the code looks contrived. It will actually fit in nicely 819 * when the CLTS part of Xtrans is implemented. 820 */ 821 { 822 struct netconfig *nconf; 823 824 if( (nconf=getnetconfigent("udp")) == NULL ) 825 { 826 t_unbind(socketFD); 827 t_close(socketFD); 828 return 0; 829 } 830 831 if( netdir_options(nconf, ND_SET_BROADCAST, socketFD, NULL) ) 832 { 833 freenetconfigent(nconf); 834 t_unbind(socketFD); 835 t_close(socketFD); 836 return 0; 837 } 838 839 freenetconfigent(nconf); 840 } 841#else 842 if ((socketFD = socket (AF_INET, SOCK_DGRAM, 0)) < 0) 843 return 0; 844# if defined(IPv6) && defined(AF_INET6) 845 socket6FD = socket (AF_INET6, SOCK_DGRAM, 0); 846# endif 847#endif 848#ifndef STREAMSCONN 849# ifdef SO_BROADCAST 850 soopts = 1; 851 if (setsockopt (socketFD, SOL_SOCKET, SO_BROADCAST, (char *)&soopts, sizeof (soopts)) < 0) 852 perror ("setsockopt"); 853# endif 854#endif 855 856 XtAddInput (socketFD, (XtPointer) XtInputReadMask, ReceivePacket, 857 (XtPointer) &socketFD); 858#if defined(IPv6) && defined(AF_INET6) 859 if (socket6FD != -1) 860 XtAddInput (socket6FD, (XtPointer) XtInputReadMask, ReceivePacket, 861 (XtPointer) &socket6FD); 862#endif 863 while (*argv) 864 { 865 RegisterHostname (*argv); 866 ++argv; 867 } 868 pingTry = 0; 869 PingHosts ((XtPointer)NULL, (XtIntervalId *)NULL); 870 return 1; 871} 872 873static void 874Choose (HostName *h) 875{ 876 if (app_resources.xdmAddress) 877 { 878 struct sockaddr_in in_addr; 879#if defined(IPv6) && defined(AF_INET6) 880 struct sockaddr_in6 in6_addr; 881#endif 882 struct sockaddr *addr = NULL; 883 int family; 884 int len = 0; 885 int fd; 886 char buf[1024]; 887 XdmcpBuffer buffer; 888 char *xdm; 889#if defined(STREAMSCONN) 890 struct t_call call, rcv; 891#endif 892 893 xdm = (char *) app_resources.xdmAddress->data; 894 family = (xdm[0] << 8) + xdm[1]; 895 switch (family) { 896 case AF_INET: 897#ifdef BSD44SOCKETS 898 in_addr.sin_len = sizeof(in_addr); 899#endif 900 in_addr.sin_family = family; 901 memmove( &in_addr.sin_port, xdm + 2, 2); 902 memmove( &in_addr.sin_addr, xdm + 4, 4); 903 addr = (struct sockaddr *) &in_addr; 904 len = sizeof (in_addr); 905 break; 906#if defined(IPv6) && defined(AF_INET6) 907 case AF_INET6: 908 bzero(&in6_addr, sizeof(in6_addr)); 909# ifdef SIN6_LEN 910 in6_addr.sin6_len = sizeof(in6_addr); 911# endif 912 in6_addr.sin6_family = family; 913 memmove( &in6_addr.sin6_port, xdm + 2, 2); 914 memmove( &in6_addr.sin6_addr, xdm + 4, 16); 915 addr = (struct sockaddr *) &in6_addr; 916 len = sizeof (in6_addr); 917 break; 918#endif 919 } 920#if defined(STREAMSCONN) 921 if ((fd = t_open ("/dev/tcp", O_RDWR, NULL)) == -1) 922 { 923 fprintf (stderr, "Cannot create response endpoint\n"); 924 fflush(stderr); 925 exit (REMANAGE_DISPLAY); 926 } 927 if (t_bind (fd, NULL, NULL) == -1) 928 { 929 fprintf (stderr, "Cannot bind response endpoint\n"); 930 fflush(stderr); 931 t_close (fd); 932 exit (REMANAGE_DISPLAY); 933 } 934 call.addr.buf=(char *)addr; 935 call.addr.len=len; 936 call.addr.maxlen=len; 937 call.opt.len=0; 938 call.opt.maxlen=0; 939 call.udata.len=0; 940 call.udata.maxlen=0; 941 if (t_connect (fd, &call, NULL) == -1) 942 { 943 t_error ("Cannot connect to xdm\n"); 944 fflush(stderr); 945 t_unbind (fd); 946 t_close (fd); 947 exit (REMANAGE_DISPLAY); 948 } 949#else 950 if ((fd = socket (family, SOCK_STREAM, 0)) == -1) 951 { 952 fprintf (stderr, "Cannot create response socket\n"); 953 exit (REMANAGE_DISPLAY); 954 } 955 if (connect (fd, addr, len) == -1) 956 { 957 fprintf (stderr, "Cannot connect to xdm\n"); 958 exit (REMANAGE_DISPLAY); 959 } 960#endif 961 buffer.data = (BYTE *) buf; 962 buffer.size = sizeof (buf); 963 buffer.pointer = 0; 964 buffer.count = 0; 965 XdmcpWriteARRAY8 (&buffer, app_resources.clientAddress); 966 XdmcpWriteCARD16 (&buffer, (CARD16) app_resources.connectionType); 967 XdmcpWriteARRAY8 (&buffer, &h->hostaddr); 968#if defined(STREAMSCONN) 969 if( t_snd (fd, (char *)buffer.data, buffer.pointer, 0) < 0 ) 970 { 971 fprintf (stderr, "Cannot send to xdm\n"); 972 fflush(stderr); 973 t_unbind (fd); 974 t_close (fd); 975 exit (REMANAGE_DISPLAY); 976 } 977 sleep(5); /* Hack because sometimes the connection gets 978 closed before the data arrives on the other end. */ 979 t_snddis (fd,NULL); 980 t_unbind (fd); 981 t_close (fd); 982#else 983 write (fd, (char *)buffer.data, buffer.pointer); 984 close (fd); 985#endif 986 } 987 else 988 { 989 int i; 990 991 printf ("%u\n", h->connectionType); 992 for (i = 0; i < (int)h->hostaddr.length; i++) 993 printf ("%u%s", h->hostaddr.data[i], 994 i == h->hostaddr.length - 1 ? "\n" : " "); 995 } 996} 997 998/* 999 next_line returns the next line in a list 1000 across the list end. 1001 (0, 1, 2, 3, 0, 1, 2, 3 ....) 1002*/ 1003 1004static int 1005next_line(unsigned int current, unsigned int size, int event) 1006{ 1007 switch(event) { 1008 case Button5: 1009 return (current + 1) % size; 1010 case Button4: 1011 return (current + size - 1) % size; 1012 case XK_Down: 1013 return (current + 1) % size; 1014 case XK_Up: 1015 return (current + size - 1) % size; 1016 } 1017 return -1; 1018} 1019 1020/* 1021 Hostselect selects a given chooser line. 1022 Returns 1 when host is willing and 0 if not 1023*/ 1024 1025static int 1026Hostselect (int line) 1027{ 1028 XawListReturnStruct *r; 1029 HostName *h; 1030 1031 /* Assume the next host is willing */ 1032 XawListHighlight (list,line); 1033 r = XawListShowCurrent (list); 1034 /* copied from DoCheckWilling */ 1035 for (h = hostNamedb; h; h = h->next) 1036 { 1037 if (!strcmp (r->string, h->fullname)) 1038 { 1039 if (!h->willing) 1040 XawListUnhighlight (list); 1041 else 1042 { 1043 /* Scroll viewport to make sure new selection is visible */ 1044 Arg size[2]; 1045 Dimension height, portheight; 1046 Position y; 1047 int lineheight, liney; 1048 1049 XtSetArg (size[0], XtNheight, &height); 1050 XtSetArg (size[1], XtNy, &y); 1051 XtGetValues (list, size, (Cardinal) 2); 1052 1053 XtSetArg (size[0], XtNheight, &portheight); 1054 XtGetValues (viewport, size, (Cardinal) 1); 1055 1056 lineheight = height / NameTableSize; 1057 liney = lineheight * line; 1058 1059 if ((y + liney) < 0) { 1060 XawViewportSetCoordinates(viewport, 0, liney); 1061 } else if ((y + liney + lineheight) > portheight) { 1062 XawViewportSetCoordinates(viewport, 0, 1063 (liney + lineheight) - portheight); 1064 } 1065 1066 XtFree((char *) r); 1067 return 1; 1068 } 1069 } 1070 } 1071 XtFree((char *) r); 1072 return 0; 1073} 1074 1075/* 1076 Selectfirst selects the first willing host 1077 in the chooser list (so you can select a host without 1078 presence of mouse, but with pressing space or return, 1079 or XK_Down / XK_Up 1080*/ 1081 1082static void 1083Selectfirst (void) 1084{ 1085 int line; 1086 1087 for (line = 0; line < NameTableSize; line++) 1088 { 1089 if (Hostselect(line)) 1090 return; 1091 } 1092 return; 1093} 1094 1095/* 1096 Storeold stores the selected line into global int oldentry 1097*/ 1098 1099static void 1100Storeold (Widget w, XEvent *event, String *params, Cardinal *num_params) 1101{ 1102 XawListReturnStruct *r = XawListShowCurrent(list); 1103 1104 oldline = r->list_index; 1105 XtFree((char *) r); 1106} 1107 1108/* 1109 Setold restores the global int oldentry 1110 when you try to select a host with your mouse 1111 who is unwilling as follows: 1112 <Btn1Down>: Store() Set() CheckWilling() Setold() \n\ 1113*/ 1114 1115static void 1116Setold (Widget w, XEvent *event, String *params, Cardinal *num_params) 1117{ 1118 1119 if ( (XawListShowCurrent(list))->list_index == XAW_LIST_NONE && oldline != XAW_LIST_NONE) 1120 XawListHighlight (list, oldline); 1121} 1122 1123/* 1124 HostCycle tries to select the next willing host across 1125 the list end and will stop at the first found willing host 1126 or after trying all entries. 1127*/ 1128 1129static void 1130HostCycle(unsigned int line, unsigned int size, KeySym keysym) 1131{ 1132 unsigned int newline = line; 1133 /* Do it only once around the chooser list, either direction */ 1134 while ( (newline = next_line(newline,size,keysym)) != line && newline != -1) 1135 { 1136 if (Hostselect(newline)) 1137 return; 1138 } 1139 /* No other willing host could be found, stay at the old one*/ 1140 XawListHighlight (list, line); 1141 return; 1142} 1143 1144/* 1145 Switch_Key handles XK_Up and XK_Down 1146 and highlights an appropriate line in the chooser list. 1147*/ 1148 1149static void 1150Switch_Key (Widget w, XEvent *event, String *params, Cardinal *num_params) 1151{ 1152 char strbuf[128]; 1153 KeySym keysym = 0; 1154 static XComposeStatus compose_status = {NULL, 0}; 1155 XawListReturnStruct *r; 1156 1157 XLookupString (&event->xkey, strbuf, sizeof (strbuf), 1158 &keysym, &compose_status); 1159 1160 if (keysym != XK_Up && keysym != XK_Down) 1161 return; 1162 1163 r = XawListShowCurrent (list); 1164 1165 if (r->list_index == XAW_LIST_NONE) 1166 Selectfirst(); 1167 else 1168 HostCycle(r->list_index,NameTableSize,keysym); 1169 1170 XtFree((char *) r); 1171 return; 1172} 1173 1174 1175 1176/* 1177 Switch_Btn handles ScrollWheel Forward (Button5) and Backward 1178 (Button4) and highlights an appropriate line in the chooser list. 1179*/ 1180 1181static void 1182Switch_Btn (Widget w, XEvent *event, String *params, Cardinal *num_params) 1183{ 1184 XawListReturnStruct *r; 1185 r = XawListShowCurrent (list); 1186 1187 if (r->list_index == XAW_LIST_NONE) 1188 Selectfirst(); 1189 else 1190 HostCycle(r->list_index,NameTableSize,event->xbutton.button); 1191 1192 XtFree((char *) r); 1193 return; 1194} 1195 1196 1197/* ARGSUSED */ 1198static void 1199DoAccept (Widget w, XEvent *event, String *params, Cardinal *num_params) 1200{ 1201 XawListReturnStruct *r; 1202 HostName *h; 1203 1204 r = XawListShowCurrent (list); 1205 if (r->list_index == XAW_LIST_NONE) 1206#ifdef XKB 1207 XkbStdBell(XtDisplay(toplevel),XtWindow(w),0,XkbBI_MinorError); 1208#else 1209 XBell (XtDisplay (toplevel), 0); 1210#endif 1211 else 1212 { 1213 for (h = hostNamedb; h; h = h->next) 1214 if (!strcmp (r->string, h->fullname)) 1215 { 1216 Choose (h); 1217 } 1218 exit (OBEYSESS_DISPLAY); 1219 } 1220 XtFree((char *) r); 1221} 1222 1223/* ARGSUSED */ 1224static void 1225DoCheckWilling (Widget w, XEvent *event, String *params, Cardinal *num_params) 1226{ 1227 XawListReturnStruct *r; 1228 HostName *h; 1229 1230 r = XawListShowCurrent (list); 1231 if (r->list_index != XAW_LIST_NONE) { 1232 for (h = hostNamedb; h; h = h->next) 1233 if (!strcmp (r->string, h->fullname)) 1234 if (!h->willing) 1235 XawListUnhighlight (list); 1236 } 1237 XtFree((char *) r); 1238} 1239 1240/* ARGSUSED */ 1241static void 1242DoCancel (Widget w, XEvent *event, String *params, Cardinal *num_params) 1243{ 1244 exit (OBEYSESS_DISPLAY); 1245} 1246 1247/* ARGSUSED */ 1248static void 1249DoPing (Widget w, XEvent *event, String *params, Cardinal *num_params) 1250{ 1251 EmptyHostnames (); 1252 pingTry = 0; 1253 PingHosts ((XtPointer)NULL, (XtIntervalId *)NULL); 1254} 1255 1256static XtActionsRec app_actions[] = { 1257 { "Accept", DoAccept }, 1258 { "Cancel", DoCancel }, 1259 { "CheckWilling", DoCheckWilling }, 1260 { "Ping", DoPing }, 1261 { "KeySwitch", Switch_Key }, 1262 { "BtnSwitch", Switch_Btn }, 1263 { "Store", Storeold }, 1264 { "Setold", Setold }, 1265}; 1266 1267int 1268main (int argc, char **argv) 1269{ 1270 Arg position[3]; 1271 Dimension width, height; 1272 Position x, y; 1273#ifdef USE_XINERAMA 1274 XineramaScreenInfo *screens; 1275 int s_num; 1276#endif 1277 1278 1279 toplevel = XtInitialize (argv[0], "Chooser", options, XtNumber(options), &argc, argv); 1280 1281 XtAddConverter(XtRString, XtRARRAY8, CvtStringToARRAY8, NULL, 0); 1282 1283 XtGetApplicationResources (toplevel, (XtPointer) &app_resources, resources, 1284 XtNumber (resources), NULL, (Cardinal) 0); 1285 1286 XtAddActions (app_actions, XtNumber (app_actions)); 1287 paned = XtCreateManagedWidget ("paned", panedWidgetClass, toplevel, NULL, 0); 1288 label = XtCreateManagedWidget ("label", labelWidgetClass, paned, NULL, 0); 1289 viewport = XtCreateManagedWidget ("viewport", viewportWidgetClass, paned, NULL, 0); 1290 list = XtCreateManagedWidget ("list", listWidgetClass, viewport, NULL, 0); 1291 box = XtCreateManagedWidget ("box", boxWidgetClass, paned, NULL, 0); 1292 cancel = XtCreateManagedWidget ("cancel", commandWidgetClass, box, NULL, 0); 1293 acceptit = XtCreateManagedWidget ("accept", commandWidgetClass, box, NULL, 0); 1294 ping = XtCreateManagedWidget ("ping", commandWidgetClass, box, NULL, 0); 1295 1296 /* 1297 * center ourselves on the screen 1298 */ 1299 XtSetMappedWhenManaged(toplevel, FALSE); 1300 XtRealizeWidget (toplevel); 1301 1302 XtSetArg (position[0], XtNwidth, &width); 1303 XtSetArg (position[1], XtNheight, &height); 1304 XtGetValues (toplevel, position, (Cardinal) 2); 1305#ifdef USE_XINERAMA 1306 if ( 1307 XineramaIsActive(XtDisplay(toplevel)) && 1308 (screens = XineramaQueryScreens(XtDisplay(toplevel), &s_num)) != NULL 1309 ) 1310 { 1311 x = (Position)(screens[0].x_org + (screens[0].width - width) / 2); 1312 y = (Position)(screens[0].y_org + (screens[0].height - height) / 3); 1313 1314 XFree(screens); 1315 } 1316 else 1317#endif 1318 { 1319 x = (Position)(WidthOfScreen (XtScreen (toplevel)) - width) / 2; 1320 y = (Position)(HeightOfScreen (XtScreen (toplevel)) - height) / 3; 1321 } 1322 XtSetArg (position[0], XtNx, x); 1323 XtSetArg (position[1], XtNy, y); 1324 XtSetValues (toplevel, position, (Cardinal) 2); 1325 1326 /* 1327 * Run 1328 */ 1329 XtMapWidget(toplevel); 1330 InitXDMCP (argv + 1); 1331 XtMainLoop (); 1332 exit(0); 1333 /*NOTREACHED*/ 1334} 1335 1336/* Converts the hex string s of length len into the byte array d. 1337 Returns 0 if s was a legal hex string, 1 otherwise. 1338 */ 1339static int 1340FromHex (char *s, char *d, int len) 1341{ 1342 int t; 1343 int ret = len&1; /* odd-length hex strings are illegal */ 1344 while (len >= 2) 1345 { 1346#define HexChar(c) ('0' <= (c) && (c) <= '9' ? (c) - '0' : (c) - 'a' + 10) 1347 1348 if (!ishexdigit(*s)) 1349 ret = 1; 1350 t = HexChar (*s) << 4; 1351 s++; 1352 if (!ishexdigit(*s)) 1353 ret = 1; 1354 t += HexChar (*s); 1355 s++; 1356 *d++ = t; 1357 len -= 2; 1358 } 1359 return ret; 1360} 1361 1362/*ARGSUSED*/ 1363static void 1364CvtStringToARRAY8 (XrmValuePtr args, Cardinal *num_args, XrmValuePtr fromVal, XrmValuePtr toVal) 1365{ 1366 static ARRAY8Ptr dest; 1367 char *s; 1368 int len; 1369 1370 dest = (ARRAY8Ptr) XtMalloc (sizeof (ARRAY8)); 1371 len = fromVal->size; 1372 s = (char *) fromVal->addr; 1373 if (!XdmcpAllocARRAY8 (dest, len >> 1)) 1374 XtStringConversionWarning ((char *) fromVal->addr, XtRARRAY8); 1375 else 1376 { 1377 FromHex (s, (char *) dest->data, len); 1378 } 1379 toVal->addr = (caddr_t) &dest; 1380 toVal->size = sizeof (ARRAY8Ptr); 1381} 1382