home *** CD-ROM | disk | FTP | other *** search
/ Informática Multimedia: Special Games (Alt) / INFESPGAMES.iso / os2 / backgam / source / socket.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-07  |  25.7 KB  |  915 lines

  1. /*************************************************************
  2.  *    ______                                                 *
  3.  *   /     /\  TinyFugue was derived from a client initially *
  4.  *  /   __/  \ written by Anton Rang (Tarrant) and later     *
  5.  *  |  / /\  | modified by Leo Plotkin (Grod).  The early    *
  6.  *  |  |/    | versions of TinyFugue written by Greg Hudson  *
  7.  *  |  X__/  | (Explorer_Bob).  The current version is       *
  8.  *  \ /      / written and maintained by Ken Keys (Hawkeye), *
  9.  *   \______/  who can be reached at kkeys@ucsd.edu.         *
  10.  *                                                           *
  11.  *             No copyright 1992, no rights reserved.        *
  12.  *             Fugue is in the public domain.                *
  13.  *************************************************************/
  14.  
  15. /***************************************************************
  16.  * Fugue socket handling                                       *
  17.  *                                                             *
  18.  * Rewritten by Ken Keys to do non-blocking connect(), handle  *
  19.  * background sockets, and do more efficient process running.  *
  20.  * Reception and transmission through sockets is handled here. *
  21.  * This module also contains the main loop.                    *
  22.  * Multiple sockets handled here.                              *
  23.  * Autologin handled here.                                     *
  24.  ***************************************************************/
  25.  
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include <sys/time.h>
  29. #include <errno.h>
  30. #include <stdio.h>
  31. #include <ctype.h>
  32. #include <sys/ioctl.h>
  33. #ifdef CONNECT_SVR4
  34. # include <stropts.h>
  35. #endif
  36. #ifdef CONNECT_BSD
  37. # include <sys/socket.h>
  38. # include <sys/uio.h>
  39. #endif
  40. #include "tf.h"
  41. #include "dstring.h"
  42. #include "util.h"
  43. #include "history.h"
  44. #include "world.h"
  45. #include "socket.h"
  46. #include "output.h"
  47. #include "process.h"
  48. #include "macro.h"
  49. #include "keyboard.h"
  50. #include "command1.h"
  51. #include "command2.h"
  52. #include "special.h"
  53. #include "signal.h"
  54. #include "tf.connect.h"
  55. #ifndef CONNECT
  56. #include "opensock.c"
  57. #endif
  58.  
  59. static void FDECL(wload,(World *w));
  60. static void FDECL(announce_world,(Sock *s));
  61. static void NDECL(bg_sock);
  62. static void FDECL(fg_sock,(Sock *sock));
  63. static void NDECL(any_sock);
  64. static int  FDECL(establish,(Sock *new));
  65. static void NDECL(nuke_dead_socks);
  66. static void FDECL(killsock,(Sock *sock));
  67. static void FDECL(nukesock,(Sock *sock));
  68. static int  FDECL(receive,(Sock *sock, Stringp s));
  69. static void NDECL(magic_login);
  70. static void FDECL(process_socket_input,(Sock *sock, Stringp out));
  71. static void FDECL(handle_socket_input,(Sock *sock));
  72. static void FDECL(flush_output,(Sock *sock));
  73. #ifdef CONNECT
  74. static int  FDECL(nb_connect,(char *address, char *port, FILE **fpp,
  75.             int *tfcerrnop));
  76. static int  FDECL(recvfd,(int sockfd, int *tfcerrnop));
  77. #endif
  78.  
  79. void   FDECL(main_loop,(World *initial_world, int autologin));
  80. void   FDECL(readers_clear,(int fd));
  81. void   FDECL(readers_set,(int fd));
  82. void   NDECL(background_on);
  83. void   FDECL(mapsock,(void FDECL((*func),(World *world))));
  84. World *NDECL(fworld);
  85. World *NDECL(xworld);
  86. int    FDECL(connect_to,(World *w, int autologin));
  87. void   FDECL(disconnect,(char *args));
  88. void   FDECL(movesock,(int dir));
  89. void   NDECL(disconnect_all);
  90. void   NDECL(listsockets);
  91. void   FDECL(world_output,(World *w, char *str, int attrs));
  92. void   FDECL(check_command,(int keyboard, Stringp str));
  93. void   FDECL(transmit,(char *s, int l));
  94. void   NDECL(clear_refresh_pending);
  95. void   NDECL(set_refresh_pending);
  96. int    NDECL(is_refresh_pending);
  97. void   NDECL(set_done);
  98.  
  99. #define CONN_WAIT 500000
  100. #ifndef LP_UWAIT
  101. #define LP_UWAIT 250000
  102. #endif
  103. #ifndef LP_SWAIT
  104. #define LP_SWAIT 0
  105. #endif
  106. #ifndef PROC_WAIT
  107. #define PROC_WAIT 100000
  108. #endif
  109. #ifndef REFRESH_TIME
  110. #define REFRESH_TIME 250000
  111. #endif
  112.  
  113. extern int lpflag, quitdone, bamf, borg, hilite, gag, quiet;
  114. extern int sockmload, lpquote;
  115. extern int login;                       /* Auto-logins enabled? */
  116. extern int background;                  /* background processing enabled? */
  117. extern int input_cursor;                /* is cursor in input window? */
  118. extern TIME_T proctime;                 /* when next process should run */
  119.  
  120. static fd_set readers;                  /* file descriptors we're watching */
  121. static fd_set active;                   /* active file descriptors */
  122. static int nfds;                        /* max # of readers */
  123. static Sock *hsock = NULL;              /* head of socket list */
  124. static Sock *tsock = NULL;              /* tail of socket list */
  125. static int done = FALSE;                /* Are we all done? */
  126. static int need_refresh;                /* Does input line need refresh? */
  127. static int dead_sock_pending = 0;       /* Number of unnuked dead sockets */
  128.  
  129. Sock *fsock = NULL;                     /* foreground socket */
  130. Sock *xsock = NULL;                     /* current (transmission) socket */
  131. int active_count = 0;                   /* # of (non-current) active sockets */
  132.  
  133. void main_loop(initial_world, autologin)
  134.     World *initial_world;
  135.     int autologin;
  136. {
  137.     int count;
  138.     struct timeval tv, *tvp;
  139.     TIME_T now, earliest, mailtime = 0;
  140.     Sock *sock;
  141.  
  142.     FD_ZERO(&readers);
  143.     FD_ZERO(&active);
  144.     FD_SET(0, &readers);
  145.     nfds = 1;
  146.     if (initial_world != NULL) connect_to(initial_world, autologin);
  147.  
  148.     while (!done) {
  149.         now = (TIME_T)time(NULL);
  150.         if (!lpquote && now >= proctime) runall(now);
  151.         earliest = proctime;
  152.         if (need_refresh || !input_cursor) {
  153.             tvp = &tv;
  154.             tv.tv_sec = 0;
  155.             tv.tv_usec = REFRESH_TIME;
  156.         } else if (earliest) {
  157.             tvp = &tv;
  158.             tv.tv_sec = earliest - now;
  159.             tv.tv_usec = 0;
  160.             if (tv.tv_sec <= 0) {
  161.                 tv.tv_sec = 0;
  162.             } else if (tv.tv_sec == 1) {
  163.                 tv.tv_sec = 0;
  164.                 tv.tv_usec = PROC_WAIT;
  165.             }
  166.         } else tvp = NULL;
  167.  
  168.         active = readers;
  169.         count = select(nfds, &active, NULL, NULL, tvp);
  170.  
  171.         if (count == -1) {
  172.             if (errno != EINTR) {
  173.                 operror("TF/main_loop/select");
  174.                 die("% Failed select");
  175.             }
  176.         } else if (count == 0) {
  177.             if (need_refresh) do_line_refresh();
  178.             else if (!input_cursor) ipos();
  179.         } else {
  180.             if (FD_ISSET(0, &active)) {
  181.                 count--;
  182.                 if (need_refresh) do_line_refresh();
  183.                 else if (!input_cursor) ipos();
  184.                 handle_keyboard_input();
  185.             }
  186.             if (count && fsock && FD_ISSET(fsock->fd, &active)) {
  187.                 count--;
  188.                 handle_socket_input(fsock);
  189.                 FD_CLR(fsock->fd, &active);
  190.             }
  191.             for (sock = hsock; count && sock; sock = sock->next) {
  192.                 if (FD_ISSET(sock->fd, &active)) {
  193.                     count--;
  194.                     if (sock->flags & SOCKPENDING) {
  195.                         establish(sock);
  196.                     } else {
  197.                         if (background) {
  198.                             handle_socket_input(xsock = sock);
  199.                             xsock = fsock;
  200.                         } else FD_CLR(sock->fd, &readers);
  201.                     }
  202.                 }
  203.             }
  204.         }
  205.         process_signals();
  206.         if (dead_sock_pending) nuke_dead_socks();
  207.     } 
  208.     cleanup();
  209. #ifdef DMALLOC
  210.     handle_purge_command("-i *");
  211.     purge_world("*");
  212.     free_keyboard();
  213.     free_prefixes();
  214.     free_histories();
  215.     free_term();
  216.     debug_mstats("tf");
  217. #endif
  218. }
  219.  
  220. int is_active(fd)
  221.     int fd;
  222. {
  223.     return FD_ISSET(fd, &active);
  224. }
  225.  
  226. void readers_clear(fd)
  227.     int fd;
  228. {
  229.     FD_CLR(fd, &readers);
  230. }
  231.  
  232. void readers_set(fd)
  233.     int fd;
  234. {
  235.     FD_SET(fd, &readers);
  236.     if (fd >= nfds) nfds = fd + 1;
  237. }
  238.  
  239. /* find open socket to world <name> */
  240. static Sock *find_sock(name)
  241.     char *name;
  242. {
  243.     Sock *sock;
  244.  
  245.     for (sock = hsock; sock; sock = sock->next) {
  246.         if (sock->flags & (SOCKDEAD | SOCKPENDING)) continue;
  247.         if (!name || cstrcmp(sock->world->name, name) == 0) break;
  248.     }
  249.     return sock;
  250. }
  251.  
  252. void background_on()
  253. {
  254.     Sock *sock;
  255.     for (sock = hsock; sock; sock = sock->next)
  256.         if (!(sock->flags & (SOCKDEAD | SOCKPENDING)))
  257.             FD_SET(sock->fd, &readers);
  258. }
  259.  
  260. /* Perform (*func)(world) on every open world */
  261. void mapsock(func)
  262.     void FDECL((*func),(World *world));
  263. {
  264.     Sock *sock;
  265.  
  266.     for (sock = hsock; sock; sock = sock->next)
  267.         if (!(sock->flags & (SOCKDEAD | SOCKPENDING))) (*func)(sock->world);
  268. }
  269.  
  270. World *fworld()
  271. {
  272.     return fsock ? fsock->world : NULL;
  273. }
  274.  
  275. World *xworld()
  276. {
  277.     return xsock ? xsock->world : NULL;
  278. }
  279.   
  280. static void wload(w)
  281.     World *w;
  282. {
  283.     World *d;
  284.  
  285.     if (*w->mfile) do_file_load(w->mfile);
  286.     else if ((d = get_default_world()) != NULL && *d->mfile)
  287.         do_file_load(d->mfile);
  288. }
  289.  
  290. static void announce_world(s)
  291.     Sock *s;
  292. {
  293.     put_world(s ? s->world->name : NULL);
  294.     if (!s)
  295.         do_hook(H_WORLD, "---- No world ----", "");
  296.     else if (s->flags & SOCKDEAD)
  297.         do_hook(H_WORLD, "---- World %s (dead) ----", "%s", s->world->name);
  298.     else do_hook(H_WORLD, "---- World %s ----", "%s", s->world->name);
  299. }
  300.  
  301. static void bg_sock()
  302. {
  303.     /* if (!fsock) return; */
  304. }
  305.  
  306. static void fg_sock(new)
  307.     Sock *new;
  308. {
  309.     if (new) {
  310.         FD_SET(new->fd, &readers);
  311.         if (new->flags & SOCKACTIVE) put_active(--active_count);
  312.         new->flags &= ~SOCKACTIVE;
  313.         announce_world(new);
  314.         flush_world(new->world);
  315. #ifndef OLD_LPPROMPTS
  316.         if (lpflag) {
  317.             if (new->current_output->len) setprompt(new->current_output->s);
  318.             Stringterm(new->current_output, 0);
  319.         }
  320. #endif
  321.         if (new->flags & SOCKDEAD) {
  322.             nukesock(new);
  323.             fsock = xsock = NULL;
  324.             any_sock();
  325.         } else xsock = fsock = new;
  326.     } else announce_world(NULL);
  327. }
  328.  
  329. int connect_to(w, autologin)                    /* initiate a connection. */
  330.     World *w;
  331.     int autologin;
  332. {
  333.     int fd, count, tfcerrno = TFC_OK;
  334.     FILE *fp;
  335.     Sock *sock;
  336.     struct timeval tv;
  337.     fd_set pending;
  338. #ifndef CONNECT
  339.     struct sockaddr_in addr;
  340. #endif
  341.  
  342.     for (sock = hsock; sock != NULL; sock = sock->next) {
  343.         if (sock->world == w &&
  344.           (!(sock->flags & SOCKDEAD) || sock->flags & SOCKACTIVE)) {
  345.             if (sock == fsock) return 1;
  346.             if (sock->flags & SOCKPENDING) {
  347.                 oputs("% Connection already in progress.");
  348.                 return 0;  /* ??? */
  349.             }
  350.             bg_sock();
  351.             fg_sock(sock);
  352.             if (sock == fsock && sockmload) wload(sock->world);
  353.             return 1;
  354.         }
  355.     }
  356.  
  357. #ifdef CONNECT
  358.     fd = nb_connect(w->address, w->port, &fp, &tfcerrno);
  359. #else
  360.     fd = open_sock(w->address, w->port, &addr, &tfcerrno);
  361. #endif
  362.     if (fd < 0) {
  363.         do_hook(H_CONFAIL, "%% Connection to %s failed: %s: %s", "%s %s: %s",
  364.             w->name, TFCERROR(tfcerrno),
  365.             tfcerrno == TFC_CANT_FIND ? w->address : STRERROR(errno));
  366.         return 0;
  367.     }
  368. #ifndef CONNECT
  369.     if (connect(fd, &addr, sizeof(struct sockaddr_in)) < 0) {
  370.         close(fd);
  371.         do_hook(H_CONFAIL, "%% Connection to %s failed: %s: %s", "%s %s: %s",
  372.             w->name, TFCERROR(TFC_ECONNECT),
  373.             tfcerrno == TFC_CANT_FIND ? w->address : STRERROR(errno));
  374.         return 0;
  375.     }
  376. #endif
  377.     if (fd >= nfds) nfds = fd + 1;
  378.     FD_SET(fd, &readers);
  379.     sock = (Sock *) MALLOC(sizeof(struct Sock));
  380.     if (hsock == NULL) {
  381.         sock->prev = NULL;
  382.         tsock = hsock = sock;
  383.     } else {
  384.         sock->prev = tsock;
  385.         tsock = tsock->next = sock;
  386.     }
  387.     sock->fd = fd;
  388.     sock->flags = (autologin ? SOCKLOGIN : 0);
  389.     sock->world = w;
  390.     sock->world->socket = sock;
  391.     Stringinit(sock->current_output);
  392.     sock->next = NULL;
  393. #ifdef CONNECT
  394.     sock->flags |= SOCKPENDING;
  395.     sock->fp = fp;
  396.     FD_SET(fd, &pending);
  397.     tv.tv_sec = 0;
  398.     tv.tv_usec = CONN_WAIT;                /* give it a chance */
  399.     count = select(fd + 1, &pending, NULL, NULL, &tv);
  400.     if (count == 1) {
  401.         return establish(sock);
  402.     } else {
  403.         do_hook(H_PENDING, "% Connection to %s in progress.", "%s",
  404.             sock->world->name);
  405.         return 1;  /* ??? */
  406.     }
  407. #else
  408.     return establish(sock);
  409. #endif
  410. }
  411.  
  412. static int establish(sock)     /* establish a pending connection */
  413.     Sock *sock;
  414. {
  415.     int fd;
  416.  
  417. #ifdef CONNECT
  418.     int tfcerrno;
  419.  
  420.     sock->flags &= ~SOCKPENDING;
  421.     FD_CLR(sock->fd, &readers);
  422.     pclose(sock->fp);                /* Let child die.  We don't need status. */
  423.     if (sock->flags & SOCKDEAD) {    /* Sock was killed already. Nuke it now. */
  424.         nukesock(sock);
  425.         return 0;
  426.     }
  427.     fd = recvfd(sock->fd, &tfcerrno);
  428.     if (fd < 0) {
  429.         do_hook(H_CONFAIL, "%% Connection to %s failed: %s: %s", "%s %s: %s",
  430.             sock->world->name, TFCERROR(tfcerrno),
  431.             tfcerrno == TFC_CANT_FIND ? sock->world->address : STRERROR(errno));
  432.         killsock(sock);
  433.         return 0;
  434.     }
  435.     close(sock->fd);
  436.     sock->fd = fd;
  437.     if (fd >= nfds) nfds = fd + 1;
  438.     FD_SET(fd, &readers);
  439. #endif
  440.     sock->quiet = quiet ? MAXQUIET : 0;
  441.     /* skip any old undisplayed lines */
  442.     sock->world->history->index = sock->world->history->pos;
  443.     bg_sock();
  444.     fg_sock(sock);
  445.     wload(fsock->world);
  446.     do_hook(H_CONNECT, NULL, "%s", fsock->world->name);
  447.     magic_login();
  448.     return 1;
  449. }
  450.  
  451. void movesock(dir)
  452.     int dir;
  453. {
  454.     Sock *sock, *stop;
  455.  
  456.     reset_outcount();
  457.     if (fsock == NULL) return;
  458.     stop = sock = fsock;
  459.     do {
  460.         if (dir > 0) sock = sock && sock->next ? sock->next : hsock;
  461.         else sock = sock && sock->prev ? sock->prev : tsock;
  462.     } while ((sock->flags & SOCKPENDING) && sock != stop);
  463.     if (sock == fsock) return;
  464.     bg_sock();
  465.     fg_sock(sock);
  466.     if (sockmload) wload(fsock->world);
  467. }
  468.  
  469. static void killsock(sock)
  470.     Sock *sock;
  471. {
  472.     sock->flags |= SOCKDEAD;
  473.     dead_sock_pending++;
  474. }
  475.  
  476. static void nukesock(sock)
  477.     Sock *sock;
  478. {
  479.     sock->world->socket = NULL;
  480.     if (sock->flags & SOCKPENDING) return;
  481.     if (sock->world->flags & WORLD_TEMP) {
  482.         nuke_world(sock->world);
  483.         sock->world = NULL;
  484.     }
  485.     if (sock == hsock) hsock = sock->next;
  486.     else sock->prev->next = sock->next;
  487.     if (sock == tsock) tsock = sock->prev;
  488.     else sock->next->prev = sock->prev; dead_sock_pending--;
  489.     FD_CLR(sock->fd, &readers);
  490.     close(sock->fd);
  491.     if (sock->flags & SOCKACTIVE) put_active(--active_count);
  492.     Stringfree(sock->current_output);
  493.     FREE(sock);
  494. }
  495.  
  496. static void nuke_dead_socks()
  497. {
  498.     Sock *sock, *next;
  499.     int reconnect = FALSE;
  500.  
  501.     if (fsock && (fsock->flags & SOCKDEAD)) {
  502.         xsock = fsock = NULL;
  503.         reconnect = TRUE;
  504.     }
  505.     for (sock = hsock; sock; sock = next) {
  506.         next = sock->next;
  507.         if (sock->flags & SOCKDEAD) {
  508.             if (sock->flags & SOCKACTIVE) FD_CLR(sock->fd, &readers);
  509.             else nukesock(sock);
  510.         }
  511.     }
  512.     if (quitdone && !hsock) done = 1;
  513.     else if (reconnect) any_sock();
  514. }
  515.  
  516. static void any_sock()
  517. {
  518.     Sock *sock;
  519.  
  520.     if (sock = find_sock(NULL)) {
  521.         fg_sock(sock);
  522.         if (sockmload) wload(fsock->world);
  523.     } else announce_world(NULL);
  524. }
  525.  
  526. void disconnect_all()
  527. {
  528.     Sock *sock, *next;
  529.  
  530.     for (sock = hsock; sock; sock = next) {
  531.         next = sock->next;
  532.         nukesock(sock);
  533.     }
  534.     hsock = tsock = xsock = fsock = NULL;
  535.     if (quitdone) done = 1;
  536. }
  537.  
  538. void disconnect(args)
  539.     char *args;
  540. {
  541.     Sock *s;
  542.  
  543.     if (!*args) {
  544.         if (fsock) killsock(fsock);
  545.     } else if (cstrcmp(args, "-all") == 0) {
  546.         if (hsock) {
  547.             disconnect_all();
  548.             announce_world(NULL);
  549.         }
  550.     } else {
  551.         for (s = hsock; s; s = s->next) {
  552.             if (cstrcmp(s->world->name, args) == 0 && !(s->flags & SOCKDEAD))
  553.                 break;
  554.         }
  555.         if (s) {
  556.             oprintf ("%% Connection to %s closed.", s->world->name);
  557.             killsock(s);
  558.         } else oprintf("%% Not connected to %s", args);
  559.     }
  560. }
  561.  
  562. void listsockets()
  563. {
  564.     Sock *sock;
  565.     char *state, buffer[81];
  566.     int defunct;
  567.  
  568.     if (hsock == NULL) {
  569.         oputs("% Not connected to any sockets.");
  570.         return;
  571.     }
  572.  
  573.     for (sock = hsock; sock != NULL; sock = sock->next) {
  574.         defunct = (sock->flags & SOCKPENDING) && (sock->flags & SOCKDEAD);
  575.         if (sock == xsock) state = "current";
  576.         else if (defunct) state = "defunct";
  577.         else if (sock->flags & SOCKPENDING) state = "pending";
  578.         else if (sock->flags & SOCKDEAD) state = "dead";
  579.         else if (sock->flags & SOCKACTIVE) state = "active";
  580.         else state = "idle";
  581.         sprintf(buffer, "%% [%7s]  %15s %30s %s", state,
  582.             sock->world->name, sock->world->address, sock->world->port);
  583.         oputs(buffer);
  584.     }
  585. }
  586.  
  587. void background_hook(line)
  588.     char *line;
  589. {
  590.     if (xsock == fsock || background > 1) return;
  591.     do_hook(H_BACKGROUND, "%% Trigger in world %s", "%s %s",
  592.         xsock->world->name, line);
  593. }
  594.  
  595. void do_send(args)
  596.     char *args;
  597. {
  598.     Sock *save = xsock, *sock = xsock;
  599.     int len = -1, opt, Wflag = FALSE;
  600.  
  601.     if (!hsock) {
  602.         oputs("% Not connected to any sockets.");
  603.         return;
  604.     }
  605.     startopt(args, "w:W");
  606.     while (opt = nextopt(&args, NULL)) {
  607.         switch (opt) {
  608.         case 'w':
  609.             if (*args) {
  610.                 if (!(sock = find_sock(args))) {
  611.                     oprintf("%% Not connected to %s", args);
  612.                     return;
  613.                 }
  614.             } else sock = xsock;
  615.             break;
  616.         case 'W':
  617.             Wflag = TRUE;
  618.             break;
  619.         default:
  620.             return;
  621.         }
  622.     }
  623.     
  624.     args[len = strlen(args)] = '\n';            /* be careful */
  625.     if (Wflag) {
  626.         for (xsock = hsock; xsock; xsock = xsock->next) transmit(args, len + 1);
  627.     } else {
  628.         xsock = sock;
  629.         transmit(args, len + 1);
  630.     }
  631.     if (len >= 0) args[len] = '\0';    /* restore end of string */
  632.     xsock = save;
  633. }
  634.  
  635. void transmit(str, numtowrite)
  636.     char *str;
  637.     int numtowrite;
  638. {
  639.     int numwritten;
  640.  
  641.     if (!xsock || xsock->flags & (SOCKDEAD | SOCKPENDING)) return;
  642.     while (numtowrite) {
  643.         numwritten = send(xsock->fd, str, numtowrite, 0);
  644.         if (numwritten == -1) {
  645.             if (errno == EWOULDBLOCK) numwritten = 0;
  646.             else {
  647.                 do_hook(H_DISCONNECT,
  648.                     "%% Connection to %s closed by foreign host: %s",
  649.                     "%s %s", xsock->world->name, STRERROR(errno));
  650.                 killsock(xsock);
  651.                 return;
  652.             }
  653.         }
  654.         numtowrite -= numwritten;
  655.         str += numwritten;
  656.         if (numtowrite) sleep(1);
  657.     }
  658. }
  659.  
  660. void check_command(keyboard, str)
  661.     int keyboard;
  662.     Stringp str;
  663. {
  664.     if (str->s[0] == '/' && str->s[1] != '/') {
  665.         newline_package(str, 0);
  666.         handle_command(str->s, NULL);
  667.     } else if (str->s[0] == '/') {
  668.         newline_package(str, 1);
  669.         transmit(str->s + 1, str->len - 1);
  670.     } else if (!keyboard || !(do_hook(H_SEND, NULL, "%S", str) & F_GAG)) {
  671.         newline_package(str, 1);
  672.         transmit(str->s, str->len);
  673.     }
  674. }
  675.  
  676. static int receive(sock, str)
  677.     Sock *sock;
  678.     Stringp str;
  679. {
  680.     int count;
  681.     char block[513];
  682.     struct timeval tv;
  683.     fd_set readfds;
  684.  
  685.     FD_ZERO(&readfds);
  686.     FD_SET(sock->fd, &readfds);
  687. #ifndef OLD_LPPROMPTS
  688.     if (lpflag) {
  689.         tv.tv_sec = LP_SWAIT;
  690.         tv.tv_usec = LP_UWAIT;
  691.     } else
  692. #endif
  693.         tv.tv_sec = tv.tv_usec = 0;
  694.     while ((count = select(sock->fd + 1, &readfds, NULL, NULL, &tv)) == -1)
  695.         if (errno != EINTR) {
  696.             operror("TF/receive/select");
  697.             die("% Failed select");
  698.         }
  699.     if (count == 0) return 0;
  700.     do count = recv(sock->fd, block, 512, 0);
  701.         while (count == -1 && errno == EINTR);
  702.     if (count == -1) {
  703.         operror("% recv failed");
  704.         block[0] = '\0';
  705.     } else block[count] = '\0';
  706.     if (count <= 0) {
  707.         flush_output(sock);
  708.         do_hook(H_DISCONNECT, "%% Connection to %s closed.",
  709.             "%s", sock->world->name);
  710.         killsock(sock);
  711.         return -1;
  712.     }
  713.     if (str) Stringcpy(str, block);
  714.     return count;
  715. }
  716.  
  717. static void magic_login()
  718. {
  719.     World *w;
  720.  
  721.     if (!(login && fsock->flags & SOCKLOGIN)) return;
  722.     w = (*fsock->world->character) ? fsock->world : get_default_world();
  723.     if (!w) return;
  724.     if (!*w->character) return;
  725.     do_hook(H_LOGIN, NULL, "%s %s %s", w->name, w->character, w->pass);
  726. }
  727.  
  728. void clear_refresh_pending()
  729. {
  730.     need_refresh = 0;
  731. }
  732.  
  733. void set_refresh_pending()
  734. {
  735.     need_refresh = 1;
  736. }
  737.  
  738. int is_refresh_pending()
  739. {
  740.     return need_refresh;
  741. }
  742.  
  743. static void process_socket_input(sock, out)
  744.     Sock *sock;
  745.     Stringp out;
  746. {
  747.     int len = out->len;
  748.     short attrs = F_NORM;
  749.  
  750.     if (len && out->s[len - 1] == '\r') {
  751.         while (--len && out->s[len - 1] == '\r');
  752.         Stringterm(out, len);
  753.     }
  754.     attrs = special_hook(sock->world->history, out->s, &sock->quiet);
  755.     world_output(sock->world, out->s, attrs);
  756. }
  757.  
  758. void world_output(w, str, attrs)
  759.     World *w;
  760.     char *str;
  761.     int attrs;
  762. {
  763.     Aline *aline;
  764.  
  765.     if (gag && (attrs & F_GAG) && (attrs & F_NORECORD) && !w->history->logfile)
  766.         return;
  767.     aline = new_aline(str, attrs | F_NEWLINE);
  768.     record_world(w->history, aline);
  769.     if (!(gag && (attrs & F_GAG))) {
  770.         if (w == fsock->world) {
  771. #if 0
  772.             flush_world(w);
  773. #endif
  774.             localoutput(aline);
  775.         } else {
  776.             enqueue(w->queue, aline);
  777.             if (!(w->socket->flags & SOCKACTIVE)) {
  778.                 w->socket->flags |= SOCKACTIVE;
  779.                 put_active(++active_count);
  780.                 do_hook(H_ACTIVITY, "%% Activity in world %s", "%s", w->name);
  781.             }
  782.         }
  783.     }
  784. }
  785.  
  786. static void handle_socket_input(sock)
  787.     Sock *sock;
  788. {
  789.     static Stringp in, temp, out;
  790.     static int strings_inited = FALSE;
  791.     char *place;
  792.  
  793.     if (!strings_inited) {
  794.         Stringinit(in);
  795.         Stringinit(temp);
  796.         Stringinit(out);
  797.         strings_inited = TRUE;
  798.     }
  799.  
  800.     while (receive(sock, in) > 0) {
  801.         SStringcat(sock->current_output, in);
  802.         while ((place = strchr(sock->current_output->s, '\n')) != NULL) {
  803.             Stringncpy(out, sock->current_output->s,
  804.                 place - sock->current_output->s);
  805.             Stringncpy(temp, place + 1,
  806.                 sock->current_output->s + sock->current_output->len - place);
  807.             process_socket_input(sock, out);
  808.             SStringcpy(sock->current_output, temp);
  809.             if (history_full(sock->world->history)) return;
  810.         }
  811.     }
  812.     if (lpflag && sock->current_output->len) {
  813.         if (lpquote) runall(time(NULL));
  814.         if (borg || hilite || gag) check_trigger(sock->current_output->s);
  815. #ifndef OLD_LPPROMPTS
  816.         if (sock == fsock) {
  817.             setprompt(sock->current_output->s);
  818.             Stringterm(sock->current_output, 0);
  819.         }
  820. #else
  821.         process_socket_input(sock, sock->current_output);
  822.         Stringterm(sock->current_output, 0);
  823. #endif
  824.     }
  825. }
  826.  
  827. static void flush_output(sock)
  828.     Sock *sock;
  829. {
  830.     if (sock->current_output->len) {
  831.         process_socket_input(sock, sock->current_output);
  832.         Stringterm(sock->current_output, 0);
  833.     }
  834.     setprompt("");
  835. }
  836.  
  837. void set_done()
  838. {
  839.     done = TRUE;
  840. }
  841.  
  842. #ifdef CONNECT
  843. static int recvfd(sockfd, flag)
  844.     int sockfd, *flag;
  845. {
  846. #ifdef CONNECT_SVR4
  847.     struct strrecvfd rfd;
  848.  
  849.     if (ioctl(sockfd, I_RECVFD, (char*)&rfd) < 0) {
  850.         *flag = TFC_ERECV;
  851.     } else return rfd.fd;
  852.     return -1;
  853. #else
  854.     struct iovec iov[1];
  855.     struct msghdr msg;
  856.     int fd, error;
  857.  
  858.     if ((recv(sockfd, flag, sizeof(*flag), 0)) < 0) {
  859.         *flag = TFC_ERECV;
  860.     } else if (*flag == TFC_OK) {
  861.         iov[0].iov_base = NULL;
  862.         iov[0].iov_len = 0;
  863.         msg.msg_name = NULL;
  864.         msg.msg_namelen = 0;
  865.         msg.msg_iov = iov;
  866.         msg.msg_iovlen = 1;
  867.         msg.msg_accrights = (char*) &fd;
  868.         msg.msg_accrightslen = sizeof(fd);
  869.         if (recvmsg(sockfd, &msg, 0) >= 0) return fd;
  870.         *flag = TFC_ERECVMSG;
  871.     } else {
  872.         if ((recv(sockfd, &error, sizeof(error), 0)) < 0) *flag = TFC_ERECV;
  873.         errno = error;
  874.     }
  875.     return -1;
  876. #endif
  877. }
  878.  
  879. /*
  880.  * nb_connect simulates a non-blocking connect() by forking a child to
  881.  * do the actual connect().  The child sends the connected file descriptor
  882.  * or error code back to the parent through a stream pipe when done.
  883.  * The parent reads the fd/error from the pipe when the pipe selects
  884.  * true for reading.  popen() and pclose() provide a portable way of
  885.  * wait()ing for the child (we don't use the pipe it creates).
  886.  */
  887.  
  888. static int nb_connect(address, port, fpp, tfcerrnop)
  889.     char *address, *port;
  890.     FILE **fpp;
  891.     int *tfcerrnop;
  892. {
  893.     int sv[2];
  894.     struct stat statbuf;
  895.     STATIC_BUFFER(cmd);
  896.  
  897.     *tfcerrnop = TFC_ESTAT;
  898.     if (stat(TFCONNECT, &statbuf) == -1) return -1;
  899. #ifdef CONNECT_SVR4
  900.     *tfcerrnop = TFC_EPIPE;
  901.     if (pipe(sv) < 0) return -1;
  902. #else
  903.     *tfcerrnop = TFC_ESOCKETPAIR;
  904.     if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) return -1;
  905. #endif
  906.     Sprintf(cmd, "%s %s %s %d", TFCONNECT, address, port, sv[0]);
  907.     *tfcerrnop = TFC_EPOPEN;
  908.     if ((*fpp = popen(cmd->s, "w")) == NULL) return -1;
  909.     close(sv[0]);                     /* parent doesn't need this */
  910.     *tfcerrnop = TFC_OK;
  911.     return sv[1];
  912. }
  913. #endif /* CONNECT */
  914.  
  915.