Merged from silc_1_0_branch.
[silc.git] / lib / silcsftp / tests / sftp_client.c
1 /*
2
3   sftp_client.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2001 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19
20 /* Tests:
21    silc_sftp_client_start();
22    silc_sftp_client_receive_process();
23    silc_sftp_opendir();
24    silc_sftp_readdir();
25    silc_sftp_open();
26    silc_sftp_read();
27    silc_sftp_fstat();
28    silc_sftp_lstat();
29    silc_sftp_close();
30 */
31
32 #include "silcincludes.h"
33 #include "silcsftp.h"
34
35 typedef struct {
36   SilcSchedule schedule;
37   SilcSocketConnection sock;
38   SilcSFTP sftp;
39 } *Client;
40
41 Client gclient;
42
43 char *dir;
44 char *file;
45 bool opendir;
46 SilcUInt64 offset;
47 bool success = FALSE;
48
49 static void sftp_name(SilcSFTP sftp, SilcSFTPStatus status,
50                       const SilcSFTPName name, void *context);
51 static void sftp_handle(SilcSFTP sftp, SilcSFTPStatus status,
52                         SilcSFTPHandle handle, void *context);
53 static void sftp_data(SilcSFTP sftp, SilcSFTPStatus status,
54                       const unsigned char *data, SilcUInt32 data_len,
55                       void *context);
56 static void end_test(void);
57
58 static void send_packet(SilcBuffer packet, void *context)
59 {
60   Client client = (Client)context;
61   SilcSocketConnection sock = client->sock;
62   SilcPacketContext packetdata;
63   const SilcBufferStruct p;
64   int ret;
65
66   memset(&packetdata, 0, sizeof(packetdata));
67   packetdata.type = SILC_PACKET_FTP;
68   packetdata.truelen = packet->len + SILC_PACKET_HEADER_LEN;
69   SILC_PACKET_PADLEN(packetdata.truelen, 0, packetdata.padlen);
70   silc_packet_assemble(&packetdata, NULL, NULL, NULL, sock,
71                        packet->data, packet->len, (const SilcBuffer)&p);
72   ret = silc_packet_send(sock, TRUE);
73   if (ret != -2)
74     return;
75   
76   silc_schedule_set_listen_fd(client->schedule, sock->sock, 
77                               (SILC_TASK_READ | SILC_TASK_WRITE), FALSE);
78   SILC_SET_OUTBUF_PENDING(sock);
79 }
80
81 static bool packet_parse(SilcPacketParserContext *parser, void *context)
82 {
83   Client client = (Client)parser->context;
84   SilcSocketConnection sock = parser->sock;
85   SilcPacketContext *packet = parser->packet;
86   int ret;
87   
88   ret = silc_packet_parse(packet, NULL);
89   assert(packet->type == SILC_PACKET_FTP);
90
91   silc_sftp_client_receive_process(client->sftp, sock, packet);
92     
93   return TRUE;
94 }
95
96 SILC_TASK_CALLBACK(packet_process)
97 {
98   Client client = (Client)context;
99   SilcSocketConnection sock = client->sock;
100   int ret;
101
102   if (type == SILC_TASK_WRITE) {
103     if (sock->outbuf->data - sock->outbuf->head)
104       silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
105
106     ret = silc_packet_send(sock, TRUE);
107     if (ret < 0)
108       return;
109       
110     silc_schedule_set_listen_fd(client->schedule, fd, SILC_TASK_READ, FALSE);
111     SILC_UNSET_OUTBUF_PENDING(sock);
112     silc_buffer_clear(sock->outbuf);
113     return;
114     
115   }
116
117   if (type == SILC_TASK_READ) {
118     ret = silc_packet_receive(sock);
119     if (ret < 0)
120       return;
121   
122     if (ret == 0) {
123       silc_net_close_connection(sock->sock);
124       silc_socket_free(sock);
125       exit(0);
126     }
127
128     silc_packet_receive_process(sock, FALSE, NULL, NULL, 0, 
129                                 packet_parse, client);
130   }
131 }
132
133 static void sftp_status(SilcSFTP sftp, SilcSFTPStatus status,
134                         const char *message, const char *lang_tag,
135                         void *context)
136 {
137   fprintf(stderr, "Status %d\n", status);
138   if (status != SILC_SFTP_STATUS_OK) {
139     SILC_LOG_DEBUG(("Error status"));
140     success = FALSE;
141     end_test();
142     return;
143   }
144
145   success = TRUE;
146   end_test();
147 }
148
149 static void sftp_attr(SilcSFTP sftp, SilcSFTPStatus status,
150                       const SilcSFTPAttributes attrs, void *context)
151 {
152   SilcSFTPHandle handle = (SilcSFTPHandle)context;
153   int debug = silc_debug;
154   int i;
155   
156   fprintf(stderr, "Status %d\n", status);
157   if (status != SILC_SFTP_STATUS_OK) {
158     SILC_LOG_DEBUG(("Error status"));
159     success = FALSE;
160     end_test();
161     return;
162   }
163     
164   if (!debug)
165     silc_debug = 1;
166
167   SILC_LOG_DEBUG(("Attr.flags: %d", attrs->flags));
168   SILC_LOG_DEBUG(("Attr.size: %lu", attrs->size));
169   SILC_LOG_DEBUG(("Attr.uid: %d", attrs->uid));
170   SILC_LOG_DEBUG(("Attr.gid: %d", attrs->gid));
171   SILC_LOG_DEBUG(("Attr.permissions: %d", attrs->permissions));
172   SILC_LOG_DEBUG(("Attr.atime: %d", attrs->atime));
173   SILC_LOG_DEBUG(("Attr.mtime: %d", attrs->mtime));
174   SILC_LOG_DEBUG(("Attr.extended count: %d", attrs->extended_count));
175   for (i = 0; i < attrs->extended_count; i++) {
176     SILC_LOG_HEXDUMP(("Attr.extended_type[i]:", i),
177                      attrs->extended_type[i]->data,
178                      attrs->extended_type[i]->len);
179     SILC_LOG_HEXDUMP(("Attr.extended_data[i]:", i),
180                      attrs->extended_data[i]->data,
181                      attrs->extended_data[i]->len);
182   }
183     
184   silc_debug = debug;
185
186   if (!file) {
187     fprintf(stderr, "Closing file\n"); 
188     silc_sftp_close(sftp, handle, sftp_status, context);
189     return;
190   }
191   
192   fprintf(stderr, "LStatting file %s\n", file); 
193   silc_sftp_lstat(sftp, file, sftp_attr, context);
194   file = NULL;
195 }
196
197 static void sftp_data(SilcSFTP sftp, SilcSFTPStatus status,
198                       const unsigned char *data, SilcUInt32 data_len,
199                       void *context)
200 {
201   SilcSFTPHandle handle = (SilcSFTPHandle)context;
202   int debug = silc_debug;
203
204   if (status != SILC_SFTP_STATUS_OK) {
205     SilcSFTPAttributesStruct attrs;
206
207     fprintf(stderr, "Status %d\n", status);
208
209     if (status != SILC_SFTP_STATUS_EOF) {
210       SILC_LOG_DEBUG(("Error status"));
211       success = FALSE;
212       end_test();
213       return;
214     }
215     
216     if (!strcmp(file, "/sftp/sftp_server.c")) {
217       fprintf(stderr, "FStatting file handle %s\n", file); 
218       silc_sftp_fstat(sftp, handle, sftp_attr, context);
219       return;
220     }
221       
222     /* Open another file */
223     opendir = FALSE;
224     memset(&attrs, 0, sizeof(attrs));
225     file = "/sftp/sftp_server.c";
226     fprintf(stderr, "Opening file %s\n", file);
227     offset = 0;
228     silc_sftp_open(sftp, file, SILC_SFTP_FXF_READ,
229                    &attrs, sftp_handle, gclient);
230     return;
231   }
232
233   if (!debug)
234     silc_debug = 1;
235   SILC_LOG_HEXDUMP(("data"), (unsigned char *)data, data_len);
236   silc_debug = debug;
237
238   offset += data_len;
239
240   /* Attempt to read more */
241   fprintf(stderr, "Reading more of file %s\n", file);
242   silc_sftp_read(sftp, handle, offset, 2048, sftp_data, handle);
243 }
244
245 static void sftp_name(SilcSFTP sftp, SilcSFTPStatus status,
246                       const SilcSFTPName name, void *context)
247 {
248   Client client = (Client)context;
249   int i;
250
251   SILC_LOG_DEBUG(("Name"));
252   fprintf(stderr, "Status %d\n", status);
253
254   if (status != SILC_SFTP_STATUS_OK) {
255     SILC_LOG_DEBUG(("Error status"));
256     success = FALSE;
257     end_test();
258     return;
259   }
260   
261   fprintf(stderr, "Directory: %s\n", dir);
262   for (i = 0; i < name->count; i++) {
263     fprintf(stderr, "%s\n", name->long_filename[i]);
264   }
265
266   if (!strcmp(dir, "sftp")) {
267     SilcSFTPAttributesStruct attrs;
268
269     /* open */
270     opendir = FALSE;
271     memset(&attrs, 0, sizeof(attrs));
272     file = "passwd";
273     fprintf(stderr, "Opening file %s\n", file);
274     offset = 0;
275     silc_sftp_open(sftp, file, SILC_SFTP_FXF_READ,
276                    &attrs, sftp_handle, client);
277     return;
278   }
279
280   if (!strcmp(dir, "/"))
281     dir = "sftp";
282
283   fprintf(stderr, "Opening %s\n", dir);
284
285   /* opendir */
286   opendir = TRUE;
287   silc_sftp_opendir(sftp, dir, sftp_handle, client);
288 }
289
290 static void sftp_handle(SilcSFTP sftp, SilcSFTPStatus status,
291                         SilcSFTPHandle handle, void *context)
292 {
293   Client client = (Client)context;
294
295   SILC_LOG_DEBUG(("Handle"));
296   fprintf(stderr, "Status %d\n", status);
297   if (status != SILC_SFTP_STATUS_OK) {
298     SILC_LOG_DEBUG(("Error status"));
299     success = FALSE;
300     end_test();
301     return;
302   }
303   
304   if (opendir) {
305     fprintf(stderr, "Reading %s\n", dir);
306     /* Readdir */
307     silc_sftp_readdir(sftp, handle, sftp_name, client);
308   } else {
309     fprintf(stderr, "Reading file %s\n", file);
310
311     /* Read */
312     silc_sftp_read(sftp, handle, 0, 2048, sftp_data, handle);
313   }
314 }
315
316 static void sftp_version(SilcSFTP sftp, SilcSFTPStatus status,
317                          SilcSFTPVersion version, void *context)
318 {
319   Client client = (Client)context;
320   fprintf(stderr, "Version: %d\n", (int)version);
321
322   SILC_LOG_DEBUG(("Version"));
323   fprintf(stderr, "Status %d\n", status);
324   if (status != SILC_SFTP_STATUS_OK) {
325     SILC_LOG_DEBUG(("Error status"));
326     success = FALSE;
327     end_test();
328     return;
329   }
330
331   /* opendir */
332   dir = "/";
333   fprintf(stderr, "Opening %s\n", dir);
334   opendir = TRUE;
335   silc_sftp_opendir(sftp, dir, sftp_handle, client);
336 }
337
338 int main(int argc, char **argv)
339 {
340   Client client = silc_calloc(1, sizeof(*client));
341   int sock;
342
343   gclient = client;
344
345   if (argc > 1 && !strcmp(argv[1], "-d")) {
346     silc_debug = 1;
347     silc_debug_hexdump = 1;
348     silc_log_set_debug_string("*sftp*");
349   }
350
351   client->schedule = silc_schedule_init(100, NULL);
352   if (!client->schedule)
353     return -1;
354
355   /* Connecto to server */
356   sock = silc_net_create_connection(NULL, 5000, "127.0.0.1");
357   if (sock < 0)
358     return -1;
359   silc_socket_alloc(sock, 0, NULL, &client->sock);
360   silc_schedule_task_add(client->schedule, sock,
361                          packet_process, client, 0, 0,
362                          SILC_TASK_GENERIC, SILC_TASK_PRI_NORMAL);
363
364   /* Start SFTP session */
365   client->sftp = silc_sftp_client_start(send_packet, client,
366                                         sftp_version, client);
367
368   silc_schedule(client->schedule);
369   return 0;
370 }
371
372 static void end_test(void)
373 {
374   SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
375   fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
376   exit(success);
377 }