home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NETKIT-A.06 / NETKIT-A / NetKit-A-0.06 / ytalk-3.0.1 / comm.c next >
Encoding:
C/C++ Source or Header  |  1993-09-27  |  27.9 KB  |  1,358 lines

  1. /* comm.c -- firewall between socket and terminal I/O */
  2.  
  3. /*               NOTICE
  4.  *
  5.  * Copyright (c) 1990,1992,1993 Britt Yenne.  All rights reserved.
  6.  * 
  7.  * This software is provided AS-IS.  The author gives no warranty,
  8.  * real or assumed, and takes no responsibility whatsoever for any 
  9.  * use or misuse of this software, or any damage created by its use
  10.  * or misuse.
  11.  * 
  12.  * This software may be freely copied and distributed provided that
  13.  * no part of this NOTICE is deleted or edited in any manner.
  14.  * 
  15.  */
  16.  
  17. /* Mail comments or questions to ytalk@austin.eds.com */
  18.  
  19. #include "header.h"
  20. #include "socket.h"
  21. #include "menu.h"
  22. #include <sys/uio.h>
  23.  
  24. ychar *io_ptr;        /* user input pointer */
  25. int    io_len = 0;    /* user input count */
  26.  
  27. extern int input_flag;    /* see fd.c */
  28.  
  29. /* ---- local functions ---- */
  30.  
  31. static y_parm parm;
  32. static v2_pack v2p;
  33. static v3_pack v3p;
  34. static v3_flags v3f;
  35. static v3_winch v3w;
  36.  
  37. /* Set up a drain of out-of-band data.
  38.  */
  39. static void
  40. drain_user(user, len, func)
  41.   yuser *user;
  42.   int len;
  43.   void (*func)();
  44. {
  45.     if(len > user->dbuf_size)
  46.     {
  47.     user->dbuf_size = len + 64;
  48.     user->dbuf = (ychar *)realloc_mem(user->dbuf, user->dbuf_size);
  49.     }
  50.     user->drain = len;
  51.     user->dptr = user->dbuf;
  52.     user->dfunc = func;
  53. }
  54.  
  55. /* Send out-of-band data.
  56.  */
  57. static void
  58. send_oob(fd, ptr, len)
  59.   int fd;
  60.   yaddr ptr;
  61.   int len;
  62. {
  63.     ychar oob, size;
  64.     static struct iovec iov[3];
  65.  
  66.     if(len <= 0 || len > V3_MAXPACK)
  67.     {
  68.     errno = 0;
  69.     show_error("send_oob: packet too large");
  70.     return;
  71.     }
  72.  
  73.     oob = V3_OOB;
  74.     iov[0].iov_base = (yaddr)(&oob);
  75.     iov[0].iov_len = 1;
  76.  
  77.     size = len;
  78.     iov[1].iov_base = (yaddr)(&size);
  79.     iov[1].iov_len = 1;
  80.  
  81.     iov[2].iov_base = ptr;
  82.     iov[2].iov_len = len;
  83.  
  84.     if(writev(fd, iov, 3) != len + 2)
  85.     show_error("send_oob: write failed");
  86. }
  87.  
  88. /* Ask another ytalk connection if he wants to import a user I've
  89.  * just now connected to.
  90.  */
  91. static void
  92. send_import(to, from)
  93.   yuser *to, *from;
  94. {
  95.     if(to->remote.vmajor > 2)
  96.     {
  97.     v3p.code = V3_IMPORT;
  98.     v3p.host_addr = htonl(from->host_addr);
  99.     v3p.pid = htonl(from->remote.pid);
  100.     strncpy(v3p.name, from->user_name, V3_NAMELEN);
  101.     strncpy(v3p.host, from->host_name, V3_HOSTLEN);
  102.     send_oob(to->fd, &v3p, V3_PACKLEN);
  103.     }
  104.     else if(to->remote.vmajor == 2)
  105.     {
  106.     v2p.code = V2_IMPORT;
  107.     strncpy(v2p.name, from->user_name, V2_NAMELEN);
  108.     strncpy(v2p.host, from->host_name, V2_HOSTLEN);
  109.     (void)write(to->fd, &v2p, V2_PACKLEN);
  110.     }
  111. }
  112.  
  113. /* Tell another ytalk connection to connect to a user.
  114.  */
  115. static void
  116. send_accept(to, from)
  117.   yuser *to, *from;
  118. {
  119.     if(to->remote.vmajor > 2)
  120.     {
  121.     v3p.code = V3_ACCEPT;
  122.     v3p.host_addr = htonl(from->host_addr);
  123.     v3p.pid = htonl(from->remote.pid);
  124.     strncpy(v3p.name, from->user_name, V3_NAMELEN);
  125.     strncpy(v3p.host, from->host_name, V3_HOSTLEN);
  126.     send_oob(to->fd, &v3p, V3_PACKLEN);
  127.     }
  128.     else if(to->remote.vmajor == 2)
  129.     {
  130.     v2p.code = V2_ACCEPT;
  131.     strncpy(v2p.name, from->user_name, V2_NAMELEN);
  132.     strncpy(v2p.host, from->host_name, V2_HOSTLEN);
  133.     (void)write(to->fd, &v2p, V2_PACKLEN);
  134.     }
  135. }
  136.  
  137. /* Process a Ytalk version 2.? data packet.
  138.  */
  139. static void
  140. v2_process(user, pack)
  141.   yuser *user;
  142.   v2_pack *pack;
  143. {
  144.     register yuser *u;
  145.     ylong host_addr;
  146.     static char name[V2_NAMELEN + 1];
  147.     static char host[V2_HOSTLEN + 1];
  148.     static char estr[V2_NAMELEN + V2_HOSTLEN + 20];
  149.  
  150.     /* Ytalk version 2.* didn't have very clever import/export
  151.      * capabilities.  We'll just go with the flow.
  152.      */
  153.     strncpy(name, pack->name, V2_NAMELEN);
  154.     strncpy(host, pack->host, V2_HOSTLEN);
  155.     name[V2_NAMELEN] = '\0';
  156.     host[V2_HOSTLEN] = '\0';
  157.     if((host_addr = get_host_addr(host)) == (ylong)-1)
  158.     {
  159.     errno = 0;
  160.     sprintf(errstr, "unknown host: '%s'\n", host);
  161.     show_error(errstr);
  162.     show_error("port from ytalk V2.? failed");
  163.     return;
  164.     }
  165.     switch(pack->code)
  166.     {
  167.     case V2_IMPORT:
  168.         /* Don't import a user with the same name of an existing
  169.          * user at this end.  yukk.
  170.          */
  171.         if(find_user(name, host_addr, (ylong)-1) != NULL)
  172.         break;
  173.         if(!(def_flags & FL_IMPORT))
  174.         {
  175.         sprintf(estr, "Import %s@%s?", name, host);
  176.         if(yes_no(estr) == 'n')
  177.             break;
  178.         }
  179.  
  180.         /* invite him but don't ring him */
  181.  
  182.         sprintf(estr, "%s@%s", name, host);
  183.         invite(estr, 0);
  184.  
  185.         /* now tell him to connect to us */
  186.  
  187.         pack->code = V2_EXPORT;
  188.         (void)write(user->fd, pack, V2_PACKLEN);
  189.  
  190.         break;
  191.     case V2_EXPORT:
  192.         /* We don't need to check if he's not connected, since
  193.          * send_accept() will think his version number is zero
  194.          * and won't send anything.
  195.          */
  196.         if((u = find_user(name, host_addr, (ylong)-1)) == NULL)
  197.         break;
  198.         send_accept(u, user);
  199.         break;
  200.     case V2_ACCEPT:
  201.         sprintf(estr, "%s@%s", name, host);
  202.         invite(estr, 1);    /* we should be expected */
  203.         break;
  204.     }
  205. }
  206.  
  207. /* Process a Ytalk version 3.? data packet.
  208.  */
  209. static void
  210. v3_process_pack(user, pack)
  211.   yuser *user;
  212.   v3_pack *pack;
  213. {
  214.     register yuser *u;
  215.     ylong host_addr, pid;
  216.     static char name[V3_NAMELEN + 1];
  217.     static char host[V3_HOSTLEN + 1];
  218.     static char estr[V3_NAMELEN + V3_HOSTLEN + 20];
  219.  
  220.     strncpy(name, pack->name, V3_NAMELEN);
  221.     strncpy(host, pack->host, V3_HOSTLEN);
  222.     name[V3_NAMELEN] = '\0';
  223.     host[V3_HOSTLEN] = '\0';
  224.     if((host_addr = get_host_addr(host)) == (ylong)-1)
  225.     host_addr = ntohl(pack->host_addr);
  226.     pid = ntohl(pack->pid);
  227.  
  228.     switch(pack->code)
  229.     {
  230.     case V3_IMPORT:
  231.         /* Don't import a user which is already in this
  232.          * session.  This is defined as a user with a matching
  233.          * name, host address, and process id.
  234.          */
  235.         if(find_user(name, host_addr, pid) != NULL)
  236.         break;
  237.         if(!(def_flags & FL_IMPORT))
  238.         {
  239.         sprintf(estr, "Import %s@%s?", name, host);
  240.         if(yes_no(estr) == 'n')
  241.             break;
  242.         }
  243.  
  244.         /* invite him but don't ring him */
  245.  
  246.         sprintf(estr, "%s@%s", name, host);
  247.         invite(estr, 0);
  248.  
  249.         /* now tell him to connect to us */
  250.  
  251.         pack->code = V3_EXPORT;
  252.         send_oob(user->fd, pack, V3_PACKLEN);
  253.  
  254.         break;
  255.     case V3_EXPORT:
  256.         /* We don't need to check if he's not connected, since
  257.          * send_accept() will think his version number is zero
  258.          * and won't send anything.
  259.          */
  260.         if((u = find_user(name, host_addr, pid)) == NULL)
  261.         break;
  262.         send_accept(u, user);
  263.         break;
  264.     case V3_ACCEPT:
  265.         sprintf(estr, "%s@%s", name, host);
  266.         invite(estr, 1);    /* we should be expected */
  267.         break;
  268.     }
  269. }
  270.  
  271. /* Process a Ytalk version 3.? flags packet.  Other users can request
  272.  * that their flags be locked to a particular value until they unlock
  273.  * them later.
  274.  */
  275. static void
  276. v3_process_flags(user, pack)
  277.   yuser *user;
  278.   v3_flags *pack;
  279. {
  280.     switch(pack->code)
  281.     {
  282.     case V3_LOCKF:
  283.         user->flags = ntohl(pack->flags) | FL_LOCKED;
  284.         break;
  285.     case V3_UNLOCKF:
  286.         user->flags = def_flags;
  287.         break;
  288.     }
  289. }
  290.  
  291. /* Process a Ytalk version 3.? winch packet.
  292.  */
  293. static void
  294. v3_process_winch(user, pack)
  295.   yuser *user;
  296.   v3_winch *pack;
  297. {
  298.     switch(pack->code)
  299.     {
  300.     case V3_YOURWIN:
  301.         user->remote.my_rows = ntohs(pack->rows);
  302.         user->remote.my_cols = ntohs(pack->cols);
  303.         winch_exec();
  304.         break;
  305.     case V3_MYWIN:
  306.         user->remote.rows = ntohs(pack->rows);
  307.         user->remote.cols = ntohs(pack->cols);
  308.         break;
  309.     case V3_REGION:
  310.         pack->rows = ntohs(pack->rows);
  311.         pack->cols = ntohs(pack->cols);
  312.         if(pack->rows > 0)
  313.         set_win_region(user, (int)(pack->rows), (int)(pack->cols));
  314.         else
  315.         end_win_region(user);
  316.         break;
  317.     }
  318.     user_winch = 1;
  319. }
  320.  
  321. /* Process a Ytalk version 3.? out-of-band packet.  Call the appropriate
  322.  * function based on the type of packet.
  323.  */
  324. static void
  325. v3_process(user, ptr)
  326.   yuser *user;
  327.   yaddr ptr;
  328. {
  329.     ychar *str;
  330.  
  331.     /* ignore anything we don't understand */
  332.  
  333.     str = (ychar *)ptr;
  334.     switch(*str)
  335.     {
  336.     case V3_IMPORT:
  337.     case V3_EXPORT:
  338.     case V3_ACCEPT:
  339.         v3_process_pack(user, (v3_pack *)ptr);
  340.         break;
  341.     case V3_LOCKF:
  342.     case V3_UNLOCKF:
  343.         v3_process_flags(user, (v3_flags *)ptr);
  344.         break;
  345.     case V3_YOURWIN:
  346.     case V3_MYWIN:
  347.     case V3_REGION:
  348.         v3_process_winch(user, (v3_winch *)ptr);
  349.         break;
  350.     }
  351. }
  352.  
  353. /* Take input from a connected user.  If necessary, drain out-of-band
  354.  * data from the canonical input stream.
  355.  */
  356. static void
  357. read_user(fd)
  358.   int fd;
  359. {
  360.     register ychar *c, *p;
  361.     register int rc;
  362.     register yuser *user;
  363.     static ychar buf[512];
  364.  
  365.     if(input_flag)
  366.     {
  367.     /* tell input_loop() to ignore this function for now */
  368.     input_flag = 0;
  369.     return;
  370.     }
  371.     if((user = fd_to_user[fd]) == NULL)
  372.     {
  373.     remove_fd(fd);
  374.     show_error("read_user: unknown contact");
  375.     return;
  376.     }
  377.     if((rc = read(fd, buf, 512)) <= 0)
  378.     {
  379.     if(rc < 0)
  380.         show_error("read_user: read() failed");
  381.     free_user(user);
  382.     return;
  383.     }
  384.     c = buf;
  385.     while(rc > 0)
  386.     {
  387.     if(user->drain > 0)    /* there is still some OOB data to drain */
  388.     {
  389.         if(rc < user->drain)
  390.         {
  391.         (void)memcpy(user->dptr, c, rc);
  392.         user->dptr += rc;
  393.         user->drain -= rc;
  394.         rc = 0;
  395.         }
  396.         else
  397.         {
  398.         (void)memcpy(user->dptr, c, user->drain);
  399.         rc -= user->drain;
  400.         c += user->drain;
  401.         user->drain = 0;
  402.         user->dfunc(user, user->dbuf);
  403.         }
  404.     }
  405.     else
  406.     {
  407.         /* Ytalk version 3.0 Out-Of-Band data protocol:
  408.          *
  409.          *    If I receive a V3_OOB character, I look at the next
  410.          *    character.  If the next character is V3_OOB, then I
  411.          *    send one V3_OOB through transparently.  Else, the
  412.          *    next character is a packet length to be drained.
  413.          *    The packet length can never be V3_OOB because the
  414.          *    maximum out-of-band packet length is (V3_OOB - 1) bytes.
  415.          *    If any packet requires more information, then it can
  416.          *    always kick off another drain_user() inside v3_process().
  417.          */
  418.         p = buf;
  419.         if(user->got_oob)
  420.         {
  421.         user->got_oob = 0;
  422.         if(*c <= V3_MAXPACK)
  423.         {
  424.             drain_user(user, *c, v3_process);
  425.             c++, rc--;
  426.             continue;
  427.         }
  428.         *(p++) = *c;
  429.         c++, rc--;
  430.         }
  431.         for(; rc > 0; c++, rc--)
  432.         {
  433.         if(*c > 127)            /* could be inline data */
  434.         {
  435.             if(user->remote.vmajor > 2)        /* ytalk 3.0+ */
  436.             {
  437.             if(*c == V3_OOB)
  438.             {
  439.                 c++, rc--;
  440.                 if(rc > 0)
  441.                 {
  442.                 if(*c <= V3_MAXPACK)
  443.                 {
  444.                     drain_user(user, *c, v3_process);
  445.                     c++, rc--;
  446.                     break;
  447.                 }
  448.                 }
  449.                 else
  450.                 {
  451.                 user->got_oob = 1;
  452.                 break;
  453.                 }
  454.             }
  455.             }
  456.             else if(user->remote.vmajor == 2)    /* ytalk 2.0+ */
  457.             {
  458.             /* Version 2.* didn't support data transparency */
  459.  
  460.             if(*c == V2_IMPORT || *c == V2_EXPORT
  461.             || *c == V2_ACCEPT || *c == V2_AUTO)
  462.             {
  463.                 drain_user(user, V2_PACKLEN, v2_process);
  464.                 /* don't increment c or decrement rc -- they're
  465.                  * part of the drain.  :-)
  466.                  */
  467.                 break;
  468.             }
  469.             }
  470.         }
  471.         *(p++) = *c;
  472.         }
  473.         if(p > buf)
  474.         {
  475.         if(user->output_fd > 0)
  476.             if(write(user->output_fd, buf, p - buf) <= 0)
  477.             {
  478.             show_error("write to user output file failed");
  479.             close(user->output_fd);
  480.             user->output_fd = 0;
  481.             }
  482.         show_input(user, buf, p - buf);
  483.         }
  484.     }
  485.     }
  486. }
  487.  
  488. /* Initial Handshaking:  read the parameter pack from another ytalk user.
  489.  */
  490. static void
  491. ytalk_user(fd)
  492.   int fd;
  493. {
  494.     register yuser *user, *u;
  495.     u_short cols;
  496.  
  497.     if((user = fd_to_user[fd]) == NULL)
  498.     {
  499.     remove_fd(fd);
  500.     show_error("ytalk_user: unknown contact");
  501.     return;
  502.     }
  503.     if(full_read(user->fd, &parm, sizeof(y_parm)) < 0)
  504.     {
  505.     free_user(user);
  506.     show_error("ytalk_user: bad ytalk contact");
  507.     return;
  508.     }
  509.     switch(parm.protocol)
  510.     {
  511.     case YTP_OLD:
  512.         cols = parm.w_cols;
  513.         (void)memset(&parm, 0, sizeof(y_parm));
  514.         parm.vmajor = 2;
  515.         parm.cols = cols;
  516.         parm.my_cols = cols;
  517.         spew_term(me, fd, me->t_rows, parm.cols);
  518.         break;
  519.     case YTP_NEW:
  520.         parm.vmajor = ntohs(parm.vmajor);
  521.         parm.vminor = ntohs(parm.vminor);
  522.         parm.rows = ntohs(parm.rows);
  523.         parm.cols = ntohs(parm.cols);
  524.         parm.my_rows = ntohs(parm.my_rows);
  525.         parm.my_cols = ntohs(parm.my_cols);
  526.         parm.pid = ntohl(parm.pid);
  527.         /* we spew_term later */
  528.         break;
  529.     default:
  530.         free_user(user);
  531.         show_error("ytalk_user: unsupported ytalk protocol");
  532.         return;
  533.     }
  534.     user->remote = parm;
  535.     user_winch = 1;
  536.     add_fd(fd, read_user);
  537.  
  538.     /* update the lists */
  539.  
  540.     if(user == wait_list)
  541.     wait_list = user->next;
  542.     else
  543.     for(u = wait_list; u; u = u->next)
  544.         if(u->next == user)
  545.         {
  546.         u->next = user->next;
  547.         break;
  548.         }
  549.     user->next = connect_list;
  550.     connect_list = user;
  551.  
  552.     /* send him my status */
  553.  
  554.     if(user->remote.vmajor > 2)
  555.     {
  556.     if(me->region_set)
  557.     {
  558.         v3w.code = V3_REGION;
  559.         v3w.rows = htons(me->rows);
  560.         v3w.cols = htons(me->cols);
  561.         send_oob(fd, &v3w, V3_WINCHLEN);
  562.         winch_exec();
  563.         spew_term(me, fd, me->rows, me->cols);
  564.     }
  565.     else
  566.         spew_term(me, fd, parm.rows, parm.cols);
  567.  
  568.     if(me->flags & FL_LOCKED)
  569.     {
  570.         v3f.code = V3_LOCKF;
  571.         v3f.flags = htonl(me->flags);
  572.         send_oob(fd, &v3f, V3_FLAGSLEN);
  573.     }
  574.     }
  575.  
  576.     /* tell everybody else he's here! */
  577.  
  578.     for(u = connect_list; u; u = u->next)
  579.     if(u != user)
  580.         send_import(u, user);
  581. }
  582.  
  583. /* Initial Handshaking:  read the edit keys and determine whether or not
  584.  * this is another ytalk user.
  585.  */
  586. static void
  587. connect_user(fd)
  588.   int fd;
  589. {
  590.     register yuser *user, *u;
  591.  
  592.     if((user = fd_to_user[fd]) == NULL)
  593.     {
  594.     remove_fd(fd);
  595.     show_error("connect_user: unknown contact");
  596.     return;
  597.     }
  598.     if(full_read(fd, user->edit, 3) < 0)
  599.     {
  600.     free_user(user);
  601.     show_error("connect_user: bad read");
  602.     return;
  603.     }
  604.     if(open_term(user, user->full_name) < 0)
  605.     {
  606.     free_user(user);
  607.     show_error("connect_user: open_term() failed");
  608.     return;
  609.     }
  610.  
  611.     /* check for ytalk connection */
  612.  
  613.     if(user->RUB == RUBDEF)
  614.     {
  615.     (void)memset(&parm, 0, sizeof(y_parm));
  616.     parm.protocol = YTP_NEW;
  617.     parm.vmajor = htons(VMAJOR);
  618.     parm.vminor = htons(VMINOR);
  619.     parm.rows = htons(me->t_rows);
  620.     parm.cols = htons(me->t_cols);
  621.     parm.my_rows = htons(user->t_rows);
  622.     parm.my_cols = htons(user->t_cols);
  623.     parm.w_rows = parm.rows;
  624.     parm.w_cols = parm.cols;
  625.     parm.pid = htonl(me->remote.pid);
  626.     (void)write(user->fd, &parm, sizeof(y_parm));
  627.     add_fd(fd, ytalk_user);
  628.     }
  629.     else
  630.     {
  631.     /* update the lists */
  632.  
  633.     if(user == wait_list)
  634.         wait_list = user->next;
  635.     else
  636.         for(u = wait_list; u; u = u->next)
  637.         if(u->next == user)
  638.         {
  639.             u->next = user->next;
  640.             break;
  641.         }
  642.     user->next = connect_list;
  643.     connect_list = user;
  644.  
  645.     spew_term(me, fd, me->t_rows, me->t_cols);
  646.     user_winch = 1;
  647.     add_fd(fd, read_user);
  648.     }
  649. }
  650.  
  651. /* Initial Handshaking:  delete his invitation (if it exists) and send
  652.  * my edit keys.
  653.  */
  654. static void
  655. contact_user(fd)
  656.   int fd;
  657. {
  658.     register yuser *user;
  659.     register int n;
  660.     int socklen;
  661.  
  662.     remove_fd(fd);
  663.     if((user = fd_to_user[fd]) == NULL)
  664.     {
  665.     show_error("contact_user: unknown contact");
  666.     return;
  667.     }
  668.     (void)send_dgram(user, DELETE_INVITE);
  669.     socklen = sizeof(struct sockaddr_in);
  670.     if((n = accept(fd, (struct sockaddr *) &(user->sock), &socklen)) < 0)
  671.     {
  672.     free_user(user);
  673.     show_error("connect_user: accept() failed");
  674.     return;
  675.     }
  676.     close(fd);
  677.     fd_to_user[fd] = NULL;
  678.  
  679.     user->fd = n;
  680.     fd_to_user[user->fd] = user;
  681.     add_fd(user->fd, connect_user);
  682.     (void)write(user->fd, me->edit, 3);    /* send the edit keys */
  683. }
  684.  
  685. /* Do a word wrap.
  686.  */
  687. static int
  688. word_wrap(user)
  689.   register yuser *user;
  690. {
  691.     register int i, x, bound;
  692.     static ychar temp[20];
  693.  
  694.     x = user->x;
  695.     if((bound = (x >> 1)) > 20)
  696.     bound = 20;
  697.     for(i = 1; i < bound && user->scr[user->y][x-i] != ' '; i++)
  698.     temp[i] = user->scr[user->y][x-i];
  699.     if(i >= bound)
  700.     return -1;
  701.     move_term(user, user->y, x - i);
  702.     clreol_term(user);
  703.     newline_term(user);
  704.     for(i--; i >= 1; i--)
  705.     addch_term(user, temp[i]);
  706.     return 0;
  707. }
  708.  
  709. /* Ring a user.  If he has an auto-invitation port established then talk
  710.  * to that instead of messing up his screen.
  711.  */
  712. static int
  713. announce(user)
  714.   yuser *user;
  715. {
  716.     register int rc, fd;
  717.  
  718.     errno = 0;
  719.     while((rc = send_dgram(user, AUTO_LOOK_UP)) == 0)
  720.     {
  721.     /* he has an auto-invite port established */
  722.  
  723.     if((fd = connect_to(NULL)) < 0)
  724.     {
  725.         if(fd == -3) /* it's one of my sockets... *sigh* */
  726.         break;
  727.         if(fd == -2) /* connection refused -- they hung up! */
  728.         {
  729.         (void)send_dgram(user, AUTO_DELETE);
  730.         errno = 0;
  731.         continue;
  732.         }
  733.         return -1;
  734.     }
  735.     /* Go ahead and use the Ytalk version 2.? auto-announce
  736.      * packet.
  737.      */
  738.     v2p.code = V2_AUTO;
  739.     strncpy(v2p.name, me->user_name, V2_NAMELEN);
  740.     strncpy(v2p.host, me->host_name, V2_HOSTLEN);
  741.     v2p.name[V2_NAMELEN-1] = '\0';
  742.     v2p.host[V2_HOSTLEN-1] = '\0';
  743.     (void)write(fd, &v2p, V2_PACKLEN);
  744.     close(fd);
  745.     return 0;
  746.     }
  747.     if(rc == -1)
  748.     return -1;
  749.  
  750.     errno = 0;
  751.     if(send_dgram(user, ANNOUNCE) != 0)
  752.     return -1;
  753.     return 0;
  754. }
  755.  
  756. /* ---- global functions ---- */
  757.  
  758. /* Invite a user into the conversation.
  759.  */
  760. void
  761. invite(name, send_announce)
  762.   register char *name;
  763.   int send_announce;
  764. {
  765.     register int rc;
  766.     char *hisname, *hishost, *histty;
  767.     yuser *user;
  768.  
  769.     /* First break down the username into login name and login host,
  770.      * assuming our host as a default.
  771.      */
  772.  
  773.     hisname = str_copy(name);
  774.     hishost = NULL;
  775.     histty  = NULL;
  776.     for(name = hisname; *name; name++)
  777.     {
  778.     if(*name == '@')
  779.     {
  780.         *name = '\0';
  781.         hishost = name+1;
  782.     }
  783.     if(*name == '#')
  784.     {
  785.         *name = '\0';
  786.         histty = name+1;
  787.     }
  788.     }
  789.     user = new_user(hisname, hishost, histty);
  790.     free(hisname);
  791.     if(user == NULL)
  792.     return;
  793.  
  794.     /* Now send off the invitation */
  795.  
  796.     user->next = wait_list;
  797.     wait_list = user;
  798.     user_winch = 1;
  799.     while((rc = send_dgram(user, LOOK_UP)) == 0)
  800.     {
  801.     /* We are expected... */
  802.     if((rc = connect_to(user)) < 0)
  803.     {
  804.         if(rc == -3) /* it's one of my sockets... *sigh* */
  805.         break;
  806.         if(rc == -2) /* connection refused -- they hung up! */
  807.         {
  808.         (void)send_dgram(user, DELETE);
  809.         continue;
  810.         }
  811.         free_user(user);
  812.         return;
  813.     }
  814.     user->last_invite = (ylong)time(NULL);
  815.     add_fd(user->fd, connect_user);
  816.     (void)write(user->fd, me->edit, 3);    /* send the edit keys */
  817.     return;
  818.     }
  819.     if(rc == -1)
  820.     return;
  821.  
  822.     /* Leave an invitation for him, and announce ourselves. */
  823.  
  824.     if(send_announce)
  825.     {
  826.     sprintf(errstr, "Ringing %s...", user->user_name);
  827.     msg_term(me, errstr);
  828.     }
  829.     if(newsock(user) != 0)
  830.     {
  831.     free_user(user);
  832.     return;
  833.     }
  834.     (void)send_dgram(user, LEAVE_INVITE);
  835.     user->last_invite = (ylong)time(NULL);
  836.     if(send_announce && announce(user) < 0)
  837.     {
  838.     (void)send_dgram(user, DELETE_INVITE);
  839.     sprintf(errstr, "%s not logged in", user->full_name);
  840.     show_error(errstr);
  841.     free_user(user);
  842.     return;
  843.     }
  844.     add_fd(user->fd, contact_user);
  845. }
  846.  
  847. /* Periodic housecleaning.
  848.  */
  849. void
  850. house_clean()
  851. {
  852.     register yuser *u, *next;
  853.     ylong t;
  854.     static char estr[80];
  855.     static ylong last_auto = 0;
  856.     int answer;
  857.  
  858.     t = (ylong)time(NULL);
  859.  
  860.     if(t - last_auto >= 30)
  861.     {
  862.     last_auto = t;
  863.     if(send_auto(LEAVE_INVITE) != 0)
  864.     {
  865.         show_error("house_clean: send_auto() failed");
  866.         kill_auto();
  867.     }
  868.     }
  869.  
  870.     for(u = wait_list; u; u = next)
  871.     {
  872.     next = u->next;
  873.     if(t - u->last_invite >= 30)
  874.     {
  875.         (void)send_dgram(u, LEAVE_INVITE);
  876.         u->last_invite = t = (ylong)time(NULL);
  877.         if(!(def_flags & FL_RING))
  878.         {
  879.         if(input_flag)
  880.             continue;
  881.         sprintf(estr, "Rering %s?", u->full_name);
  882.         answer = yes_no(estr);
  883.         t = (ylong)time(NULL);
  884.         if(answer == 'n')
  885.             continue;
  886.         }
  887.         if(announce(u) < 0)
  888.         {
  889.         (void)send_dgram(u, DELETE_INVITE);
  890.         sprintf(errstr, "%s not logged in", u->full_name);
  891.         show_error(errstr);
  892.         free_user(u);
  893.         }
  894.     }
  895.     }
  896. }
  897.  
  898. void
  899. send_winch(user)
  900.   yuser *user;
  901. {
  902.     register yuser *u;
  903.  
  904.     v3w.rows = htons(user->t_rows);
  905.     v3w.cols = htons(user->t_cols);
  906.  
  907.     if(user == me)
  908.     {
  909.     v3w.code = V3_MYWIN;
  910.     for(u = connect_list; u; u = u->next)
  911.         if(u->remote.vmajor > 2)
  912.         send_oob(u->fd, &v3w, V3_WINCHLEN);
  913.     winch_exec();
  914.     }
  915.     else if(user->remote.vmajor > 2)
  916.     {
  917.     v3w.code = V3_YOURWIN;
  918.     send_oob(user->fd, &v3w, V3_WINCHLEN);
  919.     }
  920. }
  921.  
  922. void
  923. send_region()
  924. {
  925.     register yuser *u;
  926.  
  927.     v3w.code = V3_REGION;
  928.     v3w.rows = htons(me->rows);
  929.     v3w.cols = htons(me->cols);
  930.  
  931.     for(u = connect_list; u; u = u->next)
  932.     if(u->remote.vmajor > 2)
  933.         send_oob(u->fd, &v3w, V3_WINCHLEN);
  934. }
  935.  
  936. void
  937. send_end_region()
  938. {
  939.     register yuser *u;
  940.  
  941.     v3w.code = V3_REGION;
  942.     v3w.rows = htons(0);
  943.     v3w.cols = htons(0);
  944.  
  945.     for(u = connect_list; u; u = u->next)
  946.     if(u->remote.vmajor > 2)
  947.         send_oob(u->fd, &v3w, V3_WINCHLEN);
  948. }
  949.  
  950. /* Send some output to a given user.  Sends the output to all connected
  951.  * users if the given user is either "me" or NULL.
  952.  */
  953. void
  954. send_users(user, buf, len)
  955.   yuser *user;
  956.   ychar *buf;
  957.   register int len;
  958. {
  959.     register ychar *o, *b;
  960.     register yuser *u;
  961.     static ychar *o_buf = NULL;
  962.     static int o_len = 0;
  963.  
  964.     /* data transparency */
  965.  
  966.     if((len << 1) > o_len)
  967.     {
  968.     o_len = (len << 1) + 512;
  969.     o_buf = (ychar *)realloc_mem(o_buf, o_len);
  970.     }
  971.     for(b = buf, o = o_buf; len > 0; b++, len--)
  972.     {
  973.     *(o++) = *b;
  974.     if(*b == V3_OOB)
  975.         *(o++) = V3_OOB;
  976.     }
  977.  
  978.     if(user && user != me)
  979.     {
  980.     if(user->fd > 0)    /* just to be sure... */
  981.     {
  982.         if(user->remote.vmajor > 2)
  983.         (void)write(user->fd, o_buf, o - o_buf);
  984.         else
  985.         (void)write(user->fd, buf, b - buf);
  986.     }
  987.     }
  988.     else
  989.     for(u = connect_list; u; u = u->next)
  990.         if(u->remote.vmajor > 2)
  991.         (void)write(u->fd, o_buf, o - o_buf);
  992.         else
  993.         (void)write(u->fd, buf, b - buf);
  994. }
  995.  
  996. /* Display user input.  Emulate ANSI.
  997.  */
  998. void
  999. show_input(user, buf, len)
  1000.   yuser *user;
  1001.   register ychar *buf;
  1002.   register int len;
  1003. {
  1004.     if(user->got_esc)
  1005.     {
  1006. process_esc:
  1007.     for(; len > 0; len--, buf++)
  1008.     {
  1009.         if(*buf >= '0' && *buf <= '9' && user->got_esc > 1)
  1010.         {
  1011.         user->av[user->ac] = (user->av[user->ac] * 10) + (*buf - '0');
  1012.         continue;
  1013.         }
  1014.         switch(*buf)
  1015.         {
  1016.         case ';':    /* arg separator */
  1017.             if(user->ac < MAXARG-1)
  1018.             user->av[++(user->ac)] = 0;
  1019.             break;
  1020.         case '[':
  1021.             user->got_esc = 2;
  1022.             break;
  1023.         case '?':
  1024.             if(user->got_esc == 2)
  1025.             user->got_esc = 3;
  1026.             else
  1027.             user->got_esc = 0;
  1028.             break;
  1029.         case '7':    /* save cursor */
  1030.             user->sy = user->y;
  1031.             user->sx = user->x;
  1032.             user->got_esc = 0;
  1033.             break;
  1034.         case '8':    /* restore cursor */
  1035.             move_term(user, user->sy, user->sx);
  1036.             user->got_esc = 0;
  1037.             break;
  1038.         case '@':
  1039.             if(user->got_esc == 2)    /* add char */
  1040.             {
  1041.             if(user->av[0] == 0)
  1042.                 add_char_term(user, 1);
  1043.             else
  1044.                 add_char_term(user, user->av[0]);
  1045.             }
  1046.             user->got_esc = 0;
  1047.             break;
  1048.         case 'A':    /* move up */
  1049.             if(user->av[0] == 0)
  1050.             move_term(user, user->y - 1, user->x);
  1051.             else if(user->av[0] > user->y)
  1052.             move_term(user, 0, user->x);
  1053.             else
  1054.             move_term(user, user->y - user->av[0], user->x);
  1055.             user->got_esc = 0;
  1056.             break;
  1057.         case 'B':    /* move down */
  1058.             if(user->av[0] == 0)
  1059.             move_term(user, user->y + 1, user->x);
  1060.             else
  1061.             move_term(user, user->y + user->av[0], user->x);
  1062.             user->got_esc = 0;
  1063.             break;
  1064.         case 'C':    /* move right */
  1065.             if(user->av[0] == 0)
  1066.             move_term(user, user->y, user->x + 1);
  1067.             else
  1068.             move_term(user, user->y, user->x + user->av[0]);
  1069.             user->got_esc = 0;
  1070.             break;
  1071.         case 'D':    /* move left */
  1072.             if(user->av[0] == 0)
  1073.             move_term(user, user->y, user->x - 1);
  1074.             else if(user->av[0] > user->x)
  1075.             move_term(user, user->y, 0);
  1076.             else
  1077.             move_term(user, user->y, user->x - user->av[0]);
  1078.             user->got_esc = 0;
  1079.             break;
  1080.         case 'H':    /* move */
  1081.             if(user->av[0] > 0)
  1082.             user->av[0]--;
  1083.             if(user->av[1] > 0)
  1084.             user->av[1]--;
  1085.             move_term(user, user->av[0], user->av[1]);
  1086.             user->got_esc = 0;
  1087.             break;
  1088.         case 'J':    /* clear to end of screen */
  1089.             clreos_term(user);
  1090.             user->got_esc = 0;
  1091.             break;
  1092.         case 'K':    /* clear to end of line */
  1093.             clreol_term(user);
  1094.             user->got_esc = 0;
  1095.             break;
  1096.         case 'L':
  1097.             if(user->got_esc == 2)    /* add line */
  1098.             {
  1099.             if(user->av[0] == 0)
  1100.                 add_line_term(user, 1);
  1101.             else
  1102.                 add_line_term(user, user->av[0]);
  1103.             }
  1104.             user->got_esc = 0;
  1105.             break;
  1106.         case 'M':
  1107.             if(user->got_esc == 2)    /* delete line */
  1108.             {
  1109.             if(user->av[0] == 0)
  1110.                 del_line_term(user, 1);
  1111.             else
  1112.                 del_line_term(user, user->av[0]);
  1113.             }
  1114.             else            /* reverse scroll */
  1115.             rev_scroll_term(user);
  1116.             user->got_esc = 0;
  1117.             break;
  1118.         case 'P':
  1119.             if(user->got_esc == 2)    /* del char */
  1120.             {
  1121.             if(user->av[0] == 0)
  1122.                 del_char_term(user, 1);
  1123.             else
  1124.                 del_char_term(user, user->av[0]);
  1125.             }
  1126.             user->got_esc = 0;
  1127.             break;
  1128.         case 'S':    /* forward scroll */
  1129.             scroll_term(user);
  1130.             user->got_esc = 0;
  1131.             break;
  1132.         case 'r':    /* set scroll region */
  1133.             if(user->av[0] > 0)
  1134.             user->av[0]--;
  1135.             if(user->av[1] > 0)
  1136.             user->av[1]--;
  1137.             set_scroll_region(user, user->av[0], user->av[1]);
  1138.             user->got_esc = 0;
  1139.             break;
  1140.         default:
  1141.             user->got_esc = 0;
  1142.         }
  1143.         if(user->got_esc == 0)
  1144.         {
  1145.         len--, buf++;
  1146.         break;
  1147.         }
  1148.     }
  1149.     }
  1150.     for(; len > 0; len--, buf++)
  1151.     {
  1152.     if(*buf >= ' ' && *buf <= '~')
  1153.     {
  1154.         if(user->x + 1 >= user->cols)
  1155.         {
  1156.         if(user->flags & FL_WRAP)
  1157.         {
  1158.             if(*buf == ' ')
  1159.             newline_term(user);
  1160.             else if(word_wrap(user) >= 0)
  1161.             addch_term(user, *buf);
  1162.             else
  1163.             {
  1164.             addch_term(user, *buf);
  1165.             newline_term(user);
  1166.             }
  1167.         }
  1168.         else
  1169.         {
  1170.             addch_term(user, *buf);
  1171.             newline_term(user);
  1172.         }
  1173.         }
  1174.         else
  1175.         addch_term(user, *buf);
  1176.     }
  1177.     else if(*buf == user->RUB && !(user->flags & FL_RAW))
  1178.         rub_term(user);
  1179.     else if(*buf == user->WORD && !(user->flags & FL_RAW))
  1180.         (void)word_term(user);
  1181.     else if(*buf == user->KILL && !(user->flags & FL_RAW))
  1182.         kill_term(user);
  1183.     else
  1184.     {
  1185.         switch(*buf)
  1186.         {
  1187.         case 7:        /* Bell */
  1188.             putc(7, stderr);
  1189.             break;
  1190.         case 8:        /* Backspace */
  1191.             if(user->x > 0)
  1192.             move_term(user, user->y, user->x - 1);
  1193.             break;
  1194.         case 9:        /* Tab */
  1195.             tab_term(user);
  1196.             break;
  1197.         case 10:    /* Newline */
  1198.             newline_term(user);
  1199.             break;
  1200.         case 13:    /* Return */
  1201.             if(user->flags & FL_RAW)
  1202.             move_term(user, user->y, 0);
  1203.             else
  1204.             newline_term(user);
  1205.             break;
  1206.         case 27:    /* Escape */
  1207.             user->got_esc = 1;
  1208.             user->ac = 0;
  1209.             user->av[0] = 0;
  1210.             user->av[1] = 0;
  1211.             len--, buf++;
  1212.             goto process_esc;    /* ugly but _fast_ */
  1213.         default:
  1214.             if(*buf < ' ')
  1215.             {
  1216.             /* show a control char */
  1217.             }
  1218.         }
  1219.     }
  1220.     }
  1221.     flush_term(user);
  1222. }
  1223.  
  1224. /* Process keyboard input.
  1225.  */
  1226. void
  1227. my_input(user, buf, len)
  1228.   yuser *user;
  1229.   register ychar *buf;
  1230.   int len;
  1231. {
  1232.     register ychar *c;
  1233.     register int i;
  1234.  
  1235.     /* If someone's waiting for input, give it to them! */
  1236.  
  1237.     if(input_flag)
  1238.     {
  1239.     io_ptr = buf;
  1240.     io_len = len;
  1241.     return;
  1242.     }
  1243.  
  1244.     /* Process input normally */
  1245.  
  1246.     while(len > 0)
  1247.     {
  1248.     /* check for a menu in process */
  1249.  
  1250.     if(menu_ptr)
  1251.     {
  1252.         io_ptr = buf;
  1253.         io_len = len;
  1254.         update_menu();
  1255.         buf = io_ptr;
  1256.         len = io_len;
  1257.         io_len = 0;
  1258.     }
  1259.  
  1260.     /* check for a running process */
  1261.  
  1262.     if(running_process)
  1263.     {
  1264.         io_ptr = buf;
  1265.         io_len = len;
  1266.         update_exec();
  1267.         buf = io_ptr;
  1268.         len = io_len;
  1269.         io_len = 0;
  1270.     }
  1271.     else
  1272.     {
  1273.         /* do normal input */
  1274.  
  1275.         while(len > 0)
  1276.         {
  1277.         c = buf;
  1278.         for(; len > 0; buf++, len--)
  1279.         {
  1280.             if(*buf == me->old_rub)
  1281.             *buf = me->RUB;
  1282.             else if(*buf == '\r')
  1283.             *buf = '\n';
  1284.             else if(*buf == 3)    /* Ctrl-C */
  1285.             bail(0);
  1286.             else if(*buf == 27)    /* Esc */
  1287.             break;
  1288.             else if(*buf == 12 || *buf == 18) /* ^L or ^R */
  1289.             break;
  1290.         }
  1291.         if((i = buf - c) > 0)
  1292.         {
  1293.             if(user != NULL && user != me && !(def_flags & FL_ASIDE))
  1294.             putc(7, stderr);
  1295.             else
  1296.             {
  1297.             show_input(me, c, i);
  1298.             send_users(user, c, i);
  1299.             }
  1300.         }
  1301.         if(len > 0)    /* we broke for a special char */
  1302.         {
  1303.             if(*buf == 27) /* ESC */
  1304.             break;
  1305.             if(*buf == 12 || *buf == 18) /* ^L or ^R */
  1306.             {
  1307.             redraw_all_terms();
  1308.             buf++, len--;
  1309.             }
  1310.         }
  1311.         }
  1312.     }
  1313.  
  1314.     /* start a menu if necessary */
  1315.  
  1316.     if(len > 0)
  1317.     {
  1318.         buf++, len--;
  1319.         show_main_menu();
  1320.         if(len <= 0)
  1321.         update_menu();
  1322.     }
  1323.     }
  1324. }
  1325.  
  1326. void
  1327. lock_flags(flags)
  1328.   ylong flags;
  1329. {
  1330.     register yuser *u;
  1331.  
  1332.     me->flags = flags | FL_LOCKED;
  1333.  
  1334.     /* send to connected users... */
  1335.  
  1336.     v3f.code = V3_LOCKF;
  1337.     v3f.flags = htonl(me->flags);
  1338.     for(u = connect_list; u; u = u->next)
  1339.     if(u->remote.vmajor > 2)
  1340.         send_oob(u->fd, &v3f, V3_FLAGSLEN);
  1341. }
  1342.  
  1343. void
  1344. unlock_flags()
  1345. {
  1346.     register yuser *u;
  1347.  
  1348.     me->flags = def_flags;
  1349.  
  1350.     /* send to connected users... */
  1351.  
  1352.     v3f.code = V3_UNLOCKF;
  1353.     v3f.flags = htonl(me->flags);
  1354.     for(u = connect_list; u; u = u->next)
  1355.     if(u->remote.vmajor > 2)
  1356.         send_oob(u->fd, &v3f, V3_FLAGSLEN);
  1357. }
  1358.