author | Lluís Batlle <viric@viric.name> |
Thu, 20 Mar 2014 16:33:27 +0100 | |
changeset 97 | eea77d5a624c |
parent 95 | 13360d8af313 |
permissions | -rw-r--r-- |
53 | 1 |
/* |
2 |
Terminal Mixer - multi-point multi-user access to terminal applications |
|
3 |
Copyright (C) 2007 LluĂs Batlle i Rossell |
|
4 |
||
5 |
Please find the license in the provided COPYING file. |
|
6 |
*/ |
|
21 | 7 |
#include <stdlib.h> |
24 | 8 |
#include <unistd.h> |
21 | 9 |
#include <assert.h> |
26
96920c3707b3
Unix sockets version works! Well, signals don't. :)
viric@llimona
parents:
25
diff
changeset
|
10 |
#include <errno.h> |
21 | 11 |
#include <sys/select.h> |
12 |
||
13 |
#include "main.h" |
|
36
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
14 |
#include "filter.h" |
21 | 15 |
#include "handlers.h" |
16 |
||
17 |
/* it uses app_stdin, app_stdout, app_stderr. |
|
18 |
* They have value -1 if not opened. */ |
|
19 |
||
36
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
20 |
static struct FilterRules *fr; |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
21 |
|
94
330324fc7c20
Adding a feature: save all stdin/stdout traffic of the server into a file.
viric <viriketo@gmail.com>
parents:
82
diff
changeset
|
22 |
int savefile = -1; |
330324fc7c20
Adding a feature: save all stdin/stdout traffic of the server into a file.
viric <viriketo@gmail.com>
parents:
82
diff
changeset
|
23 |
|
36
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
24 |
void write_newline_cb(struct FilterRules *myfr, |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
25 |
const struct FFilter *ff, char *obuf, int *olen, |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
26 |
const char *ibuf, int pos) |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
27 |
{ |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
28 |
obuf[(*olen)++] = '\n'; |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
29 |
} |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
30 |
|
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
31 |
void app_control_start() |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
32 |
{ |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
33 |
struct FFilter *ff; |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
34 |
fr = new_filter_rules(); |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
35 |
|
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
36 |
/* We don't pay attention to any telnet command */ |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
37 |
ff = new_ftelnet(); |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
38 |
add_ffilter(fr, ff); |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
39 |
|
72 | 40 |
/* The raw terminal will send \r, |
41 |
* telnet will send \r\0. If we filter all \0, we're fine. |
|
42 |
* I used to change \r to \n here... It works better if I don't. */ |
|
36
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
43 |
|
72 | 44 |
/* We should trim the telnet's no-operation characters '\0'. */ |
36
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
45 |
ff = new_fstring_len("\0", 1); |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
46 |
add_ffilter(fr, ff); |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
47 |
} |
21 | 48 |
|
49 |
void app_control_shutdown() |
|
50 |
{ |
|
51 |
} |
|
52 |
||
53 |
void app_control_prepare_read_fdset(fd_set *read_set, int *maxfd) |
|
54 |
{ |
|
55 |
if (app_stdout != -1) |
|
56 |
{ |
|
82
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
57 |
debugmsg("Considering app_stdout %i", app_stdout); |
21 | 58 |
FD_SET(app_stdout, read_set); |
59 |
*maxfd = max(*maxfd, app_stdout); |
|
60 |
} |
|
61 |
||
25 | 62 |
if (app_stderr != -1 && app_stdout != app_stderr) |
21 | 63 |
{ |
82
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
64 |
debugmsg("Considering app_stderr %i", app_stderr); |
21 | 65 |
FD_SET(app_stderr, read_set); |
66 |
*maxfd = max(*maxfd, app_stderr); |
|
67 |
} |
|
68 |
} |
|
69 |
||
70 |
/* Return -1, finished stdout/stderr. Else, return 0. */ |
|
71 |
int app_control_process_read_fdset(fd_set *read_set) |
|
72 |
{ |
|
73 |
if (app_stdout != -1 && FD_ISSET(app_stdout, read_set)) |
|
74 |
{ |
|
75 |
int res; |
|
82
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
76 |
debugmsg("Read app_stdout %i", app_stdout); |
21 | 77 |
res = read(app_stdout, stream_buffer, stream_buffer_size); |
26
96920c3707b3
Unix sockets version works! Well, signals don't. :)
viric@llimona
parents:
25
diff
changeset
|
78 |
if (res == -1 && errno == EIO) |
96920c3707b3
Unix sockets version works! Well, signals don't. :)
viric@llimona
parents:
25
diff
changeset
|
79 |
{ |
96920c3707b3
Unix sockets version works! Well, signals don't. :)
viric@llimona
parents:
25
diff
changeset
|
80 |
/* I've noticed that when the app dies, read() returns EIO */ |
96920c3707b3
Unix sockets version works! Well, signals don't. :)
viric@llimona
parents:
25
diff
changeset
|
81 |
app_stdout = -1; |
96920c3707b3
Unix sockets version works! Well, signals don't. :)
viric@llimona
parents:
25
diff
changeset
|
82 |
app_stdin = -1; |
96920c3707b3
Unix sockets version works! Well, signals don't. :)
viric@llimona
parents:
25
diff
changeset
|
83 |
return -1; |
96920c3707b3
Unix sockets version works! Well, signals don't. :)
viric@llimona
parents:
25
diff
changeset
|
84 |
} |
96920c3707b3
Unix sockets version works! Well, signals don't. :)
viric@llimona
parents:
25
diff
changeset
|
85 |
if (res == -1 ) |
96920c3707b3
Unix sockets version works! Well, signals don't. :)
viric@llimona
parents:
25
diff
changeset
|
86 |
error("Error reading from app."); |
21 | 87 |
if (res == 0) |
88 |
{ |
|
82
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
89 |
debugmsg("Closing app_stdout %i", app_stdout); |
21 | 90 |
close(app_stdout); |
41 | 91 |
if (!command_line.s_param.nohup) |
92 |
close(1); |
|
82
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
93 |
app_stdout = -1; |
26
96920c3707b3
Unix sockets version works! Well, signals don't. :)
viric@llimona
parents:
25
diff
changeset
|
94 |
if (app_stdout == app_stderr || app_stderr == -1) |
82
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
95 |
{ |
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
96 |
app_stderr = -1; |
21 | 97 |
return -1; |
82
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
98 |
} |
21 | 99 |
} else |
100 |
{ |
|
36
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
101 |
hex_dump("from app", stream_buffer, res); |
41 | 102 |
if (!command_line.s_param.nohup) |
103 |
write(1, stream_buffer, res); |
|
33 | 104 |
if (command_line.s_param.serve_unix) |
105 |
s_unix_send_to_connected(stream_buffer, res); |
|
106 |
if (command_line.s_param.serve_tcp) |
|
107 |
s_tcp_send_to_connected(stream_buffer, res); |
|
49
1cead94cfd99
Fixing a few bugs. The program runs well in Linux and Mac OS X.
viric@llimona
parents:
44
diff
changeset
|
108 |
#ifdef linux |
44 | 109 |
if (command_line.s_param.serve_eth) |
110 |
s_eth_send_to_connected(stream_buffer, res); |
|
49
1cead94cfd99
Fixing a few bugs. The program runs well in Linux and Mac OS X.
viric@llimona
parents:
44
diff
changeset
|
111 |
#endif /* linux */ |
94
330324fc7c20
Adding a feature: save all stdin/stdout traffic of the server into a file.
viric <viriketo@gmail.com>
parents:
82
diff
changeset
|
112 |
if (savefile != -1) |
330324fc7c20
Adding a feature: save all stdin/stdout traffic of the server into a file.
viric <viriketo@gmail.com>
parents:
82
diff
changeset
|
113 |
write(savefile, stream_buffer, res); |
21 | 114 |
} |
115 |
} |
|
25 | 116 |
if (app_stderr != -1 && app_stdout != app_stderr && |
117 |
FD_ISSET(app_stderr, read_set)) |
|
21 | 118 |
{ |
119 |
int res; |
|
82
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
120 |
debugmsg("Read app_stderr %i", app_stdout); |
21 | 121 |
res = read(app_stderr, stream_buffer, stream_buffer_size); |
122 |
if (res == 0) |
|
123 |
{ |
|
82
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
124 |
debugmsg("Closing app_stderr %i", app_stderr); |
21 | 125 |
close(app_stderr); |
126 |
close(2); /* MOVE */ |
|
127 |
app_stderr = -1; |
|
128 |
if (app_stdout == -1) |
|
129 |
return -1; |
|
130 |
} else |
|
131 |
{ |
|
41 | 132 |
if (!command_line.s_param.nohup) |
133 |
write(2, stream_buffer, res); |
|
33 | 134 |
|
135 |
if (command_line.s_param.serve_unix) |
|
136 |
s_unix_send_to_connected(stream_buffer, res); |
|
137 |
if (command_line.s_param.serve_tcp) |
|
138 |
s_tcp_send_to_connected(stream_buffer, res); |
|
49
1cead94cfd99
Fixing a few bugs. The program runs well in Linux and Mac OS X.
viric@llimona
parents:
44
diff
changeset
|
139 |
#ifdef linux |
44 | 140 |
if (command_line.s_param.serve_eth) |
141 |
s_eth_send_to_connected(stream_buffer, res); |
|
49
1cead94cfd99
Fixing a few bugs. The program runs well in Linux and Mac OS X.
viric@llimona
parents:
44
diff
changeset
|
142 |
#endif /* linux */ |
21 | 143 |
} |
144 |
} |
|
145 |
return 0; |
|
146 |
} |
|
147 |
||
32
df110f784648
Added read-only clients, added stdin-close option to clients.
lbatlle@npdl268.bpo.hp.com
parents:
26
diff
changeset
|
148 |
void app_control_local_send_to_stdin(const char *buffer, size_t size) |
21 | 149 |
{ |
150 |
if (size == 0) |
|
82
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
151 |
{ |
21 | 152 |
close(app_stdin); |
82
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
153 |
if (app_stdout == app_stdin) |
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
154 |
app_stdout = -1; |
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
155 |
if (app_stderr == app_stdin) |
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
156 |
app_stderr = -1; |
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
157 |
} |
21 | 158 |
else |
36
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
159 |
{ |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
160 |
hex_dump("from local to app", buffer, size); |
21 | 161 |
write(app_stdin, buffer, size); |
95
13360d8af313
Fixing a problem on savefile (stdin was not saved well, and the file not
viric <viriketo@gmail.com>
parents:
94
diff
changeset
|
162 |
if (savefile != -1) |
13360d8af313
Fixing a problem on savefile (stdin was not saved well, and the file not
viric <viriketo@gmail.com>
parents:
94
diff
changeset
|
163 |
write(savefile, buffer, size); |
36
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
164 |
} |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
165 |
} |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
166 |
|
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
167 |
static void write_data_to_app_stdin(const char *buffer, size_t size) |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
168 |
{ |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
169 |
if (size > 0) |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
170 |
{ |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
171 |
hex_dump("to app", buffer, size); |
41 | 172 |
if( !command_line.s_param.nohup && |
173 |
command_line.s_param.echo_in_local_terminal) |
|
36
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
174 |
write(1, buffer, size); |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
175 |
write(app_stdin, buffer, size); |
94
330324fc7c20
Adding a feature: save all stdin/stdout traffic of the server into a file.
viric <viriketo@gmail.com>
parents:
82
diff
changeset
|
176 |
if (savefile != -1) |
330324fc7c20
Adding a feature: save all stdin/stdout traffic of the server into a file.
viric <viriketo@gmail.com>
parents:
82
diff
changeset
|
177 |
write(savefile, buffer, size); |
36
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
178 |
} |
21 | 179 |
} |
32
df110f784648
Added read-only clients, added stdin-close option to clients.
lbatlle@npdl268.bpo.hp.com
parents:
26
diff
changeset
|
180 |
|
df110f784648
Added read-only clients, added stdin-close option to clients.
lbatlle@npdl268.bpo.hp.com
parents:
26
diff
changeset
|
181 |
void app_control_remote_send_to_stdin(const char *buffer, size_t size) |
df110f784648
Added read-only clients, added stdin-close option to clients.
lbatlle@npdl268.bpo.hp.com
parents:
26
diff
changeset
|
182 |
{ |
36
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
183 |
hex_dump("from client prefilter", buffer, size); |
32
df110f784648
Added read-only clients, added stdin-close option to clients.
lbatlle@npdl268.bpo.hp.com
parents:
26
diff
changeset
|
184 |
if (command_line.s_param.client_can_write) |
df110f784648
Added read-only clients, added stdin-close option to clients.
lbatlle@npdl268.bpo.hp.com
parents:
26
diff
changeset
|
185 |
{ |
36
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
186 |
int osize; |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
187 |
if (size > 0) |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
188 |
{ |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
189 |
filter_stream(fr, ostream_buffer, &osize, |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
190 |
buffer, size); |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
191 |
if (osize > 0) |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
192 |
write_data_to_app_stdin(ostream_buffer, osize); |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
193 |
} else if (size == 0) |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
194 |
{ |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
195 |
filter_flush(fr, ostream_buffer, &osize); |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
196 |
if (osize > 0) |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
197 |
write_data_to_app_stdin(ostream_buffer, osize); |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
198 |
} |
da427c23d755
Added dumps, telnet_filter, applied filters in tm, improved telnet experience.
viric@llimona
parents:
33
diff
changeset
|
199 |
|
32
df110f784648
Added read-only clients, added stdin-close option to clients.
lbatlle@npdl268.bpo.hp.com
parents:
26
diff
changeset
|
200 |
if (size == 0 && command_line.s_param.client_may_close_app_stdin) |
82
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
201 |
{ |
32
df110f784648
Added read-only clients, added stdin-close option to clients.
lbatlle@npdl268.bpo.hp.com
parents:
26
diff
changeset
|
202 |
close(app_stdin); |
82
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
203 |
if (app_stdout == app_stdin) |
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
204 |
app_stdout = -1; |
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
205 |
if (app_stderr == app_stdin) |
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
206 |
app_stderr = -1; |
5cbe47923060
Added a terminal-creation capability.
lbatlle@npdl268.bpo.hp.com
parents:
72
diff
changeset
|
207 |
} |
32
df110f784648
Added read-only clients, added stdin-close option to clients.
lbatlle@npdl268.bpo.hp.com
parents:
26
diff
changeset
|
208 |
} |
df110f784648
Added read-only clients, added stdin-close option to clients.
lbatlle@npdl268.bpo.hp.com
parents:
26
diff
changeset
|
209 |
} |
66
b2469563a1dc
Reliable ethernet protocol. I still need pselect instead of select.
viric@mandarina
parents:
53
diff
changeset
|
210 |
|
b2469563a1dc
Reliable ethernet protocol. I still need pselect instead of select.
viric@mandarina
parents:
53
diff
changeset
|
211 |
void app_control_avoid_sending(fd_set *read_set) |
b2469563a1dc
Reliable ethernet protocol. I still need pselect instead of select.
viric@mandarina
parents:
53
diff
changeset
|
212 |
{ |
b2469563a1dc
Reliable ethernet protocol. I still need pselect instead of select.
viric@mandarina
parents:
53
diff
changeset
|
213 |
} |