/*
Terminal Mixer - multi-point multi-user access to terminal applications
Copyright (C) 2007 LluĂs Batlle i Rossell
Please find the license in the provided COPYING file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/select.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include "main.h"
#include "filter.h"
#include "handlers.h"
struct FilterRules *client_recv_fr = 0;
struct FilterRules *client_termin_fr = 0;
static void loop(Net_c_prepare_read_fdset net_prepare,
Net_c_process_read_fdset net_process,
Net_c_send net_send)
{
fd_set read_set;
sigset_t sigempty,signoalarm;
int maxfd;
int res;
/* Prepare the sigset for blocking alarm */
sigemptyset(&signoalarm);
sigaddset(&signoalarm, SIGALRM);
sigemptyset(&sigempty);
do
{
FD_ZERO(&read_set);
FD_SET(0, &read_set); /* stdin */
maxfd = 0;
net_prepare(&read_set, &maxfd);
/* Prepare checking for timeout */
sigprocmask(SIG_BLOCK, &signoalarm, 0);
#ifdef linux
if (command_line.s_param.serve_eth)
{
int res;
/* This will check if the timeout occurred,
* and will not do anything otherwise.
Will return false when the connection is lost. */
res = eth_proto_process_timeouts();
if (!res)
{
printf("Connection lost (no ACK received).\n");
break;
}
}
#endif
res = pselect(maxfd + 1, &read_set, 0, 0, 0, &sigempty);
#ifdef linux
if (command_line.c_param.transport == ETHERNET)
/* If there isn't a good result, we quit */
if (!eth_proto_process_timeouts())
{
printf("Connection lost (no ACK received).\n");
break;
}
#endif
if (res == -1)
{
if (errno == EINTR)
continue;
else
error("Error in select()");
}
res = net_process(&read_set);
if (res == -1) /* EOF */
break;
if (FD_ISSET(0, &read_set))
{
res = read(0, stream_buffer, stream_buffer_size);
if (client_termin_fr)
{
int olen;
/* We use ostream_buffer2 for data from the
* keyboard to the tm client, because
* *_client.c use the ostream_buffer for data
* from the server to us (tm client). */
hex_dump("Client prefilter", stream_buffer, res);
filter_stream(client_termin_fr, ostream_buffer2, &olen,
stream_buffer,
res);
if (olen > 0)
net_send(ostream_buffer2, olen);
}
else
net_send(stream_buffer, res);
if (res == 0) /* EOF */
break;
}
} while (1);
}
void filtercb_tildes(struct FilterRules *fr, const struct FFilter *ff,
char *obuf, int *olen, const char *ibuf, int pos)
{
dump_line("filtercb_tildes: '%c'\n", ibuf[pos+3]);
if (ibuf[pos+3] == '.')
kill(getpid(), SIGINT);
else
{
obuf[(*olen)++] = '~';
obuf[(*olen)++] = '~';
obuf[(*olen)++] = '~';
}
}
int client()
{
Net_c_prepare_read_fdset net_prepare_read_fdset;
Net_c_process_read_fdset net_process_read_fdset;
Net_c_send net_send;
/* Prepare the filter */
{
struct FFilter *ff;
client_recv_fr = new_filter_rules();
ff = new_ftelnet();
add_ffilter(client_recv_fr, ff);
if (command_line.c_param.raw_mode)
{
client_termin_fr = new_filter_rules();
ff = new_ftildes();
ff->callback = filtercb_tildes;
add_ffilter(client_termin_fr, ff);
}
}
if (command_line.c_param.transport == UNIX)
/* Will be 'tcp', 'ether', ... */
{
c_unix_connect_socket();
net_prepare_read_fdset = c_unix_prepare_read_fdset;
net_process_read_fdset = c_unix_process_read_fdset;
net_send = c_unix_send;
}
#ifdef linux
else if (command_line.c_param.transport == ETHERNET)
{
c_eth_init();
net_prepare_read_fdset = c_eth_prepare_read_fdset;
net_process_read_fdset = c_eth_process_read_fdset;
net_send = c_eth_send_to_connected;
}
#endif /* linux */
if (command_line.c_param.raw_mode)
prepare_user_terminal();
loop(net_prepare_read_fdset, net_process_read_fdset, net_send);
if (command_line.c_param.raw_mode)
restore_user_terminal();
return 0;
}