示例#1
0
static gpointer
remmina_ssh_tunnel_main_thread_proc (gpointer data)
{
	RemminaSSHTunnel *tunnel = (RemminaSSHTunnel*) data;
	gchar *ptr;
	ssize_t len = 0, lenw = 0;
	fd_set set;
	struct timeval timeout;
	GTimeVal t1, t2;
	glong diff;
	ssh_channel channel = NULL;
	gboolean first = TRUE;
	gboolean disconnected;
	gint sock;
	gint maxfd;
	gint i;
	gint ret;
	struct sockaddr_in sin;

	g_get_current_time (&t1);
	t2 = t1;

	switch (tunnel->tunnel_type)
	{
		case REMMINA_SSH_TUNNEL_OPEN:
		/* Accept a local connection */
		sock = accept (tunnel->server_sock, NULL, NULL);
		if (sock < 0)
		{
			REMMINA_SSH (tunnel)->error = g_strdup ("Failed to accept local socket");
			tunnel->thread = 0;
			return NULL;
		}

		if ((channel = channel_new (tunnel->ssh.session)) == NULL)
		{
			close (sock);
			remmina_ssh_set_error (REMMINA_SSH (tunnel), "Failed to createt channel : %s");
			tunnel->thread = 0;
			return NULL;
		}
		/* Request the SSH server to connect to the destination */
		if (channel_open_forward (channel, tunnel->dest, tunnel->port, "127.0.0.1", 0) != SSH_OK)
		{
			close (sock);
			channel_close (channel);
			channel_free (channel);
			remmina_ssh_set_error (REMMINA_SSH (tunnel), _("Failed to connect to the SSH tunnel destination: %s"));
			tunnel->thread = 0;
			return NULL;
		}
		remmina_ssh_tunnel_add_channel (tunnel, channel, sock);
		break;

		case REMMINA_SSH_TUNNEL_X11:
		if ((tunnel->x11_channel = channel_new (tunnel->ssh.session)) == NULL)
		{
			remmina_ssh_set_error (REMMINA_SSH (tunnel), "Failed to create channel : %s");
			tunnel->thread = 0;
			return NULL;
		}
		if (!remmina_public_get_xauth_cookie (tunnel->localdisplay, &ptr))
		{
			remmina_ssh_set_application_error (REMMINA_SSH (tunnel), "%s", ptr);
			g_free(ptr);
			tunnel->thread = 0;
			return NULL;
		}
		if (channel_open_session (tunnel->x11_channel) ||
				channel_request_x11 (tunnel->x11_channel, TRUE, NULL, ptr,
						gdk_screen_get_number (gdk_screen_get_default ())))
		{
			g_free(ptr);
			remmina_ssh_set_error (REMMINA_SSH (tunnel), "Failed to open channel : %s");
			tunnel->thread = 0;
			return NULL;
		}
		g_free(ptr);
		if (channel_request_exec (tunnel->x11_channel, tunnel->dest))
		{
			ptr = g_strdup_printf(_("Failed to execute %s on SSH server : %%s"), tunnel->dest);
			remmina_ssh_set_error (REMMINA_SSH (tunnel), ptr);
			g_free(ptr);
			tunnel->thread = 0;
			return NULL;
		}

		if (tunnel->init_func &&
				! (*tunnel->init_func) (tunnel, tunnel->callback_data))
		{
			if (tunnel->disconnect_func)
			{
				(*tunnel->disconnect_func) (tunnel, tunnel->callback_data);
			}
			tunnel->thread = 0;
			return NULL;
		}

		break;

		case REMMINA_SSH_TUNNEL_XPORT:
		/* Detect the next available port starting from 6010 on the server */
		for (i = 10; i <= MAX_X_DISPLAY_NUMBER; i++)
		{
			if (channel_forward_listen (REMMINA_SSH (tunnel)->session,
							(tunnel->bindlocalhost ? "localhost" : NULL), 6000 + i, NULL))
			{
				continue;
			}
			else
			{
				tunnel->remotedisplay = i;
				break;
			}
		}
		if (tunnel->remotedisplay < 1)
		{
			remmina_ssh_set_error (REMMINA_SSH (tunnel), _("Failed to request port forwarding : %s"));
			if (tunnel->disconnect_func)
			{
				(*tunnel->disconnect_func) (tunnel, tunnel->callback_data);
			}
			tunnel->thread = 0;
			return NULL;
		}

		if (tunnel->init_func &&
				! (*tunnel->init_func) (tunnel, tunnel->callback_data))
		{
			if (tunnel->disconnect_func)
			{
				(*tunnel->disconnect_func) (tunnel, tunnel->callback_data);
			}
			tunnel->thread = 0;
			return NULL;
		}

		break;

		case REMMINA_SSH_TUNNEL_REVERSE:
		if (channel_forward_listen (REMMINA_SSH (tunnel)->session, NULL, tunnel->port, NULL))
		{
			remmina_ssh_set_error (REMMINA_SSH (tunnel), _("Failed to request port forwarding : %s"));
			if (tunnel->disconnect_func)
			{
				(*tunnel->disconnect_func) (tunnel, tunnel->callback_data);
			}
			tunnel->thread = 0;
			return NULL;
		}

		if (tunnel->init_func &&
				! (*tunnel->init_func) (tunnel, tunnel->callback_data))
		{
			if (tunnel->disconnect_func)
			{
				(*tunnel->disconnect_func) (tunnel, tunnel->callback_data);
			}
			tunnel->thread = 0;
			return NULL;
		}

		break;
	}

	tunnel->buffer_len = 10240;
	tunnel->buffer = g_malloc (tunnel->buffer_len);

	/* Start the tunnel data transmittion */
	while (tunnel->running)
	{
		if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_XPORT ||
				tunnel->tunnel_type == REMMINA_SSH_TUNNEL_X11 ||
				tunnel->tunnel_type == REMMINA_SSH_TUNNEL_REVERSE)
		{
			if (first)
			{
				first = FALSE;
				/* Wait for a period of time for the first incoming connection */
				if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_X11)
				{
					channel = channel_accept_x11 (tunnel->x11_channel, 15000);
				}
				else
				{
					channel = channel_forward_accept (REMMINA_SSH (tunnel)->session, 15000);
				}
				if (!channel)
				{
					remmina_ssh_set_application_error (REMMINA_SSH (tunnel), _("No response from the server."));
					if (tunnel->disconnect_func)
					{
						(*tunnel->disconnect_func) (tunnel, tunnel->callback_data);
					}
					tunnel->thread = 0;
					return NULL;
				}
				if (tunnel->connect_func)
				{
					(*tunnel->connect_func) (tunnel, tunnel->callback_data);
				}
				if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_REVERSE)
				{
					/* For reverse tunnel, we only need one connection. */
					channel_forward_cancel (REMMINA_SSH (tunnel)->session, NULL, tunnel->port);
				}
			}
			else if (tunnel->tunnel_type != REMMINA_SSH_TUNNEL_REVERSE)
			{
				/* Poll once per some period of time if no incoming connections.
				 * Don't try to poll continuously as it will significantly slow down the loop */
				g_get_current_time (&t1);
				diff = (t1.tv_sec - t2.tv_sec) * 10 + (t1.tv_usec - t2.tv_usec) / 100000;
				if (diff > 1)
				{
					if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_X11)
					{
						channel = channel_accept_x11 (tunnel->x11_channel, 0);
					}
					else
					{
						channel = channel_forward_accept (REMMINA_SSH (tunnel)->session, 0);
					}
					if (channel == NULL)
					{
						t2 = t1;
					}
				}
			}

			if (channel)
			{
				if (tunnel->tunnel_type == REMMINA_SSH_TUNNEL_REVERSE)
				{
					sin.sin_family = AF_INET;
					sin.sin_port = htons (tunnel->localport);
					sin.sin_addr.s_addr = inet_addr ("127.0.0.1");
					sock = socket (AF_INET, SOCK_STREAM, 0);
					if (connect (sock, (struct sockaddr *) &sin, sizeof (sin)) < 0)
					{
						remmina_ssh_set_application_error (REMMINA_SSH (tunnel),
								"Cannot connect to local port %i.", tunnel->localport);
						close (sock);
						sock = -1;
					}
				}
				else
				{
					sock = remmina_public_open_xdisplay (tunnel->localdisplay);
				}
				if (sock >= 0)
				{
					remmina_ssh_tunnel_add_channel (tunnel, channel, sock);
				}
				else
				{
					/* Failed to create unix socket. Will this happen? */
					channel_close (channel);
					channel_free (channel);
				}
				channel = NULL;
			}
		}

		if (tunnel->num_channels <= 0)
		{
			/* No more connections. We should quit */
			break;
		}

		timeout.tv_sec = 0;
		timeout.tv_usec = 200000;

		FD_ZERO (&set);
		maxfd = 0;
		for (i = 0; i < tunnel->num_channels; i++)
		{
			if (tunnel->sockets[i] > maxfd)
			{
				maxfd = tunnel->sockets[i];
			}
			FD_SET (tunnel->sockets[i], &set);
		}

		ret = ssh_select (tunnel->channels, tunnel->channels_out, maxfd + 1, &set, &timeout);
		if (!tunnel->running) break;
		if (ret == SSH_EINTR) continue;
		if (ret == -1) break;

		i = 0;
		while (tunnel->running && i < tunnel->num_channels)
		{
			disconnected = FALSE;
			if (FD_ISSET (tunnel->sockets[i], &set))
			{
				while (!disconnected &&
						(len = read (tunnel->sockets[i], tunnel->buffer, tunnel->buffer_len)) > 0)
				{
					for (ptr = tunnel->buffer, lenw = 0; len > 0; len -= lenw, ptr += lenw)
					{
						lenw = channel_write (tunnel->channels[i], (char*) ptr, len);
						if (lenw <= 0)
						{
							disconnected = TRUE;
							break;
						}
					}
				}
				if (len == 0) disconnected = TRUE;
			}
			if (disconnected)
			{
				remmina_ssh_tunnel_remove_channel (tunnel, i);
				continue;
			}
			i++;
		}
		if (!tunnel->running) break;

		i = 0;
		while (tunnel->running && i < tunnel->num_channels)
		{
			disconnected = FALSE;

			if (!tunnel->socketbuffers[i])
			{
				len = channel_poll (tunnel->channels[i], 0);
				if (len == SSH_ERROR || len == SSH_EOF)
				{
					disconnected = TRUE;
				}
				else if (len > 0)
				{
					tunnel->socketbuffers[i] = remmina_ssh_tunnel_buffer_new (len);
					len = channel_read_nonblocking (tunnel->channels[i], tunnel->socketbuffers[i]->data, len, 0);
					if (len <= 0)
					{
						disconnected = TRUE;
					}
					else
					{
						tunnel->socketbuffers[i]->len = len;
					}
				}
			}

			if (!disconnected && tunnel->socketbuffers[i])
			{
				for (lenw = 0; tunnel->socketbuffers[i]->len > 0;
						tunnel->socketbuffers[i]->len -= lenw, tunnel->socketbuffers[i]->ptr += lenw)
				{
					lenw = write (tunnel->sockets[i], tunnel->socketbuffers[i]->ptr, tunnel->socketbuffers[i]->len);
					if (lenw == -1 && errno == EAGAIN && tunnel->running)
					{
						/* Sometimes we cannot write to a socket (always EAGAIN), probably because it's internal
						 * buffer is full. We need read the pending bytes from the socket first. so here we simply
						 * break, leave the buffer there, and continue with other data */
						break;
					}
					if (lenw <= 0)
					{
						disconnected = TRUE;
						break;
					}
				}
				if (tunnel->socketbuffers[i]->len <= 0)
				{
					remmina_ssh_tunnel_buffer_free (tunnel->socketbuffers[i]);
					tunnel->socketbuffers[i] = NULL;
				}
			}

			if (disconnected)
			{
				remmina_ssh_tunnel_remove_channel (tunnel, i);
				continue;
			}
			i++;
		}
	}

	remmina_ssh_tunnel_close_all_channels (tunnel);

	return NULL;
}
示例#2
0
static gpointer
remmina_ssh_shell_thread (gpointer data)
{
	RemminaSSHShell *shell = (RemminaSSHShell*) data;
	fd_set fds;
	struct timeval timeout;
	ssh_channel channel = NULL;
	ssh_channel ch[2], chout[2];
	gchar *buf = NULL;
	gint buf_len;
	gint len;
	gint i, ret;

	LOCK_SSH (shell)

	if ((channel = channel_new (REMMINA_SSH (shell)->session)) == NULL ||
			channel_open_session (channel))
	{
		UNLOCK_SSH (shell)
		remmina_ssh_set_error (REMMINA_SSH (shell), "Failed to open channel : %s");
		if (channel) channel_free (channel);
		shell->thread = 0;
		return NULL;
	}

	channel_request_pty (channel);
	if (shell->exec && shell->exec[0])
	{
		ret = channel_request_exec (channel, shell->exec);
	}
	else
	{
		ret = channel_request_shell (channel);
	}
	if (ret)
	{
		UNLOCK_SSH (shell)
		remmina_ssh_set_error (REMMINA_SSH (shell), "Failed to request shell : %s");
		channel_close (channel);
		channel_free (channel);
		shell->thread = 0;
		return NULL;
	}

	shell->channel = channel;

	UNLOCK_SSH (shell)

	buf_len = 1000;
	buf = g_malloc (buf_len + 1);

	ch[0] = channel;
	ch[1] = NULL;

	while (!shell->closed)
	{
		timeout.tv_sec = 1;
		timeout.tv_usec = 0;

		FD_ZERO (&fds);
		FD_SET (shell->master, &fds);

		ret = ssh_select (ch, chout, shell->master + 1, &fds, &timeout);
		if (ret == SSH_EINTR) continue;
		if (ret == -1) break;

		if (FD_ISSET (shell->master, &fds))
		{
			len = read (shell->master, buf, buf_len);
			if (len <= 0) break;
			LOCK_SSH (shell)
			channel_write (channel, buf, len);
			UNLOCK_SSH (shell)
		}
		for (i = 0; i < 2; i++)
		{
			LOCK_SSH (shell)
			len = channel_poll (channel, i);
			UNLOCK_SSH (shell)
			if (len == SSH_ERROR || len == SSH_EOF)
			{
				shell->closed = TRUE;
				break;
			}
			if (len <= 0) continue;
			if (len > buf_len)
			{
				buf_len = len;
				buf = (gchar*) g_realloc (buf, buf_len + 1);
			}
			LOCK_SSH (shell)
			len = channel_read_nonblocking (channel, buf, len, i);
			UNLOCK_SSH (shell)
			if (len <= 0)
			{
				shell->closed = TRUE;
				break;
			}
			while (len > 0)
			{
				ret = write (shell->master, buf, len);
				if (ret <= 0) break;
				len -= ret;
			}
		}
	}
示例#3
0
static gpointer remmina_nx_session_tunnel_main_thread(gpointer data)
{
	RemminaNXSession *nx = (RemminaNXSession*) data;
	gchar *ptr;
	ssize_t len = 0, lenw = 0;
	fd_set set;
	struct timeval timeout;
	ssh_channel channels[2];
	ssh_channel channels_out[2];
	gint sock;
	gint ret;
	gchar buffer[10240];
	gchar socketbuffer[10240];
	gchar *socketbuffer_ptr = NULL;
	gint socketbuffer_len = 0;

	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

	/* Accept a local connection */
	sock = accept(nx->server_sock, NULL, NULL);
	if (sock < 0)
	{
		remmina_nx_session_set_application_error(nx, "Failed to accept local socket");
		nx->thread = 0;
		return NULL;
	}
	close(nx->server_sock);
	nx->server_sock = -1;

	channels[0] = nx->channel;
	channels[1] = NULL;

	/* Start the tunnel data transmittion */
	while (nx->running)
	{
		timeout.tv_sec = 1;
		timeout.tv_usec = 0;

		FD_ZERO(&set);
		FD_SET(sock, &set);

		ret = ssh_select(channels, channels_out, sock + 1, &set, &timeout);
		if (!nx->running)
			break;
		if (ret == SSH_EINTR)
			continue;
		if (ret == -1)
			break;

		if (FD_ISSET(sock, &set))
		{
			len = read(sock, buffer, sizeof(buffer));
			if (len == 0)
				nx->running = FALSE;
			else
				if (len > 0)
				{
					for (ptr = buffer, lenw = 0; len > 0; len -= lenw, ptr += lenw)
					{
						ssh_set_fd_towrite(nx->session);
						lenw = channel_write(channels[0], (char*) ptr, len);
						if (lenw <= 0)
						{
							nx->running = FALSE;
							break;
						}
					}
				}
		}

		if (!nx->running)
			break;

		if (channels_out[0] && socketbuffer_len <= 0)
		{
			len = channel_read_nonblocking(channels_out[0], socketbuffer, sizeof(socketbuffer), 0);
			if (len == SSH_ERROR || len == SSH_EOF)
			{
				nx->running = FALSE;
				break;
			}
			else
				if (len > 0)
				{
					socketbuffer_ptr = socketbuffer;
					socketbuffer_len = len;
				}
				else
				{
					/* Clean up the stderr buffer in case FreeNX send something there */
					len = channel_read_nonblocking(channels_out[0], buffer, sizeof(buffer), 1);
				}
		}

		if (nx->running && socketbuffer_len > 0)
		{
			for (lenw = 0; socketbuffer_len > 0; socketbuffer_len -= lenw, socketbuffer_ptr += lenw)
			{
				lenw = write(sock, socketbuffer_ptr, socketbuffer_len);
				if (lenw == -1 && errno == EAGAIN && nx->running)
				{
					/* Sometimes we cannot write to a socket (always EAGAIN), probably because it's internal
					 * buffer is full. We need read the pending bytes from the socket first. so here we simply
					 * break, leave the buffer there, and continue with other data */
					break;
				}
				if (lenw <= 0)
				{
					nx->running = FALSE;
					break;
				}
			}
		}
	}

	nx->thread = 0;

	return NULL;
}
示例#4
0
static void select_loop(ssh_session_t *session,ssh_channel_t *channel)
{
    fd_set fds;
    struct timeval timeout;
    char buffer[4096];
    /* channels will be set to the channels to poll.
     * outchannels will contain the result of the poll
     */
    ssh_channel_t *channels[2], *outchannels[2];
    int lus;
    int eof=0;
    int maxfd;
    unsigned int r;
    int ret;
    while(channel)
    {
        do
        {
            FD_ZERO(&fds);
            if(!eof)
            {
                FD_SET(0, &fds);
            }
            timeout.tv_sec = 30;
            timeout.tv_usec = 0;
            FD_SET(ssh_get_fd(session), &fds);
            maxfd = ssh_get_fd(session) + 1;
            channels[0] = channel; // set the first channel we want to read from
            channels[1] = NULL;
            ret = ssh_select(channels, outchannels, maxfd, &fds, &timeout);
            if(signal_delayed)
            {
                sizechanged();
            }
            if(ret == EINTR)
            {
                continue;
            }
            if(FD_ISSET(0, &fds))
            {
                lus = read(0, buffer, sizeof(buffer));
                if(lus)
                    ssh_channel_write(channel, buffer, lus);
                else
                {
                    eof = 1;
                    ssh_channel_send_eof(channel);
                }
            }
            if(channel && ssh_channel_is_closed(channel))
            {
                ssh_channel_free(channel);
                channel=NULL;
                channels[0]=NULL;
            }
            if(outchannels[0])
            {
                while(channel && ssh_channel_is_open(channel) && (r = ssh_channel_poll(channel,0))!=0)
                {
                    lus = ssh_channel_read(channel,buffer,sizeof(buffer) > r ? r : sizeof(buffer),0);
                    if(lus == -1)
                    {
                        fprintf(stderr, "Error reading channel: %s\n",
                                ssh_get_error(session));
                        return;
                    }
                    if(lus == 0)
                    {
                        ssh_channel_free(channel);
                        channel=channels[0]=NULL;
                    }
                    else
                    {
                        if (write(1,buffer,lus) < 0)
                        {
                            fprintf(stderr, "Error writing to buffer\n");
                            return;
                        }
                    }
                }
                while(channel && ssh_channel_is_open(channel) && (r = ssh_channel_poll(channel,1))!=0)  /* stderr */
                {
                    lus = ssh_channel_read(channel,buffer,sizeof(buffer) > r ? r : sizeof(buffer),1);
                    if(lus == -1)
                    {
                        fprintf(stderr, "Error reading channel: %s\n",
                                ssh_get_error(session));
                        return;
                    }
                    if(lus == 0)
                    {
                        ssh_channel_free(channel);
                        channel = channels[0] = NULL;
                    }
                    else
                    {
                        if (write(2, buffer, lus) < 0)
                        {
                            fprintf(stderr, "Error writing to buffer\n");
                            return;
                        }
                    }
                }
            }
            if(channel && ssh_channel_is_closed(channel))
            {
                ssh_channel_free(channel);
                channel=NULL;
            }
        }
        while (ret == EINTR || ret == SSH_EINTR);

    }
}
示例#5
0
文件: newio.c 项目: zhouqt/kbs
int igetch()
{
    time_t now;
    char c;
    int hasaddio = 1;
    extern int RMSG;


    if ((uinfo.mode == CHAT1 || uinfo.mode == TALK || uinfo.mode == PAGE) && RMSG == true)
        hasaddio = 0;

igetagain:
    if (ibufsize == icurrchar) {
        fd_set readfds, xds;
        struct timeval to;
        int sr, hifd;

        to.tv_sec = 0;
        to.tv_usec = 0;
        hifd = 1;
        FD_ZERO(&readfds);
        FD_SET(0, &readfds);
        if ((hasaddio && (i_newfd))&&(!inremsg)) {
            FD_SET(i_newfd, &readfds);
            if (hifd <= i_newfd)
                hifd = i_newfd + 1;
        }
        //TODO: igetkey重入问题
        if ((uinfo.mode != POSTING && uinfo.mode != SMAIL && uinfo.mode != EDIT) || DEFINE(getCurrentUser(), DEF_LOGININFORM))
            if (scrint&&!inremsg) {
                while (msg_count) {
                    inremsg = true;
                    msg_count--;
                    r_msg();
                    refresh();
                    inremsg = false;
                }
            }
        if (kicked) return KEY_TIMEOUT;
#ifdef SSHBBS
        sr = ssh_select(hifd, &readfds, NULL, NULL, &to);
#else
        sr = select(hifd, &readfds, NULL, NULL, &to);
#endif
        if (sr < 0 && errno == EINTR) {
            if (talkrequest)
                return KEY_TALK;
            if ((uinfo.mode != POSTING && uinfo.mode != SMAIL && uinfo.mode != EDIT) || DEFINE(getCurrentUser(), DEF_LOGININFORM))
                if (scrint&&!inremsg) {
                    while (msg_count) {
                        inremsg = true;
                        msg_count--;
                        r_msg();
                        inremsg = false;
                    }
                    goto igetagain;
                }
        }
        if (sr < 0 && errno != EINTR)
            abort_bbs(0);
        if (sr == 0) {
            refresh();
            if (flushf)
                (*flushf)();

            while (1) {
                int alarm_timeout;

                hifd = 1;
                FD_ZERO(&xds);
                FD_SET(0, &xds);
                FD_ZERO(&readfds);
                FD_SET(0, &readfds);
                if ((hasaddio && (i_newfd))&&(!inremsg)) {
                    FD_SET(i_newfd, &readfds);
                    if (hifd <= i_newfd)
                        hifd = i_newfd + 1;
                }
                alarm_timeout = 0;
                if (i_top)
                    to = *i_top;
                else {
                    while ((i_timeout != 0)||(i_timeoutusec!=0)) {
                        to.tv_sec = i_timeout - (time(0) - i_begintimeout);
                        to.tv_usec = i_timeoutusec;
                        if ((to.tv_sec < 0) ||((to.tv_sec==0)&&(i_timeoutusec==0))) {
                            i_timeout = 0;
                            i_timeoutusec=0;
                            if (i_timeout_func)
                                (*i_timeout_func)(timeout_data);
                            else
                                return KEY_TIMEOUT;
                            if (kicked) return KEY_TIMEOUT;
                            continue;
                        };
                        alarm_timeout = 1;
                        break;
                    };
                    if (!alarm_timeout)
                        to.tv_sec = IDLE_TIMEOUT;
                }
#ifdef SSHBBS
                sr = ssh_select(hifd, &readfds, NULL, &xds, &to);
#else
                sr = select(hifd, &readfds, NULL, &xds, &to);
#endif
                if (sr < 0 && errno == EINTR) {
                    if (talkrequest)
                        return KEY_TALK;
                }
                if (kicked) return KEY_TIMEOUT;
                if ((uinfo.mode != POSTING && uinfo.mode != SMAIL && uinfo.mode != EDIT) || DEFINE(getCurrentUser(), DEF_LOGININFORM))
                    if (!inremsg) {
                        int saveerrno=errno;
                        while (msg_count) {
                            inremsg = true;
                            msg_count--;
                            r_msg();
                            refresh();
                            inremsg = false;
                        }
                        if (sr<0&&saveerrno==EINTR)continue;
                    }
                if (sr == 0 && alarm_timeout) {
                    i_timeout = 0;
                    i_timeoutusec=0;
                    if (i_timeout_func)
                        (*i_timeout_func)(timeout_data);
                    else
                        return KEY_TIMEOUT;
                    continue;
                }
                if (sr >= 0)
                    break;
                if (errno == EINTR)
                    continue;
                else
                    abort_bbs(0);

            }
            if ((sr == 0) && (!i_top))
                abort_bbs(0);
            if (sr == 0)
                return I_TIMEOUT;
            if (FD_ISSET(0, &xds))
                abort_bbs(0);
        }
        if (hasaddio && (i_newfd && FD_ISSET(i_newfd, &readfds)))
            return I_OTHERDATA;
#ifdef SSHBBS
        while ((ibufsize = ssh_read(0, inbuffer + 1, IBUFSIZE)) <= 0)
#else
        while ((ibufsize = read(0, inbuffer + 1, IBUFSIZE)) <= 0)
#endif
        {
            if (ibufsize == 0)
                longjmp(byebye, -1);
            if (ibufsize < 0 && errno != EINTR)
                longjmp(byebye, -1);
        }
        if (!filter_telnet(inbuffer + 1, &ibufsize)) {
            icurrchar = 0;
            ibufsize = 0;
            goto igetagain;
        }

        /*
         * add by KCN for GB/BIG5 encode
         */
        if (convcode) {
            inbuf = big2gb(inbuffer + 1, &ibufsize, 0, getSession());
            if (ibufsize == 0) {
                icurrchar = 0;
                goto igetagain;
            }
        } else
            inbuf = inbuffer + 1;
        /*
         * end
         */
        icurrchar = 0;
        if (ibufsize > IBUFSIZE) {
            ibufsize = 0;
            goto igetagain;
        }
    }

    if (icurrchar >= ibufsize) {
        ibufsize = icurrchar;
        goto igetagain;
    }
    if (((inbuf[icurrchar] == '\n') && (lastch == '\r'))
            || ((inbuf[icurrchar] == '\r') && (lastch == '\n'))) {
        lastch = 0;
        goto igetagain;
    }

    else if (icurrchar != ibufsize) {
        if (((inbuf[icurrchar] == '\n') && (inbuf[icurrchar + 1] == '\r'))
                || ((inbuf[icurrchar] == '\r') && (inbuf[icurrchar + 1] == '\n'))) {
            icurrchar++;
            lastch = 0;
        }
    } else
        lastch = inbuf[icurrchar];

    idle_count = 0;
    c = inbuf[icurrchar];

    switch (c) {
        case Ctrl('@'):
        case Ctrl('L'):
            redoscr();
            icurrchar++;
            now = time(0);
            uinfo.freshtime = now;
            if (now - old > 60) {
                UPDATE_UTMP(freshtime, uinfo);
                old = now;
            }
            goto igetagain;
        case Ctrl('Z'):
            if (scrint&&uinfo.mode!=LOCKSCREEN&&uinfo.mode!=NEW&&uinfo.mode!=LOGIN&&uinfo.mode!=BBSNET &&uinfo.mode!=WINMINE&&!inremsg) {
                icurrchar++;
                inremsg = true;
                r_msg();
                inremsg = false;
                goto igetagain;
            }
            break;
        default:
            break;
    }
    icurrchar++;
    while ((icurrchar != ibufsize) && (inbuf[icurrchar] == 0))
        icurrchar++;
    now = time(0);
    if (Ctrl('T') != c)
        uinfo.freshtime = now;
    /*
     * add by KCN , decrease temp_numposts
     */
    if (lasttime + 60 * 60 * 8 < now) {
        lasttime = now;
        if (temp_numposts > 0)
            temp_numposts--;
    }
    if (now - old > 60) {
        UPDATE_UTMP(freshtime, uinfo);
        old = now;
    }
    return c;
}