OSDN Git Service

Add support for MLSD responses from some broken hosts.
[ffftp/ffftp.git] / putty / RAW.C
1 /*\r
2  * "Raw" backend.\r
3  */\r
4 \r
5 #include <stdio.h>\r
6 #include <stdlib.h>\r
7 \r
8 #include "putty.h"\r
9 \r
10 #ifndef FALSE\r
11 #define FALSE 0\r
12 #endif\r
13 #ifndef TRUE\r
14 #define TRUE 1\r
15 #endif\r
16 \r
17 #define RAW_MAX_BACKLOG 4096\r
18 \r
19 typedef struct raw_backend_data {\r
20     const struct plug_function_table *fn;\r
21     /* the above field _must_ be first in the structure */\r
22 \r
23     Socket s;\r
24     int bufsize;\r
25     void *frontend;\r
26 } *Raw;\r
27 \r
28 static void raw_size(void *handle, int width, int height);\r
29 \r
30 static void c_write(Raw raw, char *buf, int len)\r
31 {\r
32     int backlog = from_backend(raw->frontend, 0, buf, len);\r
33     sk_set_frozen(raw->s, backlog > RAW_MAX_BACKLOG);\r
34 }\r
35 \r
36 static void raw_log(Plug plug, int type, SockAddr addr, int port,\r
37                     const char *error_msg, int error_code)\r
38 {\r
39     Raw raw = (Raw) plug;\r
40     char addrbuf[256], *msg;\r
41 \r
42     sk_getaddr(addr, addrbuf, lenof(addrbuf));\r
43 \r
44     if (type == 0)\r
45         msg = dupprintf("Connecting to %s port %d", addrbuf, port);\r
46     else\r
47         msg = dupprintf("Failed to connect to %s: %s", addrbuf, error_msg);\r
48 \r
49     logevent(raw->frontend, msg);\r
50 }\r
51 \r
52 static int raw_closing(Plug plug, const char *error_msg, int error_code,\r
53                        int calling_back)\r
54 {\r
55     Raw raw = (Raw) plug;\r
56 \r
57     if (raw->s) {\r
58         sk_close(raw->s);\r
59         raw->s = NULL;\r
60         notify_remote_exit(raw->frontend);\r
61     }\r
62     if (error_msg) {\r
63         /* A socket error has occurred. */\r
64         logevent(raw->frontend, error_msg);\r
65         connection_fatal(raw->frontend, "%s", error_msg);\r
66     }                                  /* Otherwise, the remote side closed the connection normally. */\r
67     return 0;\r
68 }\r
69 \r
70 static int raw_receive(Plug plug, int urgent, char *data, int len)\r
71 {\r
72     Raw raw = (Raw) plug;\r
73     c_write(raw, data, len);\r
74     return 1;\r
75 }\r
76 \r
77 static void raw_sent(Plug plug, int bufsize)\r
78 {\r
79     Raw raw = (Raw) plug;\r
80     raw->bufsize = bufsize;\r
81 }\r
82 \r
83 /*\r
84  * Called to set up the raw connection.\r
85  * \r
86  * Returns an error message, or NULL on success.\r
87  *\r
88  * Also places the canonical host name into `realhost'. It must be\r
89  * freed by the caller.\r
90  */\r
91 static const char *raw_init(void *frontend_handle, void **backend_handle,\r
92                             Config *cfg,\r
93                             char *host, int port, char **realhost, int nodelay,\r
94                             int keepalive)\r
95 {\r
96     static const struct plug_function_table fn_table = {\r
97         raw_log,\r
98         raw_closing,\r
99         raw_receive,\r
100         raw_sent\r
101     };\r
102     SockAddr addr;\r
103     const char *err;\r
104     Raw raw;\r
105 \r
106     raw = snew(struct raw_backend_data);\r
107     raw->fn = &fn_table;\r
108     raw->s = NULL;\r
109     *backend_handle = raw;\r
110 \r
111     raw->frontend = frontend_handle;\r
112 \r
113     /*\r
114      * Try to find host.\r
115      */\r
116     {\r
117         char *buf;\r
118         buf = dupprintf("Looking up host \"%s\"%s", host,\r
119                         (cfg->addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" :\r
120                          (cfg->addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" :\r
121                           "")));\r
122         logevent(raw->frontend, buf);\r
123         sfree(buf);\r
124     }\r
125     addr = name_lookup(host, port, realhost, cfg, cfg->addressfamily);\r
126     if ((err = sk_addr_error(addr)) != NULL) {\r
127         sk_addr_free(addr);\r
128         return err;\r
129     }\r
130 \r
131     if (port < 0)\r
132         port = 23;                     /* default telnet port */\r
133 \r
134     /*\r
135      * Open socket.\r
136      */\r
137     raw->s = new_connection(addr, *realhost, port, 0, 1, nodelay, keepalive,\r
138                             (Plug) raw, cfg);\r
139     if ((err = sk_socket_error(raw->s)) != NULL)\r
140         return err;\r
141 \r
142     if (*cfg->loghost) {\r
143         char *colon;\r
144 \r
145         sfree(*realhost);\r
146         *realhost = dupstr(cfg->loghost);\r
147         colon = strrchr(*realhost, ':');\r
148         if (colon) {\r
149             /*\r
150              * FIXME: if we ever update this aspect of ssh.c for\r
151              * IPv6 literal management, this should change in line\r
152              * with it.\r
153              */\r
154             *colon++ = '\0';\r
155         }\r
156     }\r
157 \r
158     return NULL;\r
159 }\r
160 \r
161 static void raw_free(void *handle)\r
162 {\r
163     Raw raw = (Raw) handle;\r
164 \r
165     if (raw->s)\r
166         sk_close(raw->s);\r
167     sfree(raw);\r
168 }\r
169 \r
170 /*\r
171  * Stub routine (we don't have any need to reconfigure this backend).\r
172  */\r
173 static void raw_reconfig(void *handle, Config *cfg)\r
174 {\r
175 }\r
176 \r
177 /*\r
178  * Called to send data down the raw connection.\r
179  */\r
180 static int raw_send(void *handle, char *buf, int len)\r
181 {\r
182     Raw raw = (Raw) handle;\r
183 \r
184     if (raw->s == NULL)\r
185         return 0;\r
186 \r
187     raw->bufsize = sk_write(raw->s, buf, len);\r
188 \r
189     return raw->bufsize;\r
190 }\r
191 \r
192 /*\r
193  * Called to query the current socket sendability status.\r
194  */\r
195 static int raw_sendbuffer(void *handle)\r
196 {\r
197     Raw raw = (Raw) handle;\r
198     return raw->bufsize;\r
199 }\r
200 \r
201 /*\r
202  * Called to set the size of the window\r
203  */\r
204 static void raw_size(void *handle, int width, int height)\r
205 {\r
206     /* Do nothing! */\r
207     return;\r
208 }\r
209 \r
210 /*\r
211  * Send raw special codes.\r
212  */\r
213 static void raw_special(void *handle, Telnet_Special code)\r
214 {\r
215     /* Do nothing! */\r
216     return;\r
217 }\r
218 \r
219 /*\r
220  * Return a list of the special codes that make sense in this\r
221  * protocol.\r
222  */\r
223 static const struct telnet_special *raw_get_specials(void *handle)\r
224 {\r
225     return NULL;\r
226 }\r
227 \r
228 static int raw_connected(void *handle)\r
229 {\r
230     Raw raw = (Raw) handle;\r
231     return raw->s != NULL;\r
232 }\r
233 \r
234 static int raw_sendok(void *handle)\r
235 {\r
236     return 1;\r
237 }\r
238 \r
239 static void raw_unthrottle(void *handle, int backlog)\r
240 {\r
241     Raw raw = (Raw) handle;\r
242     sk_set_frozen(raw->s, backlog > RAW_MAX_BACKLOG);\r
243 }\r
244 \r
245 static int raw_ldisc(void *handle, int option)\r
246 {\r
247     if (option == LD_EDIT || option == LD_ECHO)\r
248         return 1;\r
249     return 0;\r
250 }\r
251 \r
252 static void raw_provide_ldisc(void *handle, void *ldisc)\r
253 {\r
254     /* This is a stub. */\r
255 }\r
256 \r
257 static void raw_provide_logctx(void *handle, void *logctx)\r
258 {\r
259     /* This is a stub. */\r
260 }\r
261 \r
262 static int raw_exitcode(void *handle)\r
263 {\r
264     Raw raw = (Raw) handle;\r
265     if (raw->s != NULL)\r
266         return -1;                     /* still connected */\r
267     else\r
268         /* Exit codes are a meaningless concept in the Raw protocol */\r
269         return 0;\r
270 }\r
271 \r
272 /*\r
273  * cfg_info for Raw does nothing at all.\r
274  */\r
275 static int raw_cfg_info(void *handle)\r
276 {\r
277     return 0;\r
278 }\r
279 \r
280 Backend raw_backend = {\r
281     raw_init,\r
282     raw_free,\r
283     raw_reconfig,\r
284     raw_send,\r
285     raw_sendbuffer,\r
286     raw_size,\r
287     raw_special,\r
288     raw_get_specials,\r
289     raw_connected,\r
290     raw_exitcode,\r
291     raw_sendok,\r
292     raw_ldisc,\r
293     raw_provide_ldisc,\r
294     raw_provide_logctx,\r
295     raw_unthrottle,\r
296     raw_cfg_info,\r
297     "raw",\r
298     PROT_RAW,\r
299     0\r
300 };\r