home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume27 / ytalk-3.0 / part01 / comm.c next >
C/C++ Source or Header  |  1993-08-20  |  28KB  |  1,313 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.     u_long 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)) == (u_long)-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, (u_long)-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, (u_long)-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.     u_long 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)) == (u_long)-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.         if(user->remote.vmajor <= 2)
  528.         spew_term(me, fd, parm.rows, parm.cols);
  529.         /* else we spew_term later */
  530.         break;
  531.     default:
  532.         free_user(user);
  533.         show_error("ytalk_user: unsupported ytalk protocol");
  534.         return;
  535.     }
  536.     user->remote = parm;
  537.     user_winch = 1;
  538.     add_fd(fd, read_user);
  539.  
  540.     /* update the lists */
  541.  
  542.     if(user == wait_list)
  543.     wait_list = user->next;
  544.     else
  545.     for(u = wait_list; u; u = u->next)
  546.         if(u->next == user)
  547.         {
  548.         u->next = user->next;
  549.         break;
  550.         }
  551.     user->next = connect_list;
  552.     connect_list = user;
  553.  
  554.     /* send him my status */
  555.  
  556.     if(user->remote.vmajor > 2)
  557.     {
  558.     if(me->region_set)
  559.     {
  560.         v3w.code = V3_REGION;
  561.         v3w.rows = htons(me->rows);
  562.         v3w.cols = htons(me->cols);
  563.         send_oob(fd, &v3w, V3_WINCHLEN);
  564.         winch_exec();
  565.         spew_term(me, fd, me->rows, me->cols);
  566.     }
  567.     else
  568.         spew_term(me, fd, parm.rows, parm.cols);
  569.  
  570.     if(me->flags & FL_LOCKED)
  571.     {
  572.         v3f.code = V3_LOCKF;
  573.         v3f.flags = htonl(me->flags);
  574.         send_oob(fd, &v3f, V3_FLAGSLEN);
  575.     }
  576.     }
  577.  
  578.     /* tell everybody else he's here! */
  579.  
  580.     for(u = connect_list; u; u = u->next)
  581.     if(u != user)
  582.         send_import(u, user);
  583. }
  584.  
  585. /* Initial Handshaking:  read the edit keys and determine whether or not
  586.  * this is another ytalk user.
  587.  */
  588. static void
  589. connect_user(fd)
  590.   int fd;
  591. {
  592.     register yuser *user, *u;
  593.  
  594.     if((user = fd_to_user[fd]) == NULL)
  595.     {
  596.     remove_fd(fd);
  597.     show_error("connect_user: unknown contact");
  598.     return;
  599.     }
  600.     if(full_read(fd, user->edit, 3) < 0)
  601.     {
  602.     free_user(user);
  603.     show_error("connect_user: bad read");
  604.     return;
  605.     }
  606.     if(open_term(user, user->user_name) < 0)
  607.     {
  608.     free_user(user);
  609.     show_error("connect_user: open_term() failed");
  610.     return;
  611.     }
  612.  
  613.     /* check for ytalk connection */
  614.  
  615.     if(user->RUB == RUBDEF)
  616.     {
  617.     (void)memset(&parm, 0, sizeof(y_parm));
  618.     parm.protocol = YTP_NEW;
  619.     parm.vmajor = htons(VMAJOR);
  620.     parm.vminor = htons(VMINOR);
  621.     parm.rows = htons(me->t_rows);
  622.     parm.cols = htons(me->t_cols);
  623.     parm.my_rows = htons(user->t_rows);
  624.     parm.my_cols = htons(user->t_cols);
  625.     parm.w_rows = parm.rows;
  626.     parm.w_cols = parm.cols;
  627.     parm.pid = htonl(me->remote.pid);
  628.     (void)write(user->fd, &parm, sizeof(y_parm));
  629.     add_fd(fd, ytalk_user);
  630.     }
  631.     else
  632.     {
  633.     /* update the lists */
  634.  
  635.     if(user == wait_list)
  636.         wait_list = user->next;
  637.     else
  638.         for(u = wait_list; u; u = u->next)
  639.         if(u->next == user)
  640.         {
  641.             u->next = user->next;
  642.             break;
  643.         }
  644.     user->next = connect_list;
  645.     connect_list = user;
  646.  
  647.     spew_term(me, fd, me->t_rows, me->t_cols);
  648.     user_winch = 1;
  649.     add_fd(fd, read_user);
  650.     }
  651. }
  652.  
  653. /* Initial Handshaking:  delete his invitation (if it exists) and send
  654.  * my edit keys.
  655.  */
  656. static void
  657. contact_user(fd)
  658.   int fd;
  659. {
  660.     register yuser *user;
  661.     register int n;
  662.     int socklen;
  663.  
  664.     remove_fd(fd);
  665.     if((user = fd_to_user[fd]) == NULL)
  666.     {
  667.     show_error("contact_user: unknown contact");
  668.     return;
  669.     }
  670.     (void)send_dgram(user, DELETE_INVITE);
  671.     socklen = sizeof(struct sockaddr_in);
  672.     if((n = accept(fd, (struct sockaddr *) &(user->sock), &socklen)) < 0)
  673.     {
  674.     free_user(user);
  675.     show_error("connect_user: accept() failed");
  676.     return;
  677.     }
  678.     close(fd);
  679.     fd_to_user[fd] = NULL;
  680.  
  681.     user->fd = n;
  682.     fd_to_user[user->fd] = user;
  683.     add_fd(user->fd, connect_user);
  684.     (void)write(user->fd, me->edit, 3);    /* send the edit keys */
  685. }
  686.  
  687. /* Do a word wrap.
  688.  */
  689. static int
  690. word_wrap(user)
  691.   register yuser *user;
  692. {
  693.     register int i, x, bound;
  694.     static ychar temp[20];
  695.  
  696.     x = user->x;
  697.     if((bound = (x >> 1)) > 20)
  698.     bound = 20;
  699.     for(i = 1; i < bound && user->scr[user->y][x-i] != ' '; i++)
  700.     temp[i] = user->scr[user->y][x-i];
  701.     if(i >= bound)
  702.     return;
  703.     move_term(user, user->y, x - i);
  704.     clreol_term(user);
  705.     newline_term(user);
  706.     for(i--; i >= 1; i--)
  707.     addch_term(user, temp[i]);
  708. }
  709.  
  710. /* Ring a user.  If he has an auto-invitation port established then talk
  711.  * to that instead of messing up his screen.
  712.  */
  713. static int
  714. announce(user)
  715.   yuser *user;
  716. {
  717.     register int rc, fd;
  718.  
  719.     errno = 0;
  720.     while((rc = send_dgram(user, AUTO_LOOK_UP)) == 0)
  721.     {
  722.     /* he has an auto-invite port established */
  723.  
  724.     if((fd = connect_to(NULL)) < 0)
  725.     {
  726.         if(fd == -3) /* it's one of my sockets... *sigh* */
  727.         break;
  728.         if(fd == -2) /* connection refused -- they hung up! */
  729.         {
  730.         (void)send_dgram(user, AUTO_DELETE);
  731.         errno = 0;
  732.         continue;
  733.         }
  734.         return -1;
  735.     }
  736.     /* Go ahead and use the Ytalk version 2.? auto-announce
  737.      * packet.
  738.      */
  739.     v2p.code = V2_AUTO;
  740.     strncpy(v2p.name, me->user_name, V2_NAMELEN);
  741.     strncpy(v2p.host, me->host_name, V2_HOSTLEN);
  742.     v2p.name[V2_NAMELEN-1] = '\0';
  743.     v2p.host[V2_HOSTLEN-1] = '\0';
  744.     (void)write(fd, &v2p, V2_PACKLEN);
  745.     close(fd);
  746.     return 0;
  747.     }
  748.     if(rc == -1)
  749.     return -1;
  750.  
  751.     errno = 0;
  752.     if(send_dgram(user, ANNOUNCE) != 0)
  753.     return -1;
  754.     return 0;
  755. }
  756.  
  757. /* ---- global functions ---- */
  758.  
  759. /* Invite a user into the conversation.
  760.  */
  761. void
  762. invite(name, send_announce)
  763.   register char *name;
  764.   int send_announce;
  765. {
  766.     register int rc;
  767.     char *hisname, *hishost, *histty;
  768.     yuser *user;
  769.  
  770.     /* First break down the username into login name and login host,
  771.      * assuming our host as a default.
  772.      */
  773.  
  774.     hisname = str_copy(name);
  775.     hishost = NULL;
  776.     histty  = NULL;
  777.     for(name = hisname; *name; name++)
  778.     {
  779.     if(*name == '@')
  780.     {
  781.         *name = '\0';
  782.         hishost = name+1;
  783.     }
  784.     if(*name == '#')
  785.     {
  786.         *name = '\0';
  787.         histty = name+1;
  788.     }
  789.     }
  790.     user = new_user(hisname, hishost, histty);
  791.     free(hisname);
  792.     if(user == NULL)
  793.     return;
  794.  
  795.     /* Now send off the invitation */
  796.  
  797.     user->next = wait_list;
  798.     wait_list = user;
  799.     user_winch = 1;
  800.     while((rc = send_dgram(user, LOOK_UP)) == 0)
  801.     {
  802.     /* We are expected... */
  803.     if((rc = connect_to(user)) < 0)
  804.     {
  805.         if(rc == -3) /* it's one of my sockets... *sigh* */
  806.         break;
  807.         if(rc == -2) /* connection refused -- they hung up! */
  808.         {
  809.         (void)send_dgram(user, DELETE);
  810.         continue;
  811.         }
  812.         free_user(user);
  813.         return;
  814.     }
  815.     user->last_invite = time(NULL);
  816.     add_fd(user->fd, connect_user);
  817.     (void)write(user->fd, me->edit, 3);    /* send the edit keys */
  818.     return;
  819.     }
  820.     if(rc == -1)
  821.     return;
  822.  
  823.     /* Leave an invitation for him, and announce ourselves. */
  824.  
  825.     if(send_announce)
  826.     {
  827.     sprintf(errstr, "Ringing %s...", user->user_name);
  828.     msg_term(me, errstr);
  829.     }
  830.     if(newsock(user) != 0)
  831.     {
  832.     free_user(user);
  833.     return;
  834.     }
  835.     (void)send_dgram(user, LEAVE_INVITE);
  836.     user->last_invite = time(NULL);
  837.     if(send_announce && announce(user) < 0)
  838.     {
  839.     (void)send_dgram(user, DELETE_INVITE);
  840.     sprintf(errstr, "%s not logged in", user->full_name);
  841.     show_error(errstr);
  842.     free_user(user);
  843.     return;
  844.     }
  845.     add_fd(user->fd, contact_user);
  846. }
  847.  
  848. /* Periodic housecleaning.
  849.  */
  850. void
  851. house_clean()
  852. {
  853.     register yuser *u, *next;
  854.     long t;
  855.     static char estr[80];
  856.     static u_long last_auto = 0;
  857.     int answer;
  858.  
  859.     t = time(NULL);
  860.  
  861.     if(t - last_auto >= 30)
  862.     {
  863.     last_auto = t;
  864.     if(send_auto(LEAVE_INVITE) != 0)
  865.     {
  866.         show_error("house_clean: send_auto() failed");
  867.         kill_auto();
  868.     }
  869.     }
  870.  
  871.     for(u = wait_list; u; u = next)
  872.     {
  873.     next = u->next;
  874.     if(t - u->last_invite >= 30)
  875.     {
  876.         (void)send_dgram(u, LEAVE_INVITE);
  877.         u->last_invite = t = time(NULL);
  878.         if(!(def_flags & FL_RING))
  879.         {
  880.         if(input_flag)
  881.             continue;
  882.         sprintf(estr, "Rering %s?", u->full_name);
  883.         answer = yes_no(estr);
  884.         t = time(NULL);
  885.         if(answer == 'n')
  886.             continue;
  887.         }
  888.         if(announce(u) < 0)
  889.         {
  890.         (void)send_dgram(u, DELETE_INVITE);
  891.         sprintf(errstr, "%s not logged in", u->full_name);
  892.         show_error(errstr);
  893.         free_user(u);
  894.         }
  895.     }
  896.     }
  897. }
  898.  
  899. void
  900. send_winch(user)
  901.   yuser *user;
  902. {
  903.     register yuser *u;
  904.  
  905.     v3w.rows = htons(user->t_rows);
  906.     v3w.cols = htons(user->t_cols);
  907.  
  908.     if(user == me)
  909.     {
  910.     v3w.code = V3_MYWIN;
  911.     for(u = connect_list; u; u = u->next)
  912.         if(u->remote.vmajor > 2)
  913.         send_oob(u->fd, &v3w, V3_WINCHLEN);
  914.     winch_exec();
  915.     }
  916.     else if(user->remote.vmajor > 2)
  917.     {
  918.     v3w.code = V3_YOURWIN;
  919.     send_oob(user->fd, &v3w, V3_WINCHLEN);
  920.     }
  921. }
  922.  
  923. void
  924. send_region()
  925. {
  926.     register yuser *u;
  927.  
  928.     v3w.code = V3_REGION;
  929.     v3w.rows = htons(me->rows);
  930.     v3w.cols = htons(me->cols);
  931.  
  932.     for(u = connect_list; u; u = u->next)
  933.     if(u->remote.vmajor > 2)
  934.         send_oob(u->fd, &v3w, V3_WINCHLEN);
  935. }
  936.  
  937. void
  938. send_end_region()
  939. {
  940.     register yuser *u;
  941.  
  942.     v3w.code = V3_REGION;
  943.     v3w.rows = htons(0);
  944.     v3w.cols = htons(0);
  945.  
  946.     for(u = connect_list; u; u = u->next)
  947.     if(u->remote.vmajor > 2)
  948.         send_oob(u->fd, &v3w, V3_WINCHLEN);
  949. }
  950.  
  951. void
  952. send_users(buf, len)
  953.   ychar *buf;
  954.   register int len;
  955. {
  956.     register ychar *o, *b;
  957.     register yuser *u;
  958.     static ychar *o_buf = NULL;
  959.     static int o_len = 0;
  960.  
  961.     /* data transparency */
  962.  
  963.     if((len << 1) > o_len)
  964.     {
  965.     o_len = (len << 1) + 512;
  966.     o_buf = (ychar *)realloc_mem(o_buf, o_len);
  967.     }
  968.     for(b = buf, o = o_buf; len > 0; b++, len--)
  969.     {
  970.     *(o++) = *b;
  971.     if(*b == V3_OOB)
  972.         *(o++) = V3_OOB;
  973.     }
  974.     for(u = connect_list; u; u = u->next)
  975.     if(u->remote.vmajor > 2)
  976.         (void)write(u->fd, o_buf, o - o_buf);
  977.     else
  978.         (void)write(u->fd, buf, b - buf);
  979. }
  980.  
  981. /* Display user input.  Emulate ANSI.
  982.  */
  983. void
  984. show_input(user, buf, len)
  985.   yuser *user;
  986.   register ychar *buf;
  987.   register int len;
  988. {
  989.     if(user->got_esc)
  990.     {
  991. process_esc:
  992.     for(; len > 0; len--, buf++)
  993.     {
  994.         if(*buf >= '0' && *buf <= '9' && user->got_esc > 1)
  995.         {
  996.         user->av[user->ac] = (user->av[user->ac] * 10) + (*buf - '0');
  997.         continue;
  998.         }
  999.         switch(*buf)
  1000.         {
  1001.         case ';':    /* arg separator */
  1002.             if(user->ac < MAXARG-1)
  1003.             user->av[++(user->ac)] = 0;
  1004.             break;
  1005.         case '[':
  1006.             user->got_esc = 2;
  1007.             break;
  1008.         case '?':
  1009.             if(user->got_esc == 2)
  1010.             user->got_esc = 3;
  1011.             else
  1012.             user->got_esc = 0;
  1013.             break;
  1014.         case '7':    /* save cursor */
  1015.             user->sy = user->y;
  1016.             user->sx = user->x;
  1017.             user->got_esc = 0;
  1018.             break;
  1019.         case '8':    /* restore cursor */
  1020.             move_term(user, user->sy, user->sx);
  1021.             user->got_esc = 0;
  1022.             break;
  1023.         case '@':
  1024.             if(user->got_esc == 2)    /* add char */
  1025.             {
  1026.             if(user->av[0] == 0)
  1027.                 add_char_term(user, 1);
  1028.             else
  1029.                 add_char_term(user, user->av[0]);
  1030.             }
  1031.             user->got_esc = 0;
  1032.             break;
  1033.         case 'A':    /* move up */
  1034.             if(user->av[0] == 0)
  1035.             move_term(user, user->y - 1, user->x);
  1036.             else if(user->av[0] > user->y)
  1037.             move_term(user, 0, user->x);
  1038.             else
  1039.             move_term(user, user->y - user->av[0], user->x);
  1040.             user->got_esc = 0;
  1041.             break;
  1042.         case 'B':    /* move down */
  1043.             if(user->av[0] == 0)
  1044.             move_term(user, user->y + 1, user->x);
  1045.             else
  1046.             move_term(user, user->y + user->av[0], user->x);
  1047.             user->got_esc = 0;
  1048.             break;
  1049.         case 'C':    /* move right */
  1050.             if(user->av[0] == 0)
  1051.             move_term(user, user->y, user->x + 1);
  1052.             else
  1053.             move_term(user, user->y, user->x + user->av[0]);
  1054.             user->got_esc = 0;
  1055.             break;
  1056.         case 'D':    /* move left */
  1057.             if(user->av[0] == 0)
  1058.             move_term(user, user->y, user->x - 1);
  1059.             else if(user->av[0] > user->x)
  1060.             move_term(user, user->y, 0);
  1061.             else
  1062.             move_term(user, user->y, user->x - user->av[0]);
  1063.             user->got_esc = 0;
  1064.             break;
  1065.         case 'H':    /* move */
  1066.             if(user->av[0] > 0)
  1067.             user->av[0]--;
  1068.             if(user->av[1] > 0)
  1069.             user->av[1]--;
  1070.             move_term(user, user->av[0], user->av[1]);
  1071.             user->got_esc = 0;
  1072.             break;
  1073.         case 'J':    /* clear to end of screen */
  1074.             clreos_term(user);
  1075.             user->got_esc = 0;
  1076.             break;
  1077.         case 'K':    /* clear to end of line */
  1078.             clreol_term(user);
  1079.             user->got_esc = 0;
  1080.             break;
  1081.         case 'L':
  1082.             if(user->got_esc == 2)    /* add line */
  1083.             {
  1084.             if(user->av[0] == 0)
  1085.                 add_line_term(user, 1);
  1086.             else
  1087.                 add_line_term(user, user->av[0]);
  1088.             }
  1089.             user->got_esc = 0;
  1090.             break;
  1091.         case 'M':
  1092.             if(user->got_esc == 2)    /* delete line */
  1093.             {
  1094.             if(user->av[0] == 0)
  1095.                 del_line_term(user, 1);
  1096.             else
  1097.                 del_line_term(user, user->av[0]);
  1098.             }
  1099.             else            /* reverse scroll */
  1100.             rev_scroll_term(user);
  1101.             user->got_esc = 0;
  1102.             break;
  1103.         case 'P':
  1104.             if(user->got_esc == 2)    /* del char */
  1105.             {
  1106.             if(user->av[0] == 0)
  1107.                 del_char_term(user, 1);
  1108.             else
  1109.                 del_char_term(user, user->av[0]);
  1110.             }
  1111.             user->got_esc = 0;
  1112.             break;
  1113.         case 'S':    /* forward scroll */
  1114.             scroll_term(user);
  1115.             user->got_esc = 0;
  1116.             break;
  1117.         case 'r':    /* set scroll region */
  1118.             if(user->av[0] > 0)
  1119.             user->av[0]--;
  1120.             if(user->av[1] > 0)
  1121.             user->av[1]--;
  1122.             set_scroll_region(user, user->av[0], user->av[1]);
  1123.             user->got_esc = 0;
  1124.             break;
  1125.         default:
  1126.             user->got_esc = 0;
  1127.         }
  1128.         if(user->got_esc == 0)
  1129.         {
  1130.         len--, buf++;
  1131.         break;
  1132.         }
  1133.     }
  1134.     }
  1135.     for(; len > 0; len--, buf++)
  1136.     {
  1137.     if(*buf >= ' ' && *buf <= '~')
  1138.     {
  1139.         if((user->flags & FL_WRAP) && user->x + 1 >= user->cols)
  1140.         {
  1141.         if(*buf == ' ')
  1142.             newline_term(user);
  1143.         else
  1144.         {
  1145.             word_wrap(user);
  1146.             addch_term(user, *buf);
  1147.         }
  1148.         }
  1149.         else
  1150.         addch_term(user, *buf);
  1151.     }
  1152.     else if(*buf == user->RUB && !(user->flags & FL_RAW))
  1153.         rub_term(user);
  1154.     else if(*buf == user->WORD && !(user->flags & FL_RAW))
  1155.         (void)word_term(user);
  1156.     else if(*buf == user->KILL && !(user->flags & FL_RAW))
  1157.         kill_term(user);
  1158.     else
  1159.     {
  1160.         switch(*buf)
  1161.         {
  1162.         case 7:        /* Bell */
  1163.             putc(7, stderr);
  1164.             break;
  1165.         case 8:        /* Backspace */
  1166.             if(user->x > 0)
  1167.             move_term(user, user->y, user->x - 1);
  1168.             break;
  1169.         case 9:        /* Tab */
  1170.             tab_term(user);
  1171.             break;
  1172.         case 10:    /* Newline */
  1173.             newline_term(user);
  1174.             break;
  1175.         case 13:    /* Return */
  1176.             if(user->flags & FL_RAW)
  1177.             move_term(user, user->y, 0);
  1178.             else
  1179.             newline_term(user);
  1180.             break;
  1181.         case 27:    /* Escape */
  1182.             user->got_esc = 1;
  1183.             user->ac = 0;
  1184.             user->av[0] = 0;
  1185.             user->av[1] = 0;
  1186.             len--, buf++;
  1187.             goto process_esc;    /* ugly but _fast_ */
  1188.         default:
  1189.             if(*buf < ' ')
  1190.             {
  1191.             /* show a control char */
  1192.             }
  1193.         }
  1194.     }
  1195.     }
  1196.     flush_term(user);
  1197. }
  1198.  
  1199. /* Process keyboard input.
  1200.  */
  1201. void
  1202. my_input(buf, len)
  1203.   register ychar *buf;
  1204.   int len;
  1205. {
  1206.     register ychar *c;
  1207.     register int i;
  1208.  
  1209.     /* If someone's waiting for input, give it to them! */
  1210.  
  1211.     if(input_flag)
  1212.     {
  1213.     io_ptr = buf;
  1214.     io_len = len;
  1215.     return;
  1216.     }
  1217.  
  1218.     /* Process input normally */
  1219.  
  1220.     while(len > 0)
  1221.     {
  1222.     /* check for a menu in process */
  1223.  
  1224.     if(menu_ptr)
  1225.     {
  1226.         io_ptr = buf;
  1227.         io_len = len;
  1228.         update_menu();
  1229.         buf = io_ptr;
  1230.         len = io_len;
  1231.         io_len = 0;
  1232.     }
  1233.  
  1234.     /* check for a running process */
  1235.  
  1236.     if(running_process)
  1237.     {
  1238.         io_ptr = buf;
  1239.         io_len = len;
  1240.         update_exec();
  1241.         buf = io_ptr;
  1242.         len = io_len;
  1243.         io_len = 0;
  1244.     }
  1245.     else
  1246.     {
  1247.         /* do normal input */
  1248.  
  1249.         c = buf;
  1250.         for(; len > 0; buf++, len--)
  1251.         {
  1252.         if(*buf == me->old_rub)
  1253.             *buf = me->RUB;
  1254.         else if(*buf == '\r')
  1255.             *buf = '\n';
  1256.         else if(*buf == 3)    /* Ctrl-C */
  1257.             bail(0);
  1258.         else if(*buf == 27)    /* Esc */
  1259.             break;
  1260.         }
  1261.         if((i = buf - c) > 0)
  1262.         {
  1263.         show_input(me, c, i);
  1264.         send_users(c, i);
  1265.         }
  1266.     }
  1267.  
  1268.     /* start a menu if necessary */
  1269.  
  1270.     if(len > 0)
  1271.     {
  1272.         buf++;
  1273.         len--;
  1274.         show_main_menu();
  1275.         if(len <= 0)
  1276.         update_menu();
  1277.     }
  1278.     }
  1279. }
  1280.  
  1281. void
  1282. lock_flags(flags)
  1283.   u_long flags;
  1284. {
  1285.     register yuser *u;
  1286.  
  1287.     me->flags = flags | FL_LOCKED;
  1288.  
  1289.     /* send to connected users... */
  1290.  
  1291.     v3f.code = V3_LOCKF;
  1292.     v3f.flags = htonl(me->flags);
  1293.     for(u = connect_list; u; u = u->next)
  1294.     if(u->remote.vmajor > 2)
  1295.         send_oob(u->fd, &v3f, V3_FLAGSLEN);
  1296. }
  1297.  
  1298. void
  1299. unlock_flags()
  1300. {
  1301.     register yuser *u;
  1302.  
  1303.     me->flags = def_flags;
  1304.  
  1305.     /* send to connected users... */
  1306.  
  1307.     v3f.code = V3_UNLOCKF;
  1308.     v3f.flags = htonl(me->flags);
  1309.     for(u = connect_list; u; u = u->next)
  1310.     if(u->remote.vmajor > 2)
  1311.         send_oob(u->fd, &v3f, V3_FLAGSLEN);
  1312. }
  1313.